aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Drewry <drewry@google.com>2015-08-24 11:52:15 -0700
committerWill Drewry <drewry@google.com>2015-08-24 11:52:15 -0700
commite96e2217decd173041388dd2664b1985587b099f (patch)
treecc84b6e344438f3edda56caa5d8e33f0ff39667e
parent4a7dd9b16b350e4218dfefb9f82b030b01226248 (diff)
parentae396da167a9e43ce10c2db0956fb2e2b0d400ea (diff)
downloadtlsdate-e96e2217decd173041388dd2664b1985587b099f.tar.gz
Import upstream tlsdate with history
-rw-r--r--.gitignore40
-rw-r--r--.travis.yml12
-rw-r--r--AUTHORS4
-rw-r--r--CHANGELOG168
-rw-r--r--HACKING.md108
-rw-r--r--HARDENING76
-rw-r--r--INSTALL217
-rw-r--r--LICENSE51
-rw-r--r--Makefile.am149
-rw-r--r--Makefile.android76
-rw-r--r--README47
-rw-r--r--TLSDATEPOOL31
-rw-r--r--TODO42
-rw-r--r--apparmor-profile200
-rwxr-xr-xautogen.sh32
-rw-r--r--ca-roots/tlsdate-ca-roots.conf4725
-rw-r--r--configure.ac604
-rw-r--r--dbus/org.torproject.tlsdate.conf.in31
-rw-r--r--dbus/org.torproject.tlsdate.service3
-rw-r--r--dbus/org.torproject.tlsdate.xml42
-rw-r--r--etc/tlsdated.conf24
-rw-r--r--events.dot58
-rw-r--r--init/tlsdated-cros.conf22
-rw-r--r--m4/ax_append_compile_flags.m465
-rw-r--r--m4/ax_append_flag.m469
-rw-r--r--m4/ax_check_compile_flag.m472
-rw-r--r--m4/ax_check_link_flag.m471
-rw-r--r--m4/ax_platform.m4103
-rw-r--r--m4/bottom.m412
-rw-r--r--m4/visibility.m477
-rw-r--r--man/tlsdate-helper.139
-rw-r--r--man/tlsdate.195
-rw-r--r--man/tlsdated.873
-rw-r--r--man/tlsdated.conf.575
-rw-r--r--mkfile12
-rwxr-xr-xrun-tests48
-rw-r--r--src/common/android.c18
-rw-r--r--src/common/android.h25
-rw-r--r--src/common/fmemopen-funopen.c158
-rw-r--r--src/common/fmemopen.c225
-rw-r--r--src/common/fmemopen.h8
-rw-r--r--src/common/strnlen.c19
-rw-r--r--src/common/strnlen.h8
-rw-r--r--src/compat/clock-darwin.c110
-rw-r--r--src/compat/clock-hurd.c59
-rw-r--r--src/compat/clock-linux.c56
-rw-r--r--src/compat/clock.h74
-rw-r--r--src/compat/include.am59
-rw-r--r--src/conf-unittest.c95
-rw-r--r--src/conf.c119
-rw-r--r--src/conf.h20
-rw-r--r--src/dbus.c578
-rw-r--r--src/dbus.h47
-rw-r--r--src/events/check_continuity.c77
-rw-r--r--src/events/kickoff_time_sync.c170
-rw-r--r--src/events/route_up.c93
-rw-r--r--src/events/run_tlsdate.c77
-rw-r--r--src/events/save.c63
-rw-r--r--src/events/sigchld.c141
-rw-r--r--src/events/sigterm.c33
-rw-r--r--src/events/time_set.c174
-rw-r--r--src/events/tlsdate_status.c148
-rw-r--r--src/include.am489
-rw-r--r--src/platform-cros.c613
-rw-r--r--src/platform.h21
-rw-r--r--src/proxy-bio-plan9.c449
-rw-r--r--src/proxy-bio-plan9.h32
-rw-r--r--src/proxy-bio-unittest.c292
-rw-r--r--src/proxy-bio.c430
-rw-r--r--src/proxy-bio.h32
-rw-r--r--src/proxy-polarssl.c360
-rw-r--r--src/proxy-polarssl.h46
-rw-r--r--src/routeup.c158
-rw-r--r--src/routeup.h44
-rw-r--r--src/rtc.h9
-rw-r--r--src/seccomp-compat.h32
-rw-r--r--src/seccomp.c117
-rw-r--r--src/seccomp.h24
-rw-r--r--src/test-bio.c156
-rw-r--r--src/test-bio.h20
-rw-r--r--src/test/check-host-1.c27
-rw-r--r--src/test/check-host-2.c26
-rw-r--r--src/test/emit.c18
-rw-r--r--src/test/proxy-override.c32
-rw-r--r--src/test/return-argc.c3
-rw-r--r--src/test/sleep-wrap.c20
-rw-r--r--src/test_harness.h451
-rw-r--r--src/tlsdate-helper-plan9.c1250
-rw-r--r--src/tlsdate-helper-plan9.h118
-rw-r--r--src/tlsdate-helper.c1439
-rw-r--r--src/tlsdate-helper.h144
-rw-r--r--src/tlsdate-monitor.c99
-rw-r--r--src/tlsdate-setter.c178
-rw-r--r--src/tlsdate.c235
-rw-r--r--src/tlsdate.h245
-rw-r--r--src/tlsdated-unittest.c328
-rw-r--r--src/tlsdated.c602
-rw-r--r--src/util-plan9.c112
-rw-r--r--src/util-plan9.h41
-rw-r--r--src/util.c439
-rw-r--r--src/util.h97
-rw-r--r--src/visibility.h75
-rw-r--r--systemd/tlsdated.service10
-rw-r--r--test.conf2
-rw-r--r--tests/README1
-rw-r--r--tests/common.sh56
-rw-r--r--tests/run-idle/output1
-rwxr-xr-xtests/run-idle/setup5
-rwxr-xr-xtests/run-idle/subproc.sh12
-rw-r--r--tests/run-idle/teardown15
-rw-r--r--tests/run-idle/test.conf4
-rw-r--r--tests/run-once/output1
-rw-r--r--tests/run-once/run-error1
-rwxr-xr-xtests/run-once/subproc.sh3
-rwxr-xr-xtests/run-routeup/input.sh8
-rw-r--r--tests/run-routeup/output1
-rwxr-xr-xtests/run-routeup/setup4
-rwxr-xr-xtests/run-routeup/subproc.sh9
-rw-r--r--tests/run-routeup/teardown4
-rw-r--r--tests/run-routeup/test.conf4
-rw-r--r--tests/subproc-retry/output3
-rwxr-xr-xtests/subproc-retry/setup4
-rwxr-xr-xtests/subproc-retry/subproc.sh9
-rw-r--r--tests/subproc-retry/teardown4
-rw-r--r--tests/wait-idle/output0
-rwxr-xr-xtests/wait-idle/setup5
-rwxr-xr-xtests/wait-idle/subproc.sh13
-rw-r--r--tlsdate-brew-formula.rb27
-rw-r--r--tlsdate-seccomp-amd64.policy48
-rw-r--r--tlsdate-seccomp-arm.policy50
-rw-r--r--tlsdate-seccomp-x86.policy47
131 files changed, 19881 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7f4ca56
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,40 @@
+*~
+*.gz
+*.o
+.deps/
+.libs/
+autom4te.cache/
+Makefile
+Makefile.in
+aclocal.m4
+config.guess
+config.log
+config.status
+config.sub
+configure
+depcomp
+install-sh
+libtool
+missing
+stamp-h1
+config/
+src/.dirstamp
+src/compat/.dirstamp
+src/android/.dirstamp
+src/configmake.h
+src/tlsdate-helper.o
+src/tlsdate-helper
+src/tlsdate.o
+src/tlsdate
+m4
+*.swp
+*.la
+*.lo
+src/proxy-bio_unittest
+src/tlsdate-routeup
+src/tlsdated
+src/tlsdated_unittest
+TAGS
+tags
+config.h
+config.in
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..57e3045
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+language: c
+before_script: ./autogen.sh
+compiler:
+ - clang
+ - gcc
+branches:
+ only:
+ - master
+before_install:
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq autotools-dev dh-apparmor hardening-wrapper libssl-dev autoconf automake pkg-config libtool
+script: ./configure && make && make test
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..6905aff
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Jacob Appelbaum <jacob@appelbaum.net>
+Christian Grothoff <christian@grothoff.org>
+Elly Jones <elly@leptoquark.net>
+Will Drewry <wad@chromium.org>
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..f6bbb45
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,168 @@
+0.0.13 Thu 28, May, 2015
+ Update default host to google.com - www.ptb.de randomized timestamps
+0.0.12 Sun 26, Oct, 2014
+ Fix AppArmor for tlsdated: allow unprivileged helper to read the time.
+ Update tlsdated systemd service file.
+ Various little fixes and an early release to make the Debian Freeze!
+0.0.11 Mon 20, Oct, 2014
+ Fix routeup flushing when using stdout (Avery Pennarun).
+ Update AppArmor profile to support multiarch systems.
+ Instruct syslog to properly output tlsdated and pid information.
+ (This closes: https://github.com/ioerror/tlsdate/issues/144 )
+ Fix -Wsizeof-pointer-memaccess in build of tlsdated unit test.
+ FreeBSD build improvements (Fabian Keil).
+ Update man pages.
+ Update AppArmor profile to remove unused stanzas.
+ Fix seccomp filter support on x86 systems (Will Drewry).
+ Refactor chatty tlsdated logging output to make it quiet.
+ Close syslog after tlsdated finishes using it.
+ Update systemd and init.d scripts for Debian.
+0.0.10 Fri 26, Sep, 2014
+ tlsdated removed from /usr/bin and now is only in /usr/sbin
+ This release is because 0.0.9 had two trivial bugs. Argh.
+0.0.9 Fri 25, Sep, 2014
+ Fix missing function prototype.
+ major libevent refactor by Will Drewry and Elly Fong-Jones of Google.
+ tlsdated should now function properly on ChromeOS and Debian GNU/Linux
+ Add ability to set COMPILE_DATE at configure/build time.
+ Add support for deterministic builds on Debian GNU/*.
+0.0.8 Sun 14, Sep, 2014
+ Add Debian GNU/Hurd and Debian GNU/kFreeBSD build support.
+ Fix build on FreeBSD 10 and 11.
+ Add FreeBSD (9.2 & 11-CURRENT) support for tlsdate and
+ tlsdate-helper. (Fabian Keil).
+ Update man pages (Kartik Mistry, Holger Levsen).
+ tlsdate will now abort if time fetch has a long delay (Avery Pennarun).
+ Updates for tlsdate related systemd service (Holger Levsen).
+ Check previously unchecked return codes (Brian Aker).
+ Update headers to reflect the correct location (Brian Aker).
+ Addition of various TODO items.
+ Update git tag to reference new GnuPG key
+ Key fingerprint = D2C6 7D20 E9C3 6C2A C5FE 74A2 D255 D3F5 C868 227F
+ Update tlsdate HTTPS user-agent to reflect proper version number
+0.0.7 Sat 2 Nov, 2013
+ Add tentative -plan9.[ch] versions of tlsdate-helper.
+ Add -x option to tlsdated to override source proxies.
+ Correctly check SANs against target host when using proxies.
+ Fix a race in tlsdate-dbus-announce that can cause signal drops.
+ Support -l argument to tlsdated.
+ Pass -l and -v arguments from tlsdated to tlsdate.
+ Log more verbosely at tlsdated startup.
+ Add FreeBSD support for tlsdate and tlsdate-helper.
+ Add Android build support with Android NDK for tlsdate.
+ Add NetBSD 6.0.1 support for tlsdate and tlsdate-helper.
+ Add OpenBSD 5.2 support for tldate and tlsdate-helper.
+ Add official support for Debian, Ubuntu, CentOS, Fedora, RHEL, OpenSUSE,
+ and Arch GNU/Linux distros.
+ Add Mac OS X 10.8.3 support
+ Extensive setup/install documentation is now present in INSTALL for most OSes
+ Add DragonFly BSD 3.3 support
+ Refactored subprocess watching.
+ Added integration tests. Run with ./run-tests
+ Refactored event loop.
+ Added suspend/resume RTC corruption detection.
+ Add -w option to get time from HTTPS header instead of from TLS ServerHello
+ Update AppArmor profile
+ Add simple systemd service file
+ Extra verbose output available with -vv; useful verbosity is -v
+0.0.6 Mon 18 Feb, 2013
+ Ensure that tlsdate compiles with g++ by explicit casting rather than
+ implicit casting by whatever compiler is compiling tlsdate.
+ Fix a logic bug in CN parsing caught by Ryan Sleevi of the Google Chrome Team
+ Further fixes by Thijs Alkemade
+ Add PolarSSL support (We no longer require OpenSSL to function!)
+ Thanks to Paul Bakker and the PolarSSL team!
+ Experimental Mac OS X (10.8.2) support
+ Thanks to Brian Aker and Ingy döt Net for pair programming time
+0.0.5 Web 23 Jan, 2013
+ Fix spelling error in tlsdate-helper
+ Update man pages formatting
+ Add Seccomp-BPF policies to be used with Minijail
+ Update CA cert file to remove TÃœRKTRUST
+ Support both CA certificate files or directories full of CA certs
+ Currently /etc/tlsdate/ca-roots/tlsdate-ca-roots.conf
+ Support announcing time updates over DBus with --enable-dbus
+ This introduces the 'tlsdate-dbus-announce' utility
+ Add support for lcov/gcov at build time
+ See ./configure --enable-code-coverage-checks and make lcov
+ Don't hardfail if DEFAULT_RTC_DEVICE cannot be opened, even if desired
+ Raspberry PI users rejoice (if the fix works)
+ Support -j to add jitter to tlsdated time checks.
+ Exponential backoff when TLS connections fail.
+ Add config file support (have a look at man/tlsdated.conf.5)
+ Support multiple hosts for time fetches
+ Add multiple hosts to your tlsdated.conf file today
+ Add simple AppArmor profile for /usr/bin/tlsdate-dbus-announce
+ Update AppArmor profile for tlsdated
+0.0.4 Wed 7 Nov, 2012
+ Fixup CHANGELOG and properly tag
+ Version Numbers Are Free! Hooray!
+ Update certificate data in ca-roots/
+ tlsdate will now call tlsdate-helper with an absolute path
+ Pointed out ages ago by 0xabad1dea and others as a better execlp path
+ forward for execution.
+0.0.3 Mon 5 Nov, 2012
+ Add tlsdate-routeup man page
+ Update all man pages to reference other related man pages
+ Fix deb Makefile target
+ Update documentation
+ misc src changes (retab, formatting, includes, etc)
+ Update AppArmor profiles
+ Add HTTP/socks4a/socks5 proxy support and update man page documentation
+0.0.2 Mon 29 Oct, 2012
+ Released at the Metalab in Vienna during their third #CryptoParty
+ Add '-n' and '--dont-set-clock' option to fetch but not set time
+ Add '-V' and '--showtime' option to display remote time
+ Add '-t' and '--timewarp' option
+ If the local clock is before RECENT_COMPILE_DATE; we set the clock to the
+ RECENT_COMPILE_DATE. If the local clock is after RECENT_COMPILE_DATE, we
+ leave the clock alone. Clock setting is performed as the first operation
+ and will impact certificate verification. Specifically, this option is
+ helpful if on first boot, the local system clock is set back to the era
+ of Disco and Terrible Hair. This should ensure that
+ X509_V_ERR_CERT_NOT_YET_VALID or X509_V_ERR_CERT_HAS_EXPIRED are not
+ encountered because of a broken RTC or the lack of a local RTC; we assume
+ that tlsdate is recompiled yearly and that all certificates are otherwise
+ considered valid.
+ Add '-l' and '--leap'
+ Normally, the passing of time or time yet to come ensures that SSL verify
+ functions will fail to validate certificates. Commonly,
+ X509_V_ERR_CERT_NOT_YET_VALID and X509_V_ERR_CERT_HAS_EXPIRED are painfully
+ annoying but still very important error states. When the only issue with
+ the certificates in question is the timing information, this option allows
+ one to trust the remote system's time, as long as it is after
+ RECENT_COMPILE_DATE and before MAX_REASONABLE_TIME. The connection will
+ only be trusted if X509_V_ERR_CERT_NOT_YET_VALID and/or
+ X509_V_OKX509_V_ERR_CERT_HAS_EXPIRED are the only errors encountered. The
+ SSL verify function will not return X509_V_OK if there are any other
+ issues, such as self-signed certificates or if the user pins to a CA that
+ is not used by the remote server. This is useful if your RTC is broken on
+ boot and you are unable to use DNSSEC until you've at least had some kind
+ of leap of cryptographically assured data.
+ Update usage documentation
+ Move {*.c,h} into src/
+ Move *.1 into man/
+ Update TODO list to reflect desired changes
+ Update AppArmor profile to restrict {tlsdate,tlsdate-helper,tlsdated,tlsdate-routeup}
+ Update AUTHORS file to include a new email address
+ Update CHANGELOG
+ Added proper date for the 0.0.1 release
+ (Added all of the above items, obviously)
+ Print key bit length and key type information
+ Update Copyright headers to include the Great Christian Grothoff
+ Ensure key bit length and key type values are reasonable
+ Add CommonName and SAN checking
+ Add enumeration and printing of other x.509 extensions in SAN checking
+ Add SAN checking for iPAddress field per RFC2818
+ Various small bug fixes
+ Fixed various tiny memory leaks
+ Added compat layer library for future multi-platform support by David Goulet
+ Compile output is now largely silent by default
+ Wildcard certificate verification per RFC 2595
+ Add list of trusted CA certs to /etc/tlsdate/tlsdate-ca-roots.conf
+ Add Makefile target to update trusted CA certs from Mozilla's NSS trust root
+ Add tlsdated daemon
+ Add tlsdated documentation
+
+0.0.1 Fri Jul 13, 2012
+ First git tagged release
diff --git a/HACKING.md b/HACKING.md
new file mode 100644
index 0000000..b069e07
--- /dev/null
+++ b/HACKING.md
@@ -0,0 +1,108 @@
+Please feel free to contribute patches; here are the basic guidelines to hack
+along with us!
+
+Please work from a git tree by cloning the repo:
+
+ git clone https://github.com/ioerror/tlsdate.git
+
+Please file bugs on the tlsdate issue tracker:
+
+ https://github.com/ioerror/tlsdate/issues
+
+Please use the github pull request feature when possible.
+
+The current build status is available as a handy image:
+
+[![Build Status](https://secure.travis-ci.org/ioerror/tlsdate.png?branch=master)](http://travis-ci.org/ioerror/tlsdate)
+
+Continuous integration is available for a number of platforms:
+
+ https://jenkins.torproject.org/job/tlsdate-ci-linux/
+ https://travis-ci.org/ioerror/tlsdate
+ http://build.chromium.org/p/chromiumos/waterfall
+
+White Space:
+
+ Spaces only, no tabs; all tabs must die
+ No stray spaces at the end of lines
+ Generally try not to add excessive empty white space
+
+Documentation:
+
+ Document all functions with doxygen style comments
+
+Ensuring Correctness:
+
+ Test your patches and ensure:
+
+ No compiler warnings or errors
+ No linker warnings or errors
+
+ Test your improved copy of tlsdate extensively
+
+Security:
+
+ tlsdate is security sensitive - please consider where you add code and in
+ what context it will run. When possible, run with the least privilege as is
+ possible.
+
+Proactively find bugs:
+
+ Run your copy of tlsdate under valgrind
+
+Weird but meaningful conventions are prefered in tlsdate. We prefer attention
+to detail:
+
+ if ( NULL == foo (void) )
+ {
+ bar (void);
+ }
+
+Over quick, hard to read and potentilly incorrect:
+
+ if (foo(void)==NULL))
+ bar();
+
+Define magic numbers and explain their origin:
+
+ // As taken from RFC 3.14
+ #define MAGIC_NUMBER 23 // This goes in foo.h
+ ptr = malloc (MAGIC_NUMBER);
+
+Rather than just throwing them about in code:
+
+ ptr = malloc (23);
+
+It is almost always prefered to use dynamically allocated memory:
+
+ widget_ptr = malloc (WIDGET_SIZE);
+
+Try to avoid static allocations like the following:
+
+ char widget[WIDGET_SIZE];
+
+Try to use unsigned values unless an API requires signed values:
+
+ uint32_t server_time_s;
+
+Please provide relevant CHANGELOG entries for all changes.
+Please remove items from the TODO file as they are completed.
+Please provide unittest cases.
+
+When submitting patches via email, please use `git format-patch` to format
+patches:
+
+ git format-patch 9a61fcba9bebc3fa2d91c9f79306bf316c59cbcc
+
+Email patches with a GnuPG signature whenever possible.
+
+When applying patches, please use `git am` to apply patches:
+
+ git am -i 0001-add-TODO-item.patch
+
+If `git format-patch` is not possible, please send a unified diff.
+
+When in doubt, please consult the Tor HACKING guide:
+
+ https://gitweb.torproject.org/tor.git/blob/HEAD:/doc/HACKING
+
diff --git a/HARDENING b/HARDENING
new file mode 100644
index 0000000..e977395
--- /dev/null
+++ b/HARDENING
@@ -0,0 +1,76 @@
+Platforms offer varying security features; we'd like to support the best.
+
+This is a document that notes which security hardening we have implemented and
+which things we'd like to see implemented for various platforms. We
+specifically address exploitation mitigation and containment; security issues
+such as x509 certification validation are not addressed here, yet. Patches,
+suggestions and improvements are welcome! We always want the strongest set of
+options by default on each supported platform.
+
+We attempt to use the C programming language correctly and in a standard way.
+We do however use some compiler specific options such as defining integer
+wrapping because we believe the practical benefit outweights the implied risks.
+As such, we prefer to be explicit rather than implicit in our casting or other
+possible ambiguity.
+
+We should treat all compiler and linker warnings as fatal errors. Currently,
+consider autotools warnings to be an exception as we would like to support
+platforms imperfectly rather than not at all. We generally wish to support
+autotools bootstrapping on all of our supported platforms. This is not possible
+on Plan 9. Currently autotools will complain on the BSD systems.
+
+On all platforms we attempt to support available compiler hardening and linking
+options. Please do not disable these options. Additional compiler and linker
+hardening options are welcome and the current options are implemented in the
+following file:
+
+ configure.ac
+
+On all platforms, we attempt to switch from the administrative user to an
+unimportant role account which shares data with no other processes. If we start
+as any user other than an administrative user, we will likely be unable to
+switch to our normal unprivileged account. These users are defined at
+`configure` time. It is most effective if such a user is not the traditional
+'nobody' or group 'nogroup' as is often the tradition.
+
+In addition to the above hardening options, we have tried to extend our
+hardening when the platform supports it. Each additional security measure that
+we take is documented as well as planned or desired improvements.
+
+We do not currently support or set ulimits, we should do so where possible.
+
+On Debian Gnu/Linux platforms, we ship with a minimal AppArmor profile, see
+the policy for details:
+
+ apparmor-profile
+
+We'd like to have an SELinux policy specifically for tlsdate.
+We'd like to support capability dropping with libcap or libcap-ng.
+We'd like to support libseccomp2 filters.
+Other kernel hardening suggestions are welcome.
+
+On ChromeOS we use minijail and seccomp filters, see the following policies for
+details:
+
+ tlsdate-seccomp-amd64.policy
+ tlsdate-seccomp-arm.policy
+ tlsdate-seccomp-x86.policy
+
+These are enabled by default in ChromeOS.
+
+On FreeBSD, we'd like to support jails, chroot, and Capsicum.
+
+On OpenBSD, we'd like to support chroot and systrace.
+
+On NetBSD, we'd like to chroot.
+
+On DragonFly BSD, we'd like to support chroot and jails.
+
+On Mac OS X, we'd like to support chroot and seatbelt.
+
+On Plan9, we'd like to chroot.
+
+On Windows, we do nothing beyond compile time hardening. We'd like to do more.
+
+On other platforms, we'll try to run correctly with the understanding that any
+bug is likely a much more serious problem.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..03e91b6
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,217 @@
+tlsdate should build and work on the following Operating Systems:
+
+ Debian GNU/Linux squeeze, wheezy, jessie, sid
+ Ubuntu lucid, natty, oneiric, precise, quantal
+ CentOS 6.2, 6.3, 6.4
+ Fedora 17, 18
+ RedHat Enterprise Server 6.4
+ OpenSUSE 11.2, 12.3
+ FreeBSD 9.2, 10, 11
+ Mac OS X 10.8.2, 10.8.3
+ ChromeOS Release 25, 26, 27 and above
+ Android with the Android NDK (use Makefile.android)
+ Arch Linux (Don't forget to symlink to /dev/rtc to /dev/rtc0)
+ NetBSD 6.0.1
+ OpenBSD 5.2
+ Gentoo 20130413
+ DragonFly BSD 3.3-DEVELOPMENT
+ Debian GNU/kFreeBSD 7.0 (8.2-1-amd64)
+ Debian GNU/Hurd
+
+tlsdate should build and might even work on the following Operating Systems:
+
+ Win32 with Cygwin CYGWIN_NT-6.1 1.7.18(0.263/5/3
+ Win32 with MinGW
+ Haiku r1alpha4
+
+Please file a bug or email the tlsdate team if you have successfully built or
+use tlsdate on a platform that is not listed. We are specifically looking for
+ports of tlsdate or for tlsdate integration on the following Operating Systems:
+
+ Windows native
+ OpenWRT
+ pfsense
+ OpenVMS
+ Irix
+ Minix
+ Any of the other classic unix systems
+
+Currently porting is in progress or partially documented for:
+
+ Plan9 (with APE)
+ Debian GNU/Hurd 7.0 (GNU-Mach 1.3.99-486-dbg/Hurd-0.3)
+ Currently we report "server time 0 (difference is about 1367009757 s)"
+Building and install of tlsdate on GNU/Linux and FreeBSD:
+
+ ./autogen.sh
+ ./configure
+ make
+ make install
+
+Cleaning is the usual:
+
+ make clean
+
+On Debian Gnu/Linux sid/unstable:
+
+ apt-get install tlsdate
+
+On other versions of Debian GNU/Linux and with Debian backports, tlsdate may be
+available:
+
+ apt-get install tlsdate
+
+On recent Debian GNU/Linux and related systems, we provide a systemd service.
+It will notice network changes and regularly invoke tlsdate to keep the clock
+in sync. Start it like so:
+
+ service tlsdated start
+
+On older Debian GNU/Linux and related systems, we provide an init.d script that
+controls the tlsdated daemon. It will notice network changes and regularly
+invoke tlsdate to keep the clock in sync. Start it like so:
+
+ /etc/init.d/tlsdated start
+
+Debian GNU/Hurd does not yet support autotools bootstrapping and users must
+bootstrap with `make dist` on another platform from the tlsdate git
+repository. With such a release tar.gz it is the expected process:
+
+ ./configure
+ make
+ make install
+
+Please note that setting time on GNU/Hurd has not yet been tested.
+
+On ChromeOS:
+
+ tlsdated and tlsdate are included in the ChromeOS TCB; no install needed. They
+ run automatically and are the core ntp service for ChromeOS.
+
+On Gentoo:
+
+ emerge net-misc/tlsdate
+
+On FreeBSD one may also use the ports system:
+
+ cd /usr/ports/sysutils/tlsdate
+ make
+ make install
+
+On Mac OS X, we require that you have XCode installed. You may also need brew
+for autoconf and automake packages:
+
+ brew install autoconf automake libtool pkg-config
+
+It should also be possible to install tlsdate on OS X 10.8.x with brew directly:
+
+ brew install tlsdate
+
+On Fedora:
+
+ yum install tlsdate
+
+To run tlsdated as a service on Fedora:
+
+ systemctl enable tlsdate.service
+ systemctl start tlsdate.service
+
+On Arch Linux there is a PKGBUILD in the Arch User Repository:
+
+ https://aur.archlinux.org/packages/tlsdate
+ https://aur.archlinux.org/packages/tl/tlsdate/PKGBUILD
+
+Cygwin requires that the user installs openssl-dev, gcc, pkg-config, libtool, automake, autoconf:
+
+ ./configure
+ make
+
+On Plan9 the start of building might look something like this:
+
+ ip/ipconfig
+ ndb/dns -r
+ 9fs sources
+ /n/sources/contrib/fgb/root/rc/bin/contrib/install fgb/openssl
+ mk install
+
+On Haiku we must use gcc4:
+
+ export CC=/boot/develop/abi/x86/gcc4/tools/gcc4.6.3-haiku-121101/bin/gcc
+ export LDFLAGS="$LDFLAGS -lbsd"
+ ./configure # This includes the above exports currently
+ make
+
+OpenBSD builds from source and is not yet in the port system:
+
+ export AUTOCONF_VERSION=<your installed version>
+ export AUTOMAKE_VERSION=<your installed version>
+ ./autogen.sh
+ ./configure
+ make
+ make install
+
+If you wish to make a Debian package there are several other options. It is
+expected that you are building for Sid and that you are familiar with how to
+build Debian packages that are for upload into Debian directly. It is expected
+that you should build in a chroot if you wish to have reliable and or
+reproducible builds.
+
+ # Prep your schroot
+ mysid=sid$RANDOM;
+ schroot -b -c sid -n $mysid;
+ dd-schroot-cmd -c $mysid apt-get update;
+ dd-schroot-cmd -c $mysid apt-get build-dep tlsdate;
+ # If build-dep is building an older tlsdate, you may need these tools too:
+ dd-schroot-cmd -c $mysid apt-get install git ca-certificates \
+ lintian libevent-dev libseccomp-dev;
+ echo "Your chroot is called: $mysid";
+ schroot -r -c $mysid
+ # Build tlsdate
+ git clone https://www.github.com/ioerror/tlsdate/
+ cd tlsdate/
+ git checkout debian-master
+ dpkg-buildpackage -B "-mMyName <MyEmail>" -uc
+
+Building without schroot should work with dpkg-buildpackage but the build
+environment will have to be manually configured.
+
+To make a Debian package with git-buildpackage is the expected build process:
+
+ # install dependencies
+ apt-get install git ca-certificates \
+ lintian libevent-dev libseccomp-dev build-essential \
+ autoconf dh-autoreconf dh-systemd automake autotools-dev \
+ dh-apparmor libssl-dev libevent-dev libtool pkg-config \
+ debhelper fakeroot hardening-wrapper git-buildpackage;
+ git clone https://www.github.com/ioerror/tlsdate/
+ cd tlsdate/
+ git checkout debian-master
+ git-buildpackage --git-upstream-branch=master \
+ --git-debian-branch=debian-master \
+ --git-upstream-tree=master \
+ --git-ignore-new
+
+For Android:
+
+To cross compile tlsdate for Android (tested on Linux) you must have the
+Android NDK (>=r8) installed somewhere on your system, and define the
+environment variable NDK_BASE to be the path to the NDK's root dir.
+
+ export NDK_BASE=/home/user/src/android-ndk-r8d
+
+The Android build also requires a cross-compiled OpenSSL. The Android Makefile
+will attempt to build openssl, if you provide the path via the OPENSSL_ANDROID
+env var.
+
+ git clone https://github.com/guardianproject/openssl-android.git /path/to/android-openssl
+ export OPENSSL_ANDROID=/path/to/android-openssl
+
+Once NDK_BASE and OPENSSL_ANDROID are set properly, you can cross compile tlsdate with:
+
+ make distclean # clean any previous builds
+ rm configure # distclean doesn't remove this file
+ make -f Makefile.android
+
+Android NDK: https://developer.android.com/tools/sdk/ndk/index.html
+OpenSSL for Android: https://github.com/guardianproject/openssl-android
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3253de6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,51 @@
+ This file contains the license for tlsdate,
+ a free software project to set your system clock securely.
+
+ It also lists the licenses for other components used by tlsdate.
+
+ For more information about tlsdate, see https://github.com/ioerror/tlsdate
+
+ If you got this file as a part of a larger bundle,
+ there may be other license terms that you should be aware of.
+
+===============================================================================
+tlsdate is distributed under this license:
+
+Copyright (c) 2011-2012, Jacob Appelbaum <jacob@appelbaum.net>
+Copyright (c) 2011-2012, The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+If you got tlsdate as a static binary with OpenSSL included, then you should
+know:
+
+ "This product includes software developed by the OpenSSL Project for use in
+ the OpenSSL Toolkit (http://www.openssl.org/)"
+
+===============================================================================
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..1573a7b
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,149 @@
+# vim:ft=automake
+
+AM_CFLAGS="-D__STDC_LIMIT_MACROS"
+
+BUILT_SOURCES=
+doc_DATA=
+EXTRA_DIST=
+TESTS=
+bin_PROGRAMS=
+sbin_PROGRAMS=
+check_PROGRAMS=
+lib_LTLIBRARIES=
+man_MANS=
+noinst_HEADERS=
+noinst_LTLIBRARIES=
+noinst_PROGRAMS=
+
+if !TARGET_OSX
+# GNU style is "make check", this will make check and test work
+TESTS+= src/conf_unittest src/proxy-bio_unittest
+if TARGET_LINUX
+TESTS+= src/tlsdated_unittest
+endif
+test: check
+endif
+
+ACLOCAL_AMFLAGS= -I m4
+
+# Our Debian version
+DEBIAN_VERSION := $(shell if [ -e debian/changelog ]; then cat debian/changelog|head -n1|cut -d\- -f2| head -c 1; else echo "unknown"; fi)
+
+doc_DATA+= AUTHORS
+doc_DATA+= CHANGELOG
+doc_DATA+= LICENSE
+doc_DATA+= README
+doc_DATA+= TODO
+
+EXTRA_DIST+= $(doc_DATA)
+EXTRA_DIST+= apparmor-profile
+EXTRA_DIST+= autogen.sh
+EXTRA_DIST+= tlsdated.service
+
+include src/include.am
+
+# Cleanup individual files in order to preserve uninstall/etc order
+maintainer-clean-local:
+ @rm -r -f autom4te.cache
+ @rm Makefile.in
+ @rm aclocal.m4
+ @rm config.in
+ @rm config/config.guess
+ @rm config/config.sub
+ @rm config/depcomp
+ @rm config/install-sh
+ @rm config/ltmain.sh
+ @rm config/missing
+ @rm configure
+ @rmdir config
+ @rm dbus/org.torproject.tlsdate.conf
+ @rm m4/libtool.m4
+ @rm m4/ltoptions.m4
+ @rm m4/ltsugar.m4
+ @rm m4/ltversion.m4
+ @rm m4/lt~obsolete.m4
+ @rm -f tlsdate-*.tar.gz
+ -rm src/configmake.h
+ -rm dbus/org.torproject.tlsdate.conf
+ @find ./ | $(GREP) \~$$ | xargs rm -f
+
+certdir = @TLSDATE_CA_ROOTS@
+cert_DATA = ca-roots/tlsdate-ca-roots.conf
+EXTRA_DIST+= $(cert_DATA)
+
+confdir = @TLSDATE_CONF_DIR@
+if TARGET_LINUX
+conf_DATA = etc/tlsdated.conf
+EXTRA_DIST+= $(conf_DATA)
+endif
+
+# Our documentation
+man_MANS+= man/tlsdate.1
+man_MANS+= man/tlsdate-helper.1
+
+if TARGET_LINUX
+man_MANS+= man/tlsdated.8
+man_MANS+= man/tlsdated.conf.5
+endif
+
+EXTRA_DIST+= $(man_MANS)
+
+.PHONY: debian_orig git-tag git-push git-tag-debian deb really-clean valgrind_test
+debian_orig:
+ $(MAKE) dist
+ mv tlsdate-$(VERSION).tar.gz ../tlsdate_$(VERSION).orig.tar.gz
+
+git-tag:
+ git tag -u 0x1801A819 -s tlsdate-$(VERSION)
+
+git-tag-debian:
+ git tag -u 0x1801A819 -s tlsdate-$(VERSION)-debian-${DEBIAN_VERSION}
+
+git-push:
+ git push --tags
+ git push
+
+deb: debian_orig
+ debuild -i'.*' -rfakeroot -uc -us -d
+
+# This generates code coverage data that is useful for continuous integration
+lcov:
+# ./configure --enable-code-coverage-checks && make && # ... run everything and then...
+ lcov --directory src -b . --capture --output-file tlsdate.lcov && genhtml -o lcov/ tlsdate.lcov
+
+valgrind_test:
+ TESTS_ENVIRONMENT="./libtool --mode=execute valgrind --trace-children=yes --leak-check=full" ./src/tlsdate -v -V -n -H encrypted.google.com
+
+# This allows us to parse the Mozilla NSS CA trusted root list and ensures we
+# respect the trust bits as they are set - using them directly without the
+# context is dangerous. This gives us a basic set of CA roots to trust for use
+# with tlsdate without relying on any system CA list.
+# You'll need agl's extract-nss-root-certs to recreate this file:
+# https://github.com/agl/extract-nss-root-certs
+update_ca_root_data:
+ curl https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt\?raw\=1 -o ca-roots/certdata.txt
+ go run ~/Documents/code/git/extract-nss-root-certs/convert_mozilla_certdata.go ca-roots/certdata.txt > ca-roots/tlsdate-ca-roots.conf
+ rm ca-roots/certdata.txt
+
+test_run:
+ ./src/tlsdate-helper google.com 443 tlsv1 racket verbose ca-roots/tlsdate-ca-roots.conf dont-set-clock showtime no-fun holdfast none
+
+BUILT_SOURCES+= src/configmake.h
+noinst_HEADERS+= src/configmake.h
+src/configmake.h: ${top_srcdir}/Makefile.in
+ @echo "Making $@"
+ @rm -f $@-t $@
+ @{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+ echo '#define TLSDATE_CONFIG "$(sysconfdir)/ca-roots/"'; \
+ echo '#define TLSDATE_CERTFILE "$(sysconfdir)/tlsdate/ca-roots/tlsdate-ca-roots.conf"'; \
+ echo '#define TLSDATE_CONF_DIR "$(sysconfdir)/tlsdate/"'; \
+ echo '#define TLSDATE_HELPER "$(bindir)/tlsdate-helper"'; \
+ echo '#define TLSDATE "$(bindir)/tlsdate"'; \
+ echo '#define TLSDATED "$(bindir)/tlsdated"'; \
+ } | sed '/""/d' > $@-t
+ @if diff $@-t $@ >/dev/null 2>&1 ; then \
+ rm @-t ; \
+ else \
+ mv $@-t $@ ; \
+ fi
+
diff --git a/Makefile.android b/Makefile.android
new file mode 100644
index 0000000..fba97ac
--- /dev/null
+++ b/Makefile.android
@@ -0,0 +1,76 @@
+#
+## Cross-compile env for Android
+# Requires Android NDK >= r8
+# Requires the following env variables:
+#
+# NDK_BASE - path to your NDK's root directory
+# e.g., /home/user/android-ndk
+# OPENSSL_ANDROID - path to NDK built openssl
+# e.g., /home/user/src/openssl-android
+#
+
+# Android NDK setup
+NDK_COMPILER_VERSION=4.6
+NDK_ABI=arm
+NDK_BASE ?= /usr/local/android-ndk
+#platform level >= 8 required for dladdr()
+NDK_PLATFORM_LEVEL ?= 8
+NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_LEVEL)/arch-arm
+NDK_UNAME=`uname -s | tr '[A-Z]' '[a-z]'`
+NDK_TOOLCHAIN=$(NDK_BASE)/toolchains/$(NDK_ABI)-linux-androideabi-$(NDK_COMPILER_VERSION)/prebuilt/$(NDK_UNAME)-x86
+
+# to use the real HOST tag, you need the latest libtool files:
+# http://stackoverflow.com/questions/4594736/configure-does-not-recognize-androideabi
+NDK_UNAME := `uname -s | tr '[A-Z]' '[a-z]'`
+HOST := arm-linux-androideabi
+
+LOCAL_LDFLAGS = -L$(OPENSSL_ANDROID)/obj/local/armeabi/ -ldl -lcrypto -lssl -lz
+LOCAL_LDFLAGS += -L$(NDK_TOOLCHAIN)/lib/gcc/arm-linux-androideabi/$($NDK_COMPILER_VERSION) -lgcc
+CFLAGS = -I$(OPENSSL_ANDROID)/include
+CC := $(NDK_TOOLCHAIN)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT)
+CXX := $(NDK_TOOLCHAIN)/bin/arm-linux-androideabi-g++
+CPP := $(NDK_TOOLCHAIN)/bin/arm-linux-androideabi-cpp
+LD := $(NDK_TOOLCHAIN)/bin/arm-linux-androideabi-ld
+AR := $(NDK_TOOLCHAIN)/bin/arm-linux-androideabi-ar
+RANLIB := $(NDK_TOOLCHAIN)/bin/arm-linux-androideabi-ranlib
+STRIP := $(NDK_TOOLCHAIN)/bin/arm-linux-androideabi-strip \
+
+all: $(OPENSSL_ANDROID)/libs/armeabi/libcrypto.so tlsdate-build
+
+$(OPENSSL_ANDROID)/libs/armeabi/libcrypto.so:
+ cd $(OPENSSL_ANDROID) && ndk-build -j4
+
+openssl-clean:
+ -cd $(OPENSSL_ANDROID) && ndk-build clean
+
+openssl-distclean:
+ -cd $(OPENSSL_ANDROID) && ndk-build distclean
+
+configure: configure.ac
+ ./autogen.sh && \
+ CFLAGS="$(CFLAGS)" ./configure \
+ CC="$(CC)" \
+ AR=$(AR) \
+ RANLIB=$(RANLIB) \
+ CFLAGS="$(CFLAGS)" \
+ --disable-static \
+ --disable-languages \
+ --disable-dbus \
+ --host=$(HOST)
+ #--prefix=$(prefix) \
+ #--exec-prefix=$(prefix)
+
+tlsdate-build: configure
+ make -f Makefile CFLAGS="$(CFLAGS)" LDFLAGS="$(LOCAL_LDFLAGS)"
+
+tlsdate-clean:
+ -make -f Makefile clean
+
+tlsdate-distclean:
+ -make -f Makefile distclean && rm configure
+
+
+clean: openssl-clean tlsdate-clean
+distclean: openssl-distclean tlsdate-distclean
+
+.PHONY: clean openssl-clean tlsdate-clean
diff --git a/README b/README
new file mode 100644
index 0000000..2eccdde
--- /dev/null
+++ b/README
@@ -0,0 +1,47 @@
+tlsdate: secure parasitic rdate replacement
+
+ tlsdate sets the local clock by securely connecting with TLS to remote
+ servers and extracting the remote time out of the secure handshake. Unlike
+ ntpdate, tlsdate uses TCP, for instance connecting to a remote HTTPS or TLS
+ enabled service, and provides some protection against adversaries that try to
+ feed you malicious time information.
+
+On Debian GNU/Linux and related systems, we provide an init.d script that
+controls the tlsdated daemon. It will notice network changes and regularly
+invoke tlsdate to keep the clock in sync. Start it like so:
+
+ /etc/init.d/tlsdate start
+
+
+Here is an example an unprivileged user fetching the remote time:
+
+ % tlsdate -V -n -H encrypted.google.com
+ Fri Apr 19 17:56:46 PDT 2013
+
+
+This is an example run - starting as root and dropping to nobody, setting the
+clock and printing it:
+
+ % sudo tlsdate -V
+ Fri Apr 19 17:57:49 PDT 2013
+
+
+Here is an example with a custom host and custom port without verification:
+
+ % sudo tlsdate --skip-verification -p 80 -H rgnx.net
+
+Here is an example where a system may not have any kind of RTC at boot. Do the
+time warp to restore sanity and do so with a leap of faith:
+
+ % sudo tlsdate -V -l -t
+ Fri Apr 19 18:08:03 PDT 2013
+
+
+Some SSL/TLS services do not provide accurate time in their handshake process;
+tlsdate may also be used to fetch time by processing the HTTP Date headers of
+HTTP services:
+
+ % sudo tlsdate -V -l -t -w
+ Wed Oct 30 18:08:46 CET 2013
+
+
diff --git a/TLSDATEPOOL b/TLSDATEPOOL
new file mode 100644
index 0000000..2ca8015
--- /dev/null
+++ b/TLSDATEPOOL
@@ -0,0 +1,31 @@
+"Lets parasitically pool TLS resources into a single location!"
+
+ntp has pool.ntp.org which currently hosts around ~3000 machines.
+tlsdate has only the wild internet's pool of TLS/SSL machines.
+
+It is believed that there are around ~185,000 reasonable SSL/TLS servers in the
+genepool that is the internet.
+
+To discover the relevant systems in the genepool we will conduct scans and
+collect data of SSL/TLS services for the entire internet. When a server is
+discovered and it is confirmed to have a reasonably accurate clock, we will
+store it in the genepool list.
+
+The genepool list will first be a text file included with tlsdate and tlsdate
+will have an option to use the local genepool; it will randomly select an entry
+from the list and use it for timing information.
+
+The genepool list will be in the following CSV format:
+
+ hostname,port,last known IP address, protocol
+
+Currently, the default protocol is TLSv1 unless otherwise specified. Fields may
+include sslv2, sslv3, tlsv1, tlsv1.1, tlsv1.2, xmpp, pop3, imap and other
+STARTTLS enabled protocols.
+
+Eventually, we propose that a simple DNS query interface located at
+genepool.tlsdate.net should return random entries from the genepool list. It
+should only host records of machines that have correct timing information in
+their SSL/TLS handshakes. The data returned will optionally be a TXT record
+containing a line from a regularly updated genepool cache file or an A/AAAA
+record for the host.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..75cc095
--- /dev/null
+++ b/TODO
@@ -0,0 +1,42 @@
+
+Here is a nice list of things to do to improve tlsdate:
+
+
+ 1) hack the client handshake to not leak the clock to the server
+ set it to all zeros or something cute or something random
+
+ 3) add HTTP GET request to avoid network fingerprinting
+ 6) skew the clock rather than slamming it
+11) verification of remote certificate for Tor nodes
+13) account for servers that do not send UTC (Microsoft sends local time)
+14) port to bssl, nss, gnutls, yassl, and other libraries
+15) starttls support (smtp, pop, imap, ftp, xmpp)
+16) ensure that 32bit time isn't near wrapping time on 32bit systems
+17) find others to audit it - we need more eyes!
+20) Add verification of remote servers by DANE/CAA DNSSEC protected records
+21) Integrate Chrome's CRL list into tlsdate
+22) Block revoked or bad certs such as MD5 inc. and others.
+24) Add OCSP check option
+25) Block weak signature algorithms
+26) Hard code block list of known horrible certs (extract from Chrome/FF)
+28) Check that extended key usage is empty, or includes TLS Server Auth
+29) extract the SubjectPublicKeyInfo from the certificates; match against
+ public keys
+31) Confirm HTTP and TLS date is within a sane range
+32) Integrate tack support https://github.com/tack/tackc
+33) Implement checking of RFC 2818 style wildcards:
+ http://wiki.cacert.org/WildcardCertificates
+35) seatbelt profile for Mac OS X
+36) SELinux policy for GNU/Linux platforms
+37) Port to some Windows operating system that anyone actually uses
+42) Unit-test everything
+47) Review cert validation and compare it with Chrome:
+ https://code.google.com/p/chromium/codesearch#chrome/src/net/base/x509_certificate.cc&l=500
+48) Complain when server uses very weak DH group parameters
+ example weak server: https://demo.cmrg.net/
+49) Add seccomp tlsdate and tlsdate-helper
+50) Add AppArmor fixes for Tails
+52) Port tlsdated to FreeBSD and other non GNU/Linux systems
+
+Patches welcome!
+
diff --git a/apparmor-profile b/apparmor-profile
new file mode 100644
index 0000000..20451ed
--- /dev/null
+++ b/apparmor-profile
@@ -0,0 +1,200 @@
+#
+# AppArmor tlsdate profile for Debian GNU/Linux
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License published by the Free Software Foundation.
+#
+
+#include <tunables/global>
+#include <tunables/multiarch.d>
+/usr/bin/tlsdate {
+ #include <abstractions/consoles>
+ #include <abstractions/ssl_certs>
+
+ capability sys_time,
+ capability setgid,
+ capability setuid,
+ capability sys_chroot,
+
+ # IPv4 TCP
+ network inet stream,
+ # IPv4 UDP for DNS resolution
+ network inet dgram,
+ # IPv6 TCP
+ network inet6 stream,
+ # IPv6 UDP
+ network inet6 dgram,
+
+ # Required for gethostbyname
+ /etc/resolv.conf r,
+ /run/resolvconf/resolv.conf r,
+ /etc/nsswitch.conf r,
+ /etc/localtime r,
+ /etc/nsswitch.conf r,
+ /etc/hosts r,
+ /etc/host.conf r,
+
+ # Allow reading public certs but not private keys
+ /etc/ssl/certs/* r,
+ /usr/share/ca-certificates/*/** r,
+
+ # Allow reading of /etc/tlsdate/
+ /etc/tlsdate/*/** r,
+
+ # Required for getpwnam
+ /etc/passwd r,
+ /etc/group r,
+ /proc/sys/kernel/ngroups_max r,
+
+ # Allow reading of libs and /tmp
+ /etc/ld.so.cache r,
+
+ # Random number generation requires these two
+ /dev/random r,
+ /dev/urandom r,
+
+ # Allow mapping of shared libraries
+ /lib{,32,64}/* rm,
+ /usr/lib/* rm,
+ /lib/@{multiarch}/* rm,
+ /usr/lib/@{multiarch}/* rm,
+
+ # We'll allow tlsdate to write a new root to chroot into
+ /tmp/ r,
+ owner /tmp/tlsdate_*/ rw,
+
+ # We'll allow tlsdate to exec tlsdate-helper
+ /usr/bin/tlsdate-helper ixm,
+ /usr/bin/tlsdate ixm,
+}
+
+/usr/bin/tlsdate-helper {
+ #include <abstractions/consoles>
+ #include <abstractions/ssl_certs>
+
+ capability sys_time,
+ capability setgid,
+ capability setuid,
+ capability sys_chroot,
+
+ # IPv4 TCP
+ network inet stream,
+ # IPv4 UDP for DNS resolution
+ network inet dgram,
+ # IPv6 TCP
+ network inet6 stream,
+ # IPv6 UDP
+ network inet6 dgram,
+
+ # Required for gethostbyname
+ /etc/resolv.conf r,
+ /run/resolvconf/resolv.conf r,
+ /etc/nsswitch.conf r,
+ /etc/localtime r,
+ /etc/nsswitch.conf r,
+ /etc/hosts r,
+ /etc/host.conf r,
+
+ # Allow reading public certs but not private keys
+ /etc/ssl/certs/* r,
+ /usr/share/ca-certificates/*/** r,
+
+ # Allow reading of /etc/tlsdate/
+ /etc/tlsdate/*/** r,
+
+ # Required for getpwnam
+ /etc/passwd r,
+ /etc/group r,
+ /proc/sys/kernel/ngroups_max r,
+
+ # Allow reading of libs and /tmp
+ /etc/ld.so.cache r,
+
+ # Random number generation requires these two
+ /dev/random r,
+ /dev/urandom r,
+
+ # Allow mapping of shared libraries
+ /lib{,32,64}/* rm,
+ /usr/lib/* rm,
+ /lib/@{multiarch}/* rm,
+ /usr/lib/@{multiarch}/* rm,
+
+ # We'll allow tlsdate to write a new root to chroot into
+ /tmp/ r,
+ owner /tmp/tlsdate_*/ rw,
+}
+
+/usr/sbin/tlsdated {
+ #include <abstractions/consoles>
+ #include <abstractions/ssl_certs>
+
+ capability sys_time,
+ capability setgid,
+ capability setuid,
+ capability sys_chroot,
+
+ # IPv4 TCP
+ network inet stream,
+ # IPv4 UDP for DNS resolution
+ network inet dgram,
+ # IPv6 TCP
+ network inet6 stream,
+ # IPv6 UDP
+ network inet6 dgram,
+
+ # Required for gethostbyname
+ /etc/resolv.conf r,
+ /etc/nsswitch.conf r,
+ /etc/localtime r,
+ /etc/nsswitch.conf r,
+ /etc/hosts r,
+ /etc/host.conf r,
+
+ # Allow reading public certs but not private keys
+ /etc/ssl/certs/* r,
+ /usr/share/ca-certificates/*/** r,
+
+ # Allow reading of /etc/tlsdate/
+ /etc/tlsdate/*/** r,
+ /etc/tlsdate/tlsdated.conf r,
+
+ # Required for getpwnam
+ /etc/passwd r,
+ /etc/group r,
+ /proc/sys/kernel/ngroups_max r,
+
+ # tlsdated looks into proc for answers
+ /proc/meminfo r,
+
+ # Allow reading of libs and /tmp
+ /etc/ld.so.cache r,
+
+ # Random number generation requires these two
+ /dev/random r,
+ /dev/urandom r,
+
+ # RTC
+ /dev/rtc0 rw,
+ /dev/rtc1 rw,
+
+ # Allow mapping of shared libraries
+ /lib{,32,64}/* rm,
+ /usr/lib/* rm,
+ /lib/@{multiarch}/* rm,
+ /usr/lib/@{multiarch}/* rm,
+
+ # We'll allow tlsdate to write a new root to chroot into
+ /tmp/ r,
+ owner /tmp/tlsdate_*/ rw,
+
+ # We'll allow tlsdated to cache the time here
+ owner /var/cache/tlsdated/* rw,
+ # We'll allow the unprivileged helper to read the time
+ /var/cache/tlsdated/* r,
+
+ # We'll allow tlsdated to exec tlsdate-helper
+ /usr/bin/tlsdate-helper ixm,
+ /usr/bin/tlsdate ixm,
+}
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..efdcacc
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# This generates our configure scripts and leads us onto the path of
+# the great Makefile...
+#
+
+set -e
+
+if [ ! -d config ];
+then
+ mkdir config;
+fi
+
+if [ $(uname) != FreeBSD ];
+then
+ WARNINGS="all,error"
+ export WARNINGS
+fi
+
+if [ $(uname) = NetBSD ] || [ $(uname) = DragonFly ];
+then
+ WARNINGS=""
+ export WARNINGS
+fi
+
+if [ $(uname) = "CYGWIN_NT-6.1" ] || [ $(uname) = "MINGW32_NT-6.1" ];
+then
+ WARNINGS=""
+ export WARNINGS
+fi
+
+autoreconf --install --verbose --force
diff --git a/ca-roots/tlsdate-ca-roots.conf b/ca-roots/tlsdate-ca-roots.conf
new file mode 100644
index 0000000..9122472
--- /dev/null
+++ b/ca-roots/tlsdate-ca-roots.conf
@@ -0,0 +1,4725 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Issuer: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
+# Subject: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
+# Label: "GTE CyberTrust Global Root"
+# Serial: 421
+# MD5 Fingerprint: ca:3d:d3:68:f1:03:5c:d0:32:fa:b8:2b:59:e8:5a:db
+# SHA1 Fingerprint: 97:81:79:50:d8:1c:96:70:cc:34:d8:09:cf:79:44:31:36:7e:f4:74
+# SHA256 Fingerprint: a5:31:25:18:8d:21:10:aa:96:4b:02:c7:b7:c6:da:32:03:17:08:94:e5:fb:71:ff:fb:66:67:d5:e6:81:0a:36
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
+bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
+b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
+b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
+iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
+r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
+04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
+GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
+3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
+lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+
+# Issuer: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Subject: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Label: "Thawte Server CA"
+# Serial: 1
+# MD5 Fingerprint: c5:70:c4:a2:ed:53:78:0c:c8:10:53:81:64:cb:d0:1d
+# SHA1 Fingerprint: 23:e5:94:94:51:95:f2:41:48:03:b4:d5:64:d2:a3:a3:f5:d8:8b:8c
+# SHA256 Fingerprint: b4:41:0b:73:e2:e6:ea:ca:47:fb:c4:2f:8f:a4:01:8a:f4:38:1d:c5:4c:fa:a8:44:50:46:1e:ed:09:45:4d:e9
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
+MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
+MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
+dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
+cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
+DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
+yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
+L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
+7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
+qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Subject: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Label: "Thawte Premium Server CA"
+# Serial: 1
+# MD5 Fingerprint: 06:9f:69:79:16:66:90:02:1b:8c:8c:a2:c3:07:6f:3a
+# SHA1 Fingerprint: 62:7f:8d:78:27:65:63:99:d2:7d:7f:90:44:c9:fe:b3:f3:3e:fa:9a
+# SHA256 Fingerprint: ab:70:36:36:5c:71:54:aa:29:c2:c2:9f:5d:41:91:16:3b:16:2a:22:25:01:13:57:d5:6d:07:ff:a7:bc:1f:72
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+# Issuer: O=Equifax OU=Equifax Secure Certificate Authority
+# Subject: O=Equifax OU=Equifax Secure Certificate Authority
+# Label: "Equifax Secure CA"
+# Serial: 903804111
+# MD5 Fingerprint: 67:cb:9d:c0:13:24:8a:82:9b:b2:17:1e:d1:1b:ec:d4
+# SHA1 Fingerprint: d2:32:09:ad:23:d3:14:23:21:74:e4:0d:7f:9d:62:13:97:86:63:3a
+# SHA256 Fingerprint: 08:29:7a:40:47:db:a2:36:80:c7:31:db:6e:31:76:53:ca:78:48:e1:be:bd:3a:0b:01:79:a7:07:f9:2c:f1:78
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
+
+# Issuer: O=Digital Signature Trust Co. OU=DSTCA E1
+# Subject: O=Digital Signature Trust Co. OU=DSTCA E1
+# Label: "Digital Signature Trust Co. Global CA 1"
+# Serial: 913315222
+# MD5 Fingerprint: 25:7a:ba:83:2e:b6:a2:0b:da:fe:f5:02:0f:08:d7:ad
+# SHA1 Fingerprint: 81:96:8b:3a:ef:1c:dc:70:f5:fa:32:69:c2:92:a3:63:5b:d1:23:d3
+# SHA256 Fingerprint: 63:04:19:ae:c4:78:cb:b4:bb:80:83:de:9d:9c:f2:79:75:2f:03:9d:ef:16:e4:64:71:b6:79:ca:93:00:2d:b0
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg
+bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ
+j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV
+Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw
+MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5
+fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i
++DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN
+QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+
+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl
+-----END CERTIFICATE-----
+
+# Issuer: O=Digital Signature Trust Co. OU=DSTCA E2
+# Subject: O=Digital Signature Trust Co. OU=DSTCA E2
+# Label: "Digital Signature Trust Co. Global CA 3"
+# Serial: 913232846
+# MD5 Fingerprint: 93:c2:8e:11:7b:d4:f3:03:19:bd:28:75:13:4a:45:4a
+# SHA1 Fingerprint: ab:48:f3:33:db:04:ab:b9:c0:72:da:5b:0c:c1:d0:57:f0:36:9b:46
+# SHA256 Fingerprint: 8f:62:d7:73:6f:99:db:d3:3e:e0:0e:10:c7:e3:29:33:9c:98:8a:5b:47:ef:25:f4:08:29:3c:f2:42:6b:4d:44
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/
+k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso
+LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o
+TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3
+MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C
+TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5
+WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR
+xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL
+B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID
+-----END CERTIFICATE-----
+
+# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
+# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
+# Label: "Verisign Class 3 Public Primary Certification Authority"
+# Serial: 149843929435818692848040365716851702463
+# MD5 Fingerprint: 10:fc:63:5d:f6:26:3e:0d:f3:25:be:5f:79:cd:67:67
+# SHA1 Fingerprint: 74:2c:31:92:e6:07:e4:24:eb:45:49:54:2b:e1:bb:c5:3e:61:74:e2
+# SHA256 Fingerprint: e7:68:56:34:ef:ac:f6:9a:ce:93:9a:6b:25:5b:7b:4f:ab:ef:42:93:5b:50:a2:65:ac:b5:cb:60:27:e4:4e:70
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
+
+# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
+# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
+# Label: "Verisign Class 3 Public Primary Certification Authority - G2"
+# Serial: 167285380242319648451154478808036881606
+# MD5 Fingerprint: a2:33:9b:4c:74:78:73:d4:6c:e7:c1:f3:8d:cb:5c:e9
+# SHA1 Fingerprint: 85:37:1c:a6:e5:50:14:3d:ce:28:03:47:1b:de:3a:09:e8:f8:77:0f
+# SHA256 Fingerprint: 83:ce:3c:12:29:68:8a:59:3d:48:5f:81:97:3c:0f:91:95:43:1e:da:37:cc:5e:36:43:0e:79:c7:a8:88:63:8b
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
+
+# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
+# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
+# Label: "GlobalSign Root CA"
+# Serial: 4835703278459707669005204
+# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a
+# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c
+# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
+# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
+# Label: "GlobalSign Root CA - R2"
+# Serial: 4835703278459682885658125
+# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30
+# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe
+# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
+# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
+# Label: "ValiCert Class 1 VA"
+# Serial: 1
+# MD5 Fingerprint: 65:58:ab:15:ad:57:6c:1e:a8:a7:b5:69:ac:bf:ff:eb
+# SHA1 Fingerprint: e5:df:74:3c:b6:01:c4:9b:98:43:dc:ab:8c:e8:6a:81:10:9f:e4:8e
+# SHA256 Fingerprint: f4:c1:49:55:1a:30:13:a3:5b:c7:bf:fe:17:a7:f3:44:9b:c1:ab:5b:5a:0a:e7:4b:06:c2:3b:90:00:4c:01:04
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
+NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
+LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
+TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
+LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
+I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
+nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
+-----END CERTIFICATE-----
+
+# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
+# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
+# Label: "ValiCert Class 2 VA"
+# Serial: 1
+# MD5 Fingerprint: a9:23:75:9b:ba:49:36:6e:31:c2:db:f2:e7:66:ba:87
+# SHA1 Fingerprint: 31:7a:2a:d0:7f:2b:33:5e:f5:a1:c3:4e:4b:57:e8:b7:d8:f1:fc:a6
+# SHA256 Fingerprint: 58:d0:17:27:9c:d4:dc:63:ab:dd:b1:96:a6:c9:90:6c:30:c4:e0:87:83:ea:e8:c1:60:99:54:d6:93:55:59:6b
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
+NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
+dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
+WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
+v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
+UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
+IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
+W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+-----END CERTIFICATE-----
+
+# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
+# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
+# Label: "RSA Root Certificate 1"
+# Serial: 1
+# MD5 Fingerprint: a2:6f:53:b7:ee:40:db:4a:68:e7:fa:18:d9:10:4b:72
+# SHA1 Fingerprint: 69:bd:8c:f4:9c:d3:00:fb:59:2e:17:93:ca:55:6a:f3:ec:aa:35:fb
+# SHA256 Fingerprint: bc:23:f9:8a:31:3c:b9:2d:e3:bb:fc:3a:5a:9f:44:61:ac:39:49:4c:4a:e1:5a:9e:9d:f1:31:e9:9b:73:01:9a
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
+NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
+cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
+2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
+JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
+Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
+n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
+PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Label: "Verisign Class 3 Public Primary Certification Authority - G3"
+# Serial: 206684696279472310254277870180966723415
+# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09
+# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6
+# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
+N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
+KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
+kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
+CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
+Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
+imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
+2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
+DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
+F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
+TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Label: "Verisign Class 4 Public Primary Certification Authority - G3"
+# Serial: 314531972711909413743075096039378935511
+# MD5 Fingerprint: db:c8:f2:27:2e:b1:ea:6a:29:23:5d:fe:56:3e:33:df
+# SHA1 Fingerprint: c8:ec:8c:87:92:69:cb:4b:ab:39:e9:8d:7e:57:67:f3:14:95:73:9d
+# SHA256 Fingerprint: e3:89:36:0d:0f:db:ae:b3:d2:50:58:4b:47:30:31:4e:22:2f:39:c1:56:a0:20:14:4e:8d:96:05:61:79:15:06
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
+GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
+U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
+NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
+ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
+ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
+CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
+g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
+2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
+bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Subject: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Label: "Entrust.net Secure Server CA"
+# Serial: 927650371
+# MD5 Fingerprint: df:f2:80:73:cc:f1:e6:61:73:fc:f5:42:e9:c5:7c:ee
+# SHA1 Fingerprint: 99:a6:9b:e6:1a:fe:88:6b:4d:2b:82:00:7c:b8:54:fc:31:7e:15:39
+# SHA256 Fingerprint: 62:f2:40:27:8c:56:4c:4d:d8:bf:7d:9d:4f:6f:36:6e:a8:94:d2:2f:5f:34:d9:89:a9:83:ac:ec:2f:ff:ed:50
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Label: "Entrust.net Premium 2048 Secure Server CA"
+# Serial: 946059622
+# MD5 Fingerprint: ba:21:ea:20:d6:dd:db:8f:c1:57:8b:40:ad:a1:fc:fc
+# SHA1 Fingerprint: 80:1d:62:d0:7b:44:9d:5c:5c:03:5c:98:ea:61:fa:44:3c:2a:58:fe
+# SHA256 Fingerprint: d1:c3:39:ea:27:84:eb:87:0f:93:4f:c5:63:4e:4a:a9:ad:55:05:01:64:01:f2:64:65:d3:7a:57:46:63:35:9f
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
+MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
+vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
+CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
+WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
+oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
+h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
+f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
+B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
+vUxFnmG6v4SBkgPR0ml8xQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
+# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
+# Label: "Baltimore CyberTrust Root"
+# Serial: 33554617
+# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4
+# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74
+# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+# Issuer: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
+# Subject: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
+# Label: "Equifax Secure Global eBusiness CA"
+# Serial: 1
+# MD5 Fingerprint: 8f:5d:77:06:27:c4:98:3c:5b:93:78:e7:d7:7d:9b:cc
+# SHA1 Fingerprint: 7e:78:4a:10:1c:82:65:cc:2d:e1:f1:6d:47:b4:40:ca:d9:0a:19:45
+# SHA256 Fingerprint: 5f:0b:62:ea:b5:e3:53:ea:65:21:65:16:58:fb:b6:53:59:f4:43:28:0a:4a:fb:d1:04:d7:7d:10:f9:f0:4c:07
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+# Issuer: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
+# Subject: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
+# Label: "Equifax Secure eBusiness CA 1"
+# Serial: 4
+# MD5 Fingerprint: 64:9c:ef:2e:44:fc:c6:8f:52:07:d0:51:73:8f:cb:3d
+# SHA1 Fingerprint: da:40:18:8b:91:89:a3:ed:ee:ae:da:97:fe:2f:9d:f5:b7:d1:8a:41
+# SHA256 Fingerprint: cf:56:ff:46:a4:a1:86:10:9d:d9:65:84:b5:ee:b5:8a:51:0c:42:75:b0:e5:f9:4f:40:bb:ae:86:5e:19:f6:73
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+# Issuer: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
+# Subject: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
+# Label: "Equifax Secure eBusiness CA 2"
+# Serial: 930140085
+# MD5 Fingerprint: aa:bf:bf:64:97:da:98:1d:6f:c6:08:3a:95:70:33:ca
+# SHA1 Fingerprint: 39:4f:f6:85:0b:06:be:52:e5:18:56:cc:10:e1:80:e8:82:b3:85:cc
+# SHA256 Fingerprint: 2f:27:4e:48:ab:a4:ac:7b:76:59:33:10:17:75:50:6d:c3:0e:e3:8e:f6:ac:d5:c0:49:32:cf:e0:41:23:42:20
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
+dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
+NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
+VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
+vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
+BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
+IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
+NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
+y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
+0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
+E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Subject: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Label: "AddTrust Low-Value Services Root"
+# Serial: 1
+# MD5 Fingerprint: 1e:42:95:02:33:92:6b:b9:5f:c0:7f:da:d6:b2:4b:fc
+# SHA1 Fingerprint: cc:ab:0e:a0:4c:23:01:d6:69:7b:dd:37:9f:cd:12:eb:24:e3:94:9d
+# SHA256 Fingerprint: 8c:72:09:27:9a:c0:4e:27:5e:16:d0:7f:d3:b7:75:e8:01:54:b5:96:80:46:e3:1f:52:dd:25:76:63:24:e9:a7
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
+MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
+VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
+CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
+tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
+dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
+PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
+BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
+ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
+7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
+43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
+pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
+WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
+# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
+# Label: "AddTrust External Root"
+# Serial: 1
+# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f
+# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68
+# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Subject: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Label: "AddTrust Public Services Root"
+# Serial: 1
+# MD5 Fingerprint: c1:62:3e:23:c5:82:73:9c:03:59:4b:2b:e9:77:49:7f
+# SHA1 Fingerprint: 2a:b6:28:48:5e:78:fb:f3:ad:9e:79:10:dd:6b:df:99:72:2c:96:e5
+# SHA256 Fingerprint: 07:91:ca:07:49:b2:07:82:aa:d3:c7:d7:bd:0c:df:c9:48:58:35:84:3e:b2:d7:99:60:09:ce:43:ab:6c:69:27
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx
+MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB
+ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV
+BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV
+6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX
+GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP
+dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH
+1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF
+62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW
+BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL
+MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
+cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv
+b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6
+IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/
+iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
+4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
+XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Subject: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Label: "AddTrust Qualified Certificates Root"
+# Serial: 1
+# MD5 Fingerprint: 27:ec:39:47:cd:da:5a:af:e2:9a:01:65:21:a9:4c:bb
+# SHA1 Fingerprint: 4d:23:78:ec:91:95:39:b5:00:7f:75:8f:03:3b:21:1e:c5:4d:8b:cf
+# SHA256 Fingerprint: 80:95:21:08:05:db:4b:bc:35:5e:44:28:d8:fd:6e:c2:cd:e3:ab:5f:b9:7a:99:42:98:8e:b8:f4:dc:d0:60:16
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1
+MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK
+EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh
+BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq
+xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G
+87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i
+2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U
+WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1
+0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G
+A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr
+pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
+ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm
+aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv
+hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm
+hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3
+P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
+iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
+xqE=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
+# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
+# Label: "Entrust Root Certification Authority"
+# Serial: 1164660820
+# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4
+# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9
+# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
+Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
+KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
+NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
+NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
+ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
+BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
+Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
+4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
+KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
+rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
+94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
+sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
+gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
+kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
+vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
+O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
+AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
+9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
+eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
+0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+
+# Issuer: O=RSA Security Inc OU=RSA Security 2048 V3
+# Subject: O=RSA Security Inc OU=RSA Security 2048 V3
+# Label: "RSA Security 2048 v3"
+# Serial: 13297492616345471454730593562152402946
+# MD5 Fingerprint: 77:0d:19:b1:21:fd:00:42:9c:3e:0c:a5:dd:0b:02:8e
+# SHA1 Fingerprint: 25:01:90:19:cf:fb:d9:99:1c:b7:68:25:74:8d:94:5f:30:93:95:42
+# SHA256 Fingerprint: af:8b:67:62:a1:e5:28:22:81:61:a9:5d:5c:55:9e:e2:66:27:8f:75:d7:9e:83:01:89:a5:03:50:6a:bd:6b:4c
+-----BEGIN CERTIFICATE-----
+MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6
+MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp
+dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX
+BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy
+MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp
+eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg
+/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl
+wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh
+AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2
+PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu
+AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR
+MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc
+HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/
+Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+
+f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO
+rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch
+6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3
+7CAFYd4=
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc.
+# Subject: CN=GeoTrust Global CA O=GeoTrust Inc.
+# Label: "GeoTrust Global CA"
+# Serial: 144470
+# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5
+# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12
+# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
+# Subject: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
+# Label: "GeoTrust Global CA 2"
+# Serial: 1
+# MD5 Fingerprint: 0e:40:a7:6c:de:03:5d:8f:d1:0f:e4:d1:8d:f9:6c:a9
+# SHA1 Fingerprint: a9:e9:78:08:14:37:58:88:f2:05:19:b0:6d:2b:0d:2b:60:16:90:7d
+# SHA256 Fingerprint: ca:2d:82:a0:86:77:07:2f:8a:b6:76:4f:f0:35:67:6c:fe:3e:5e:32:5e:01:21:72:df:3f:92:09:6d:b7:9b:85
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
+IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
+R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
+PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
+Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
+TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
+5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
+S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
+2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
+EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
+EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
+/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
+A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
+abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
+I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
+4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc.
+# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc.
+# Label: "GeoTrust Universal CA"
+# Serial: 1
+# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48
+# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79
+# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
+IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
+VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
+cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
+QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
+F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
+c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
+mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
+VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
+teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
+f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
+Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
+nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
+/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
+MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
+9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
+IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
+ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
+uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
+Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
+QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
+koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
+ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
+DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
+bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
+# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
+# Label: "GeoTrust Universal CA 2"
+# Serial: 1
+# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7
+# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79
+# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
+VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
+c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
+WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
+FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
+XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
+se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
+KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
+IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
+y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
+hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
+QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
+Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
+HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
+KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
+L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
+Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
+ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
+T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
+GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
+1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
+OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
+6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
+QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+# Issuer: CN=America Online Root Certification Authority 1 O=America Online Inc.
+# Subject: CN=America Online Root Certification Authority 1 O=America Online Inc.
+# Label: "America Online Root Certification Authority 1"
+# Serial: 1
+# MD5 Fingerprint: 14:f1:08:ad:9d:fa:64:e2:89:e7:1c:cf:a8:ad:7d:5e
+# SHA1 Fingerprint: 39:21:c1:15:c1:5d:0e:ca:5c:cb:5b:c4:f0:7d:21:d8:05:0b:56:6a
+# SHA256 Fingerprint: 77:40:73:12:c6:3a:15:3d:5b:c0:0b:4e:51:75:9c:df:da:c2:37:dc:2a:33:b6:79:46:e9:8e:9b:fa:68:0a:e3
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
+hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
+1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
+OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
+2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
+O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
+AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
+Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
+LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
+oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
+MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
+
+# Issuer: CN=America Online Root Certification Authority 2 O=America Online Inc.
+# Subject: CN=America Online Root Certification Authority 2 O=America Online Inc.
+# Label: "America Online Root Certification Authority 2"
+# Serial: 1
+# MD5 Fingerprint: d6:ed:3c:ca:e2:66:0f:af:10:43:0d:77:9b:04:09:bf
+# SHA1 Fingerprint: 85:b5:ff:67:9b:0c:79:96:1f:c8:6e:44:22:00:46:13:db:17:92:84
+# SHA256 Fingerprint: 7d:3b:46:5a:60:14:e5:26:c0:af:fc:ee:21:27:d2:31:17:27:ad:81:1c:26:84:2d:00:6a:f3:73:06:cc:80:bd
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC
+206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci
+KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2
+JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9
+BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e
+Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B
+PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67
+Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq
+Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
+o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3
++L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj
+YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj
+FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn
+xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2
+LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc
+obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8
+CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe
+IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA
+DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F
+AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX
+Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb
+AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl
+Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
+RY8mkaKO/qk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association
+# Subject: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association
+# Label: "Visa eCommerce Root"
+# Serial: 25952180776285836048024890241505565794
+# MD5 Fingerprint: fc:11:b8:d8:08:93:30:00:6d:23:f9:7e:eb:52:1e:02
+# SHA1 Fingerprint: 70:17:9b:86:8c:00:a4:fa:60:91:52:22:3f:9f:3e:32:bd:e0:05:62
+# SHA256 Fingerprint: 69:fa:c9:bd:55:fb:0a:c7:8d:53:bb:ee:5c:f1:d5:97:98:9f:d0:aa:ab:20:a2:51:51:bd:f1:73:3e:e7:d1:22
+-----BEGIN CERTIFICATE-----
+MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr
+MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl
+cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
+bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw
+CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h
+dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l
+cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h
+2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E
+lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV
+ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq
+299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t
+vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL
+dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF
+AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR
+zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3
+LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd
+7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw
+++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
+398znM/jra6O1I7mT1GvFpLgXPYHDw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Certum CA O=Unizeto Sp. z o.o.
+# Subject: CN=Certum CA O=Unizeto Sp. z o.o.
+# Label: "Certum Root CA"
+# Serial: 65568
+# MD5 Fingerprint: 2c:8f:9f:66:1d:18:90:b1:47:26:9d:8e:86:82:8c:a9
+# SHA1 Fingerprint: 62:52:dc:40:f7:11:43:a2:2f:de:9e:f7:34:8e:06:42:51:b1:81:18
+# SHA256 Fingerprint: d8:e0:fe:bc:1d:b2:e3:8d:00:94:0f:37:d2:7d:41:34:4d:99:3e:73:4b:99:d5:65:6d:97:78:d4:d8:14:36:24
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E
+jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo
+ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI
+ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu
+Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg
+AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7
+HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA
+uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa
+TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg
+xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q
+CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
+O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs
+6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
+# Subject: CN=AAA Certificate Services O=Comodo CA Limited
+# Label: "Comodo AAA Services root"
+# Serial: 1
+# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0
+# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49
+# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Secure Certificate Services O=Comodo CA Limited
+# Subject: CN=Secure Certificate Services O=Comodo CA Limited
+# Label: "Comodo Secure Services root"
+# Serial: 1
+# MD5 Fingerprint: d3:d9:bd:ae:9f:ac:67:24:b3:c8:1b:52:e1:b9:a9:bd
+# SHA1 Fingerprint: 4a:65:d5:f4:1d:ef:39:b8:b8:90:4a:4a:d3:64:81:33:cf:c7:a1:d1
+# SHA256 Fingerprint: bd:81:ce:3b:4f:65:91:d1:1a:67:b5:fc:7a:47:fd:ef:25:52:1b:f9:aa:4e:18:b9:e3:df:2e:34:a7:80:3b:e8
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
+ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
+fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
+BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
+cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
+HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
+CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
+3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
+6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
+HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
+Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
+Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
+DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
+5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
+gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
+aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
+izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Trusted Certificate Services O=Comodo CA Limited
+# Subject: CN=Trusted Certificate Services O=Comodo CA Limited
+# Label: "Comodo Trusted Services root"
+# Serial: 1
+# MD5 Fingerprint: 91:1b:3f:6e:cd:9e:ab:ee:07:fe:1f:71:d2:b3:61:27
+# SHA1 Fingerprint: e1:9f:e3:0e:8b:84:60:9e:80:9b:17:0d:72:a8:c5:ba:6e:14:09:bd
+# SHA256 Fingerprint: 3f:06:e5:56:81:d4:96:f5:be:16:9e:b5:38:9f:9f:2b:8f:f6:1e:17:08:df:68:81:72:48:49:cd:5d:27:cb:69
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
+aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
+MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
+VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
+fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
+TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
+fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
+1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
+kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
+A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
+dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
+HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
+jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
+dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+
+# Issuer: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority
+# Subject: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority
+# Label: "QuoVadis Root CA"
+# Serial: 985026699
+# MD5 Fingerprint: 27:de:36:fe:72:b7:00:03:00:9d:f4:f0:1e:6c:04:24
+# SHA1 Fingerprint: de:3f:40:bd:50:93:d3:9b:6c:60:f6:da:bc:07:62:01:00:89:76:c9
+# SHA256 Fingerprint: a4:5e:de:3b:bb:f0:9c:8a:e1:5c:72:ef:c0:72:68:d6:93:a2:1c:99:6f:d5:1e:67:ca:07:94:60:fd:6d:88:73
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz
+MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw
+IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR
+dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp
+li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D
+rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ
+WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug
+F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU
+xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC
+Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv
+dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
+ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl
+IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
+c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
+ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI
+KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T
+KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq
+y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p
+dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD
+VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL
+MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk
+fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8
+7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R
+cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y
+mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
+xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
+SnQ2+Q==
+-----END CERTIFICATE-----
+
+# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited
+# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited
+# Label: "QuoVadis Root CA 2"
+# Serial: 1289
+# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b
+# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7
+# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa
+GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg
+Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J
+WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB
+rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp
++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1
+ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i
+Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz
+PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og
+/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH
+oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI
+yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud
+EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2
+A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL
+MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f
+BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn
+g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl
+fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K
+WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha
+B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc
+hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR
+TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD
+mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z
+ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
+4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
+8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
+
+# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited
+# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited
+# Label: "QuoVadis Root CA 3"
+# Serial: 1478
+# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf
+# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85
+# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM
+V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB
+4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr
+H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd
+8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv
+vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT
+mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe
+btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc
+T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt
+WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ
+c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A
+4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD
+VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG
+CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0
+aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
+dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw
+czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G
+A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg
+Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0
+7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem
+d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd
++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B
+4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN
+t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x
+DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57
+k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s
+zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j
+Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT
+mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK
+4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+
+# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1
+# Subject: O=SECOM Trust.net OU=Security Communication RootCA1
+# Label: "Security Communication Root CA"
+# Serial: 0
+# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a
+# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7
+# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY
+MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t
+dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5
+WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD
+VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8
+9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ
+DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9
+Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N
+QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ
+xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G
+A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG
+kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr
+Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5
+Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU
+JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
+RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Sonera Class2 CA O=Sonera
+# Subject: CN=Sonera Class2 CA O=Sonera
+# Label: "Sonera Class 2 Root CA"
+# Serial: 29
+# MD5 Fingerprint: a3:ec:75:0f:2e:88:df:fa:48:01:4e:0b:5c:48:6f:fb
+# SHA1 Fingerprint: 37:f7:6d:e6:07:7c:90:c5:b1:3e:93:1a:b7:41:10:b4:f2:e4:9a:27
+# SHA256 Fingerprint: 79:08:b4:03:14:c1:38:10:0b:51:8d:07:35:80:7f:fb:fc:f8:51:8a:00:95:33:71:05:ba:38:6b:15:3d:d9:27
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
+MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
+Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
+5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
+3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
+vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
+8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
+zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
+3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
+FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
+Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
+ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
+-----END CERTIFICATE-----
+
+# Issuer: CN=Staat der Nederlanden Root CA O=Staat der Nederlanden
+# Subject: CN=Staat der Nederlanden Root CA O=Staat der Nederlanden
+# Label: "Staat der Nederlanden Root CA"
+# Serial: 10000010
+# MD5 Fingerprint: 60:84:7c:5a:ce:db:0c:d4:cb:a7:e9:fe:02:c6:a9:c0
+# SHA1 Fingerprint: 10:1d:fa:3f:d5:0b:cb:bb:9b:b5:60:0c:19:55:a4:1a:f4:73:3a:04
+# SHA256 Fingerprint: d4:1d:82:9e:8c:16:59:82:2a:f9:3f:ce:62:bf:fc:de:26:4f:c8:4e:8b:95:0c:5f:f2:75:d0:52:35:46:95:a3
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO
+TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy
+MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk
+ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn
+ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71
+9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO
+hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U
+tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o
+BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh
+SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww
+OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv
+cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA
+7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k
+/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm
+eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6
+u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy
+7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
+iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+-----END CERTIFICATE-----
+
+# Issuer: O=TDC Internet OU=TDC Internet Root CA
+# Subject: O=TDC Internet OU=TDC Internet Root CA
+# Label: "TDC Internet Root CA"
+# Serial: 986490188
+# MD5 Fingerprint: 91:f4:03:55:20:a1:f8:63:2c:62:de:ac:fb:61:1c:8e
+# SHA1 Fingerprint: 21:fc:bd:8e:7f:6c:af:05:1b:d1:b3:43:ec:a8:e7:61:47:f2:0f:8a
+# SHA256 Fingerprint: 48:98:c6:88:8c:0c:ff:b0:d3:e3:1a:ca:8a:37:d4:e3:51:5f:f7:46:d0:26:35:d8:66:46:cf:a0:a3:18:5a:e7
+-----BEGIN CERTIFICATE-----
+MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE
+SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg
+Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV
+BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl
+cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA
+vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu
+Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a
+0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1
+4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN
+eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD
+R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG
+A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu
+dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME
+Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3
+WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw
+HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ
+KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO
+Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX
+wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89
+9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0
+jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38
+aQNiuJkFBT1reBK9sG9l
+-----END CERTIFICATE-----
+
+# Issuer: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
+# Subject: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
+# Label: "UTN DATACorp SGC Root CA"
+# Serial: 91374294542884689855167577680241077609
+# MD5 Fingerprint: b3:a5:3e:77:21:6d:ac:4a:c0:c9:fb:d5:41:3d:ca:06
+# SHA1 Fingerprint: 58:11:9f:0e:12:82:87:ea:50:fd:d9:87:45:6f:4f:78:dc:fa:d6:d4
+# SHA256 Fingerprint: 85:fb:2f:91:dd:12:27:5a:01:45:b6:36:53:4f:84:02:4a:d6:8b:69:b8:ee:88:68:4f:f7:11:37:58:05:b3:48
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+# Issuer: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
+# Subject: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
+# Label: "UTN USERFirst Hardware Root CA"
+# Serial: 91374294542884704022267039221184531197
+# MD5 Fingerprint: 4c:56:41:e5:0d:bb:2b:e8:ca:a3:ed:18:08:ad:43:39
+# SHA1 Fingerprint: 04:83:ed:33:99:ac:36:08:05:87:22:ed:bc:5e:46:00:e3:be:f9:d7
+# SHA256 Fingerprint: 6e:a5:47:41:d0:04:66:7e:ed:1b:48:16:63:4a:a3:a7:9e:6e:4b:96:95:0f:82:79:da:fc:8d:9b:d8:81:21:37
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Chambers of Commerce Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org
+# Subject: CN=Chambers of Commerce Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org
+# Label: "Camerfirma Chambers of Commerce Root"
+# Serial: 0
+# MD5 Fingerprint: b0:01:ee:14:d9:af:29:18:94:76:8e:f1:69:33:2a:84
+# SHA1 Fingerprint: 6e:3a:55:a4:19:0c:19:5c:93:84:3c:c0:db:72:2e:31:30:61:f0:b1
+# SHA256 Fingerprint: 0c:25:8a:12:a5:67:4a:ef:25:f2:8b:a7:dc:fa:ec:ee:a3:48:e5:41:e6:f5:cc:4e:e6:3b:71:b3:61:60:6a:c3
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn
+MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
+ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg
+b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa
+MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB
+ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw
+IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B
+AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb
+unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d
+BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq
+7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3
+0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX
+roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG
+A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j
+aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p
+26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA
+BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud
+EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN
+BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB
+AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd
+p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi
+1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc
+XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0
+eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu
+tGWaIZDgqtCYvDi1czyL+Nw=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Global Chambersign Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org
+# Subject: CN=Global Chambersign Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org
+# Label: "Camerfirma Global Chambersign Root"
+# Serial: 0
+# MD5 Fingerprint: c5:e6:7b:bf:06:d0:4f:43:ed:c4:7a:65:8a:fb:6b:19
+# SHA1 Fingerprint: 33:9b:6b:14:50:24:9b:55:7a:01:87:72:84:d9:e0:2f:c3:d2:d8:e9
+# SHA256 Fingerprint: ef:3c:b4:17:fc:8e:bf:6f:97:87:6c:9e:4e:ce:39:de:1e:a5:fe:64:91:41:d1:02:8b:7d:11:c0:b2:29:8c:ed
+-----BEGIN CERTIFICATE-----
+MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn
+MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
+ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo
+YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9
+MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy
+NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G
+A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA
+A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0
+Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s
+QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV
+eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795
+B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh
+z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T
+AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i
+ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w
+TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH
+MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD
+VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE
+VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
+bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B
+AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM
+bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi
+ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG
+VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c
+ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/
+AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
+-----END CERTIFICATE-----
+
+# Issuer: CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok
+# Subject: CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok
+# Label: "NetLock Notary (Class A) Root"
+# Serial: 259
+# MD5 Fingerprint: 86:38:6d:5e:49:63:6c:85:5c:db:6d:dc:94:b7:d0:f7
+# SHA1 Fingerprint: ac:ed:5f:65:53:fd:25:ce:01:5f:1f:7a:48:3b:6a:74:9f:61:78:c6
+# SHA256 Fingerprint: 7f:12:cd:5f:7e:5e:29:0e:c7:d8:51:79:d5:b7:2c:20:a5:be:75:08:ff:db:5b:f8:1a:b9:68:4a:7f:c9:f6:67
+-----BEGIN CERTIFICATE-----
+MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV
+MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe
+TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0
+dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB
+KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0
+N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC
+dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu
+MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL
+b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD
+zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi
+3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8
+WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY
+Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi
+NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC
+ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4
+QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0
+YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz
+aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
+IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm
+ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg
+ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs
+amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv
+IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3
+Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6
+ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1
+YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg
+dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs
+b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G
+CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO
+xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP
+0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ
+QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk
+f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK
+8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI
+-----END CERTIFICATE-----
+
+# Issuer: CN=NetLock Uzleti (Class B) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok
+# Subject: CN=NetLock Uzleti (Class B) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok
+# Label: "NetLock Business (Class B) Root"
+# Serial: 105
+# MD5 Fingerprint: 39:16:aa:b9:6a:41:e1:14:69:df:9e:6c:3b:72:dc:b6
+# SHA1 Fingerprint: 87:9f:4b:ee:05:df:98:58:3b:e3:60:d6:33:e7:0d:3f:fe:98:71:af
+# SHA256 Fingerprint: 39:df:7b:68:2b:7b:93:8f:84:71:54:81:cc:de:8d:60:d8:f2:2e:c5:98:87:7d:0a:aa:c1:2b:59:18:2b:03:12
+-----BEGIN CERTIFICATE-----
+MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD
+EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05
+OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l
+dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG
+SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK
+gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX
+iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc
+Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E
+BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G
+SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu
+b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh
+bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv
+Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln
+aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0
+IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
+c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph
+biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo
+ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP
+UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj
+YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo
+dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA
+bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06
+sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa
+n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS
+NitjrFgBazMpUIaD8QFI
+-----END CERTIFICATE-----
+
+# Issuer: CN=NetLock Expressz (Class C) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok
+# Subject: CN=NetLock Expressz (Class C) Tanusitvanykiado O=NetLock Halozatbiztonsagi Kft. OU=Tanusitvanykiadok
+# Label: "NetLock Express (Class C) Root"
+# Serial: 104
+# MD5 Fingerprint: 4f:eb:f1:f0:70:c2:80:63:5d:58:9f:da:12:3c:a9:c4
+# SHA1 Fingerprint: e3:92:51:2f:0a:cf:f5:05:df:f6:de:06:7f:75:37:e1:65:ea:57:4b
+# SHA256 Fingerprint: 0b:5e:ed:4e:84:64:03:cf:55:e0:65:84:84:40:ed:2a:82:75:8b:f5:b9:aa:1f:25:3d:46:13:cf:a0:80:ff:3f
+-----BEGIN CERTIFICATE-----
+MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD
+EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X
+DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw
+DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u
+c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr
+TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA
+OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC
+2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW
+RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P
+AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW
+ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0
+YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz
+b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO
+ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB
+IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs
+b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
+ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s
+YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg
+a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g
+SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0
+aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg
+YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg
+Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY
+ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g
+pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4
+Fp1hBWeAyNDYpQcCNJgEjTME1A==
+-----END CERTIFICATE-----
+
+# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
+# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
+# Label: "XRamp Global CA Root"
+# Serial: 107108908803651509692980124233745014957
+# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1
+# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6
+# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
+gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
+MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
+UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
+NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
+dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
+dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
+38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
+KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
+DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
+qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
+JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
+PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
+BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
+jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
+eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
+vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
+IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
+i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
+O+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
+# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
+# Label: "Go Daddy Class 2 CA"
+# Serial: 0
+# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67
+# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4
+# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
+
+# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
+# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
+# Label: "Starfield Class 2 CA"
+# Serial: 0
+# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24
+# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a
+# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Label: "StartCom Certification Authority"
+# Serial: 1
+# MD5 Fingerprint: 22:4d:8f:8a:fc:f7:35:c2:bb:57:34:90:7b:8b:22:16
+# SHA1 Fingerprint: 3e:2b:f7:f2:03:1b:96:f3:8c:e6:c4:d8:a8:5d:3e:2d:58:47:6a:0f
+# SHA256 Fingerprint: c7:66:a9:be:f2:d4:07:1c:86:3a:31:aa:49:20:e8:13:b2:d1:98:60:8c:b7:b7:cf:e2:11:43:b8:36:df:09:ea
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----
+
+# Issuer: O=Government Root Certification Authority
+# Subject: O=Government Root Certification Authority
+# Label: "Taiwan GRCA"
+# Serial: 42023070807708724159991140556527066870
+# MD5 Fingerprint: 37:85:44:53:32:45:1f:20:f0:f3:95:e1:25:c4:43:4e
+# SHA1 Fingerprint: f4:8b:11:bf:de:ab:be:94:54:20:71:e6:41:de:6b:be:88:2b:40:b9
+# SHA256 Fingerprint: 76:00:29:5e:ef:e8:5b:9e:1f:d6:24:db:76:06:2a:aa:ae:59:81:8a:54:d2:77:4c:d4:c0:b2:c0:11:31:e1:b3
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/
+MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow
+PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR
+IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q
+gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy
+yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts
+F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2
+jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx
+ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC
+VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK
+YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH
+EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN
+Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud
+DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE
+MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK
+UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
+TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf
+qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK
+ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE
+JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7
+hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1
+EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm
+nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX
+udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz
+ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe
+LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl
+pYYsfPQS
+-----END CERTIFICATE-----
+
+# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
+# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
+# Label: "Firmaprofesional Root CA"
+# Serial: 1
+# MD5 Fingerprint: 11:92:79:40:3c:b1:83:40:e5:ab:66:4a:67:92:80:df
+# SHA1 Fingerprint: a9:62:8f:4b:98:a9:1b:48:35:ba:d2:c1:46:32:86:bb:66:64:6a:8c
+# SHA256 Fingerprint: c1:cf:0b:52:09:64:35:e3:f1:b7:1d:aa:ec:45:5a:23:11:c8:40:4f:55:83:a9:e2:13:c6:9d:85:7d:94:33:05
+-----BEGIN CERTIFICATE-----
+MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMx
+IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1
+dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w
+HhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTELMAkGA1UEBhMCRVMx
+IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1
+dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u
+Cp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdY
+rv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3z
+hxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPay
+BQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcL
+iam8NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcb
+AgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv
+bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0
+MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E
+FgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n
+VPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq
+u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36m
+hoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzfl
+ZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBp
+QWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YGVM+h4k0460tQtcsm9MracEpqoeJ5
+quGnM/b9Sh/22WA=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Wells Fargo Root Certificate Authority O=Wells Fargo OU=Wells Fargo Certification Authority
+# Subject: CN=Wells Fargo Root Certificate Authority O=Wells Fargo OU=Wells Fargo Certification Authority
+# Label: "Wells Fargo Root CA"
+# Serial: 971282334
+# MD5 Fingerprint: 20:0b:4a:7a:88:a7:a9:42:86:8a:5f:74:56:7b:88:05
+# SHA1 Fingerprint: 93:e6:ab:22:03:03:b5:23:28:dc:da:56:9e:ba:e4:d1:d1:cc:fb:65
+# SHA256 Fingerprint: 03:45:8b:6a:be:ec:c2:14:95:3d:97:14:9a:f4:53:91:69:1d:e9:f9:cd:cc:26:47:86:3a:3d:67:c9:5c:24:3b
+-----BEGIN CERTIFICATE-----
+MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9v
+dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDAxMDExMTY0MTI4WhcNMjEwMTE0
+MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSww
+KgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0G
+A1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n13
+5zHCLielTWi5MbqNQ1mXx3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHE
+SxP9cMIlrCL1dQu3U+SlK93OvRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4O
+JgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCu
+ltQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCE
+AQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMB
+AAGjYTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcB
+CzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRw
+b2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo
+7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZWohDo7qd/
+0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0ROhPs7fpvcmR7
+nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx
+x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ
+33ZwmVxwQ023tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Swisscom Root CA 1 O=Swisscom OU=Digital Certificate Services
+# Subject: CN=Swisscom Root CA 1 O=Swisscom OU=Digital Certificate Services
+# Label: "Swisscom Root CA 1"
+# Serial: 122348795730808398873664200247279986742
+# MD5 Fingerprint: f8:38:7c:77:88:df:2c:16:68:2e:c2:e2:52:4b:b8:f9
+# SHA1 Fingerprint: 5f:3a:fc:0a:8b:64:f6:86:67:34:74:df:7e:a9:a2:fe:f9:fa:7a:51
+# SHA256 Fingerprint: 21:db:20:12:36:60:bb:2e:d4:18:20:5d:a1:1e:e7:a8:5a:65:e2:bc:6e:55:b5:af:7e:78:99:c8:a2:66:d9:2e
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk
+MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0
+YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg
+Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT
+AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp
+Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9
+m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih
+FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/
+TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F
+EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco
+kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu
+HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF
+vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo
+19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC
+L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW
+bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX
+JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw
+FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j
+BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc
+K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf
+ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik
+Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB
+sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e
+3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR
+ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip
+mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH
+b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf
+rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms
+hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y
+zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6
+MBr1mmz0DlP5OlvRHA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
+# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
+# Label: "DigiCert Assured ID Root CA"
+# Serial: 17154717934120587862167794914071425081
+# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72
+# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43
+# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
+JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
+mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
+VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
+AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
+AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
+pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
+dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
+fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
+NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
+H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
+# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
+# Label: "DigiCert Global Root CA"
+# Serial: 10944719598952040374951832963794454346
+# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e
+# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36
+# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
+# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
+# Label: "DigiCert High Assurance EV Root CA"
+# Serial: 3553400076410547919724730734378100087
+# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a
+# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25
+# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
+
+# Issuer: CN=Class 2 Primary CA O=Certplus
+# Subject: CN=Class 2 Primary CA O=Certplus
+# Label: "Certplus Class 2 Primary CA"
+# Serial: 177770208045934040241468760488327595043
+# MD5 Fingerprint: 88:2c:8c:52:b8:a2:3c:f3:f7:bb:03:ea:ae:ac:42:0b
+# SHA1 Fingerprint: 74:20:74:41:72:9c:dd:92:ec:79:31:d8:23:10:8d:c2:81:92:e2:bb
+# SHA256 Fingerprint: 0f:99:3c:8a:ef:97:ba:af:56:87:14:0e:d5:9a:d1:82:1b:b4:af:ac:f0:aa:9a:58:b5:d5:7a:33:8a:3a:fb:cb
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw
+PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz
+cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9
+MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz
+IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ
+ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR
+VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL
+kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd
+EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas
+H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0
+HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4
+QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu
+Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/
+AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8
+yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR
+FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA
+ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB
+kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
+l7+ijrRU
+-----END CERTIFICATE-----
+
+# Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co.
+# Subject: CN=DST Root CA X3 O=Digital Signature Trust Co.
+# Label: "DST Root CA X3"
+# Serial: 91299735575339953335919266965803778155
+# MD5 Fingerprint: 41:03:52:dc:0f:f7:50:1b:16:f0:02:8e:ba:6f:45:c5
+# SHA1 Fingerprint: da:c9:02:4f:54:d8:f6:df:94:93:5f:b1:73:26:38:ca:6a:d7:7c:13
+# SHA256 Fingerprint: 06:87:26:03:31:a7:24:03:d9:09:f1:05:e6:9b:cf:0d:32:e1:bd:24:93:ff:c6:d9:20:6d:11:bc:d6:77:07:39
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
+PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
+Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
+rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
+OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
+xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
+7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
+aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
+SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
+ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
+AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
+R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
+JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
+Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+
+# Issuer: CN=DST ACES CA X6 O=Digital Signature Trust OU=DST ACES
+# Subject: CN=DST ACES CA X6 O=Digital Signature Trust OU=DST ACES
+# Label: "DST ACES CA X6"
+# Serial: 17771143917277623872238992636097467865
+# MD5 Fingerprint: 21:d8:4c:82:2b:99:09:33:a2:eb:14:24:8d:8e:5f:e8
+# SHA1 Fingerprint: 40:54:da:6f:1c:3f:40:74:ac:ed:0f:ec:cd:db:79:d1:53:fb:90:1d
+# SHA256 Fingerprint: 76:7c:95:5a:76:41:2c:89:af:68:8e:90:a1:c7:0f:55:6c:fd:6b:60:25:db:ea:10:41:6d:7e:b6:83:1f:8c:40
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx
+ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w
+MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD
+VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx
+FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu
+ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7
+gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH
+fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a
+ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT
+ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk
+c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto
+dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt
+aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI
+hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk
+QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/
+h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
+nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR
+rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2
+9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis=
+-----END CERTIFICATE-----
+
+# Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=(c) 2005 TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş.
+# Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=(c) 2005 TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş.
+# Label: "TURKTRUST Certificate Services Provider Root 1"
+# Serial: 1
+# MD5 Fingerprint: f1:6a:22:18:c9:cd:df:ce:82:1d:1d:b7:78:5c:a9:a5
+# SHA1 Fingerprint: 79:98:a3:08:e1:4d:65:85:e6:c2:1e:15:3a:71:9f:ba:5a:d3:4a:d9
+# SHA256 Fingerprint: 44:04:e3:3b:5e:14:0d:cf:99:80:51:fd:fc:80:28:c7:c8:16:15:c5:ee:73:7b:11:1b:58:82:33:a9:b5:35:a0
+-----BEGIN CERTIFICATE-----
+MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOc
+UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
+c8SxMQswCQYDVQQGDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykg
+MjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8
+dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMxMDI3MTdaFw0xNTAz
+MjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2Vy
+dGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYD
+VQQHDAZBTktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kg
+xLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEu
+xZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7
+XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2k
+heiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35J
+YbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5C
+urKZ8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1
+JuTm5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51
+b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV
+9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd82YCdAR7
+kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxEq8Sn5RTOPEFh
+fEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy
+B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdA
+aLX/7KfS0zgYnNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKS
+RGQDJereW26fyfJOrN3H
+-----END CERTIFICATE-----
+
+# Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Kasım 2005
+# Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Kasım 2005
+# Label: "TURKTRUST Certificate Services Provider Root 2"
+# Serial: 1
+# MD5 Fingerprint: 37:a5:6e:d4:b1:25:84:97:b7:fd:56:15:7a:f9:a2:00
+# SHA1 Fingerprint: b4:35:d4:e1:11:9d:1c:66:90:a7:49:eb:b3:94:bd:63:7b:a7:82:b7
+# SHA256 Fingerprint: c4:70:cf:54:7e:23:02:b9:77:fb:29:dd:71:a8:9a:7b:6c:1f:60:77:7b:03:29:f5:60:17:f3:28:bf:4f:6b:e6
+-----BEGIN CERTIFICATE-----
+MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc
+UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
+c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS
+S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg
+SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3
+WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv
+bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU
+UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw
+bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe
+LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef
+J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh
+R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ
+Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX
+JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p
+zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S
+Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq
+ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4
+Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz
+gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH
+uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS
+y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI=
+-----END CERTIFICATE-----
+
+# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG
+# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG
+# Label: "SwissSign Gold CA - G2"
+# Serial: 13492815561806991280
+# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93
+# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61
+# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln
+biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF
+MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT
+d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8
+76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+
+bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c
+6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE
+emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd
+MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt
+MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y
+MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y
+FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi
+aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM
+gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB
+qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7
+lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn
+8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6
+45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO
+UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5
+O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC
+bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv
+GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a
+77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC
+hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3
+92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp
+Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w
+ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
+Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+-----END CERTIFICATE-----
+
+# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG
+# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG
+# Label: "SwissSign Silver CA - G2"
+# Serial: 5700383053117599563
+# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13
+# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb
+# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5
+-----BEGIN CERTIFICATE-----
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu
+IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow
+RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY
+U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv
+Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br
+YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF
+nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH
+6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt
+eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/
+c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ
+MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH
+HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf
+jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6
+5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB
+rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
+F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c
+wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB
+AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp
+WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9
+xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ
+2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ
+IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8
+aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X
+em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR
+dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/
+OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+
+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
+tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
+# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
+# Label: "GeoTrust Primary Certification Authority"
+# Serial: 32798226551256963324313806436981982369
+# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf
+# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96
+# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
+MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
+R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
+MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
+AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
+ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
+7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
+kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
+mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
+KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
+6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
+4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
+oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
+UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
+AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
+# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
+# Label: "thawte Primary Root CA"
+# Serial: 69529181992039203566298953787712940909
+# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12
+# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81
+# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
+qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
+BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
+NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
+LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
+A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
+W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
+3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
+6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
+Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
+NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
+r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
+DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
+YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
+/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
+LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
+jVaMaA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
+# Label: "VeriSign Class 3 Public Primary Certification Authority - G5"
+# Serial: 33037644167568058970164719475676101450
+# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c
+# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5
+# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
+ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
+nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
+t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
+SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
+BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
+rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
+NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
+BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
+BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
+MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
+p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
+5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
+WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
+4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
+hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+
+# Issuer: CN=SecureTrust CA O=SecureTrust Corporation
+# Subject: CN=SecureTrust CA O=SecureTrust Corporation
+# Label: "SecureTrust CA"
+# Serial: 17199774589125277788362757014266862032
+# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1
+# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11
+# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
+FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz
+MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv
+cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz
+Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO
+0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao
+wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj
+7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS
+8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT
+BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg
+JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC
+NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3
+6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/
+3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm
+D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS
+CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Secure Global CA O=SecureTrust Corporation
+# Subject: CN=Secure Global CA O=SecureTrust Corporation
+# Label: "Secure Global CA"
+# Serial: 9751836167731051554232119481456978597
+# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de
+# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b
+# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69
+-----BEGIN CERTIFICATE-----
+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
+GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx
+MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg
+Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ
+iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa
+/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ
+jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI
+HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7
+sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w
+gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw
+KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG
+AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L
+URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO
+H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm
+I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY
+iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
+-----END CERTIFICATE-----
+
+# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited
+# Subject: CN=COMODO Certification Authority O=COMODO CA Limited
+# Label: "COMODO Certification Authority"
+# Serial: 104350513648249232941998508985834464573
+# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75
+# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b
+# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
+gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
+BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
+MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
+YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
+RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
+UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
+2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
+Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
+nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
+/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
+PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
+QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
+SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
+IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
+zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
+BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
+ZQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
+# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
+# Label: "Network Solutions Certificate Authority"
+# Serial: 116697915152937497490437556386812487904
+# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e
+# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce
+# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi
+MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp
+dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV
+UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO
+ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz
+c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP
+OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl
+mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF
+BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4
+qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw
+gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu
+bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp
+dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8
+6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/
+h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH
+/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN
+pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
+-----END CERTIFICATE-----
+
+# Issuer: CN=WellsSecure Public Root Certificate Authority O=Wells Fargo WellsSecure OU=Wells Fargo Bank NA
+# Subject: CN=WellsSecure Public Root Certificate Authority O=Wells Fargo WellsSecure OU=Wells Fargo Bank NA
+# Label: "WellsSecure Public Root Certificate Authority"
+# Serial: 1
+# MD5 Fingerprint: 15:ac:a5:c2:92:2d:79:bc:e8:7f:cb:67:ed:02:cf:36
+# SHA1 Fingerprint: e7:b4:f6:9d:61:ec:90:69:db:7e:90:a7:40:1a:3c:f4:7d:4f:e8:ee
+# SHA256 Fingerprint: a7:12:72:ae:aa:a3:cf:e8:72:7f:7f:b3:9f:0f:b3:d1:e5:42:6e:90:60:b0:6e:e6:f1:3e:9a:3c:58:33:cd:43
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx
+IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs
+cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v
+dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0
+MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl
+bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD
+DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r
+WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU
+Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs
+HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj
+z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf
+SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl
+AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG
+KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P
+AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j
+BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC
+VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX
+ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB
+ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd
+/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB
+A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn
+k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9
+iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv
+2G0xffX8oRAHh84vWdw+WNs=
+-----END CERTIFICATE-----
+
+# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited
+# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited
+# Label: "COMODO ECC Certification Authority"
+# Serial: 41578283867086692638256921589707938090
+# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23
+# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11
+# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
+IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
+MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
+ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
+T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
+FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
+cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
+BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
+fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
+GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
+
+# Issuer: CN=IGC/A O=PM/SGDN OU=DCSSI
+# Subject: CN=IGC/A O=PM/SGDN OU=DCSSI
+# Label: "IGC/A"
+# Serial: 245102874772
+# MD5 Fingerprint: 0c:7f:dd:6a:f4:2a:b9:c8:9b:bd:20:7e:a9:db:5c:37
+# SHA1 Fingerprint: 60:d6:89:74:b5:c2:65:9e:8a:0f:c1:88:7c:88:d2:46:69:1b:18:2c
+# SHA256 Fingerprint: b9:be:a7:86:0a:96:2e:a3:61:1d:ab:97:ab:6d:a3:e2:1c:10:68:b9:7d:55:57:5e:d0:e1:12:79:c1:1c:89:32
+-----BEGIN CERTIFICATE-----
+MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYT
+AkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQ
+TS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG
+9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMB4XDTAyMTIxMzE0MjkyM1oXDTIw
+MTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAM
+BgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEO
+MAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2
+LmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaI
+s9z4iPf930Pfeo2aSVz2TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2
+xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCWSo7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4
+u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYyHF2fYPepraX/z9E0+X1b
+F8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNdfrGoRpAx
+Vs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGd
+PDPQtQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNV
+HSAEDjAMMAoGCCqBegF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAx
+NjAfBgNVHSMEGDAWgBSjBS8YYFDCiQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUF
+AAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RKq89toB9RlPhJy3Q2FLwV3duJ
+L92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3QMZsyK10XZZOY
+YLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg
+Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2a
+NjSaTFR+FwNIlQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R
+0982gaEbeC9xs/FZTEYYKKuF0mBWWg==
+-----END CERTIFICATE-----
+
+# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication EV RootCA1
+# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication EV RootCA1
+# Label: "Security Communication EV RootCA1"
+# Serial: 0
+# MD5 Fingerprint: 22:2d:a6:01:ea:7c:0a:f7:f0:6c:56:43:3f:77:76:d3
+# SHA1 Fingerprint: fe:b8:c4:32:dc:f9:76:9a:ce:ae:3d:d8:90:8f:fd:28:86:65:64:7d
+# SHA256 Fingerprint: a2:2d:ba:68:1e:97:37:6e:2d:39:7d:72:8a:ae:3a:9b:62:96:b9:fd:ba:60:bc:2e:11:f6:47:f2:c6:75:fb:37
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl
+MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh
+U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz
+MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N
+IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11
+bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE
+RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO
+zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5
+bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF
+MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1
+VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC
+OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW
+tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ
+q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb
+EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+
+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O
+VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
+-----END CERTIFICATE-----
+
+# Issuer: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed
+# Subject: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed
+# Label: "OISTE WISeKey Global Root GA CA"
+# Serial: 86718877871133159090080555911823548314
+# MD5 Fingerprint: bc:6c:51:33:a7:e9:d3:66:63:54:15:72:1b:21:92:93
+# SHA1 Fingerprint: 59:22:a1:e1:5a:ea:16:35:21:f8:98:39:6a:46:46:b0:44:1b:0f:a9
+# SHA256 Fingerprint: 41:c9:23:86:6a:b4:ca:d6:b7:ad:57:80:81:58:2e:02:07:97:a6:cb:df:4f:ff:78:ce:83:96:b3:89:37:d7:f5
+-----BEGIN CERTIFICATE-----
+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB
+ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly
+aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
+ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w
+NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G
+A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD
+VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX
+SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR
+VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2
+w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF
+mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg
+4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9
+4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw
+DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw
+EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx
+SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2
+ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8
+vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi
+Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ
+/L7fCg0=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Microsec e-Szigno Root CA O=Microsec Ltd. OU=e-Szigno CA
+# Subject: CN=Microsec e-Szigno Root CA O=Microsec Ltd. OU=e-Szigno CA
+# Label: "Microsec e-Szigno Root CA"
+# Serial: 272122594155480254301341951808045322001
+# MD5 Fingerprint: f0:96:b6:2f:c5:10:d5:67:8e:83:25:32:e8:5e:2e:e5
+# SHA1 Fingerprint: 23:88:c9:d3:71:cc:9e:96:3d:ff:7d:3c:a7:ce:fc:d6:25:ec:19:0d
+# SHA256 Fingerprint: 32:7a:3d:76:1a:ba:de:a0:34:eb:99:84:06:27:5c:b1:a4:77:6e:fd:ae:2f:df:6d:01:68:ea:1c:4f:55:67:d0
+-----BEGIN CERTIFICATE-----
+MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAw
+cjELMAkGA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNy
+b3NlYyBMdGQuMRQwEgYDVQQLEwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9z
+ZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0MDYxMjI4NDRaFw0xNzA0MDYxMjI4
+NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEWMBQGA1UEChMN
+TWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMTGU1p
+Y3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2u
+uO/TEdyB5s87lozWbxXGd36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+
+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/NoqdNAoI/gqyFxuEPkEeZlApxcpMqyabA
+vjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjcQR/Ji3HWVBTji1R4P770
+Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJPqW+jqpx
+62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcB
+AQRbMFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3Aw
+LQYIKwYBBQUHMAKGIWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAP
+BgNVHRMBAf8EBTADAQH/MIIBcwYDVR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIB
+AQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3LmUtc3ppZ25vLmh1L1NaU1ov
+MIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0AdAB2AOEAbgB5
+ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn
+AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABT
+AHoAbwBsAGcA4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABh
+ACAAcwB6AGUAcgBpAG4AdAAgAGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABo
+AHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMAegBpAGcAbgBvAC4AaAB1AC8AUwBa
+AFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6Ly93d3cuZS1zemln
+bm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NOPU1p
+Y3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxP
+PU1pY3Jvc2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZv
+Y2F0aW9uTGlzdDtiaW5hcnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuB
+EGluZm9AZS1zemlnbm8uaHWkdzB1MSMwIQYDVQQDDBpNaWNyb3NlYyBlLVN6aWdu
+w7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhTWjEWMBQGA1UEChMNTWlj
+cm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhVMIGsBgNV
+HSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJI
+VTERMA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDAS
+BgNVBAsTC2UtU3ppZ25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBS
+b290IENBghEAzLjnv04pGv2i3GalHCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS
+8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMTnGZjWS7KXHAM/IO8VbH0jgds
+ZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FEaGAHQzAxQmHl
+7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a
+86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfR
+hUZLphK3dehKyVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/
+MPMMNz7UwiiAc7EBt51alhQBS6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Certigna O=Dhimyotis
+# Subject: CN=Certigna O=Dhimyotis
+# Label: "Certigna"
+# Serial: 18364802974209362175
+# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff
+# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97
+# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
+BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X
+DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ
+BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4
+QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny
+gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw
+zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q
+130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2
+JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw
+DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw
+ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT
+AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj
+AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG
+9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h
+bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc
+fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu
+HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w
+t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
+WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=AC Raíz Certicámara S.A. O=Sociedad Cameral de Certificación Digital - Certicámara S.A.
+# Subject: CN=AC Raíz Certicámara S.A. O=Sociedad Cameral de Certificación Digital - Certicámara S.A.
+# Label: "AC Ra\xC3\xADz Certic\xC3\xA1mara S.A."
+# Serial: 38908203973182606954752843738508300
+# MD5 Fingerprint: 93:2a:3e:f6:fd:23:69:0d:71:20:d4:2b:47:99:2b:a6
+# SHA1 Fingerprint: cb:a1:c5:f8:b0:e3:5e:b8:b9:45:12:d3:f9:34:a2:e9:06:10:d3:36
+# SHA256 Fingerprint: a6:c5:1e:0d:a5:ca:0a:93:09:d2:e4:c0:e4:0c:2a:f9:10:7a:ae:82:03:85:7f:e1:98:e3:e7:69:e3:43:08:5c
+-----BEGIN CERTIFICATE-----
+MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx
+CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp
+ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa
+QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw
+NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft
+ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu
+QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG
+qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL
+fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ
+Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4
+Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ
+54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b
+MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j
+ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej
+YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt
+A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF
+rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ
+pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB
+lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy
+YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50
+7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs
+YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6
+xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc
+unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/
+Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp
+ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42
+gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0
+jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+
+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD
+W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/
+RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r
+MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk
+BYn8eNZcLCZDqQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
+# Subject: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
+# Label: "TC TrustCenter Class 2 CA II"
+# Serial: 941389028203453866782103406992443
+# MD5 Fingerprint: ce:78:33:5c:59:78:01:6e:18:ea:b9:36:a0:b9:2e:23
+# SHA1 Fingerprint: ae:50:83:ed:7c:f4:5c:bc:8f:61:c6:21:fe:68:5d:79:42:21:15:6e
+# SHA256 Fingerprint: e6:b8:f8:76:64:85:f8:07:ae:7f:8d:ac:16:70:46:1f:07:c0:a1:3e:ef:3a:1f:f7:17:53:8d:7a:ba:d3:91:b4
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf
+tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg
+uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J
+XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK
+8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99
+5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3
+kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
+dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6
+Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
+JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
+Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS
+GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt
+ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8
+au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV
+hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI
+dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
+# Subject: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
+# Label: "TC TrustCenter Class 3 CA II"
+# Serial: 1506523511417715638772220530020799
+# MD5 Fingerprint: 56:5f:aa:80:61:12:17:f6:67:21:e6:2b:6d:61:56:8e
+# SHA1 Fingerprint: 80:25:ef:f4:6e:70:c8:d4:72:24:65:84:fe:40:3b:8a:8d:6a:db:f5
+# SHA256 Fingerprint: 8d:a0:84:fc:f9:9c:e0:77:22:f8:9b:32:05:93:98:06:fa:5c:b8:11:e1:c8:13:f6:a1:08:c7:d3:36:b3:40:8e
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW
+Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q
+Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2
+1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq
+ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1
+Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX
+XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
+dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6
+Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
+JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
+Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN
+irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8
+TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6
+g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB
+95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj
+S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A==
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Subject: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Label: "TC TrustCenter Universal CA I"
+# Serial: 601024842042189035295619584734726
+# MD5 Fingerprint: 45:e1:a5:72:c5:a9:36:64:40:9e:f5:e4:58:84:67:8c
+# SHA1 Fingerprint: 6b:2f:34:ad:89:58:be:62:fd:b0:6b:5c:ce:bb:9d:d9:4f:4e:39:f3
+# SHA256 Fingerprint: eb:f3:c0:2a:87:89:b1:fb:7d:51:19:95:d6:63:b7:29:06:d9:13:ce:0d:5e:10:56:8a:8a:77:e2:58:61:67:e7
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx
+MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg
+R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD
+VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR
+JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T
+fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu
+jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z
+wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ
+fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD
+VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G
+CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1
+7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn
+8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs
+ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
+ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/
+2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
+-----END CERTIFICATE-----
+
+# Issuer: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center
+# Subject: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center
+# Label: "Deutsche Telekom Root CA 2"
+# Serial: 38
+# MD5 Fingerprint: 74:01:4a:91:b1:08:c4:58:ce:47:cd:f0:dd:11:53:08
+# SHA1 Fingerprint: 85:a4:08:c0:9c:19:3e:5d:51:58:7d:cd:d6:13:30:fd:8c:de:37:bf
+# SHA256 Fingerprint: b6:19:1a:50:d0:c3:97:7f:7d:a9:9b:cd:aa:c8:6a:22:7d:ae:b9:67:9e:c7:0b:a3:b0:c9:d9:22:71:c1:70:d3
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc
+MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj
+IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB
+IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE
+RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl
+U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290
+IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU
+ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC
+QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr
+rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S
+NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc
+QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH
+txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP
+BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
+AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp
+tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa
+IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl
+6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+
+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
+Cm26OWMohpLzGITY+9HPBVZkVw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=ComSign Secured CA O=ComSign
+# Subject: CN=ComSign Secured CA O=ComSign
+# Label: "ComSign Secured CA"
+# Serial: 264725503855295744117309814499492384489
+# MD5 Fingerprint: 40:01:25:06:8d:21:43:6a:0e:43:00:9c:e7:43:f3:d5
+# SHA1 Fingerprint: f9:cd:0e:2c:da:76:24:c1:8f:bd:f0:f0:ab:b6:45:b8:f7:fe:d5:7a
+# SHA256 Fingerprint: 50:79:41:c7:44:60:a0:b4:70:86:22:0d:4e:99:32:57:2a:b5:d1:b5:bb:cb:89:80:ab:1c:b1:76:51:a8:44:d2
+-----BEGIN CERTIFICATE-----
+MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw
+PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu
+MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx
+GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL
+MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf
+HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh
+gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW
+v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue
+Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr
+9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt
+6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7
+MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl
+Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58
+ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq
+hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p
+iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC
+dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL
+kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL
+hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz
+OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc
+# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc
+# Label: "Cybertrust Global Root"
+# Serial: 4835703278459682877484360
+# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1
+# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6
+# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG
+A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh
+bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE
+ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS
+b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5
+7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS
+J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y
+HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP
+t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz
+FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY
+XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
+MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw
+hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js
+MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA
+A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj
+Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx
+XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o
+omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc
+A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
+WL1WMRJOEcgh4LMRkWXbtKaIOM5V
+-----END CERTIFICATE-----
+
+# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority
+# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority
+# Label: "ePKI Root Certification Authority"
+# Serial: 28956088682735189655030529057352760477
+# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3
+# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0
+# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5
+-----BEGIN CERTIFICATE-----
+MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe
+MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
+ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw
+IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL
+SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH
+SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh
+ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X
+DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1
+TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ
+fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA
+sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU
+WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS
+nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH
+dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip
+NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC
+AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF
+MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
+ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB
+uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl
+PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP
+JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/
+gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2
+j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6
+5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB
+o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS
+/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z
+Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE
+W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D
+hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
+-----END CERTIFICATE-----
+
+# Issuer: CN=TÜBİTAK UEKAE Kök Sertifika Hizmet Sağlayıcısı - Sürüm 3 O=Türkiye Bilimsel ve Teknolojik Araştırma Kurumu - TÜBİTAK OU=Ulusal Elektronik ve Kriptoloji Araştırma Enstitüsü - UEKAE/Kamu Sertifikasyon Merkezi
+# Subject: CN=TÜBİTAK UEKAE Kök Sertifika Hizmet Sağlayıcısı - Sürüm 3 O=Türkiye Bilimsel ve Teknolojik Araştırma Kurumu - TÜBİTAK OU=Ulusal Elektronik ve Kriptoloji Araştırma Enstitüsü - UEKAE/Kamu Sertifikasyon Merkezi
+# Label: "T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3"
+# Serial: 17
+# MD5 Fingerprint: ed:41:f5:8c:50:c5:2b:9c:73:e6:ee:6c:eb:c2:a8:26
+# SHA1 Fingerprint: 1b:4b:39:61:26:27:6b:64:91:a2:68:6d:d7:02:43:21:2d:1f:1d:96
+# SHA256 Fingerprint: e4:c7:34:30:d7:a5:b5:09:25:df:43:37:0a:0d:21:6e:9a:79:b9:d6:db:83:73:a0:c6:9e:b1:cc:31:c7:c5:2a
+-----BEGIN CERTIFICATE-----
+MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS
+MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp
+bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw
+VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy
+YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy
+dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2
+ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe
+Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx
+GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls
+aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU
+QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh
+xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0
+aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr
+IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h
+gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK
+O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO
+fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw
+lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL
+hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID
+AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP
+NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t
+wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM
+7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh
+gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n
+oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs
+yZyQ2uypQjyttgI=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Buypass Class 2 CA 1 O=Buypass AS-983163327
+# Subject: CN=Buypass Class 2 CA 1 O=Buypass AS-983163327
+# Label: "Buypass Class 2 CA 1"
+# Serial: 1
+# MD5 Fingerprint: b8:08:9a:f0:03:cc:1b:0d:c8:6c:0b:76:a1:75:64:23
+# SHA1 Fingerprint: a0:a1:ab:90:c9:fc:84:7b:3b:12:61:e8:97:7d:5f:d3:22:61:d3:cc
+# SHA256 Fingerprint: 0f:4e:9c:dd:26:4b:02:55:50:d1:70:80:63:40:21:4f:e9:44:34:c9:b0:2f:69:7e:c7:10:fc:5f:ea:fb:5e:38
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg
+Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL
+MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD
+VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0
+ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX
+l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB
+HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B
+5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3
+WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD
+AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP
+gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+
+DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu
+BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs
+h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk
+LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho
+-----END CERTIFICATE-----
+
+# Issuer: CN=Buypass Class 3 CA 1 O=Buypass AS-983163327
+# Subject: CN=Buypass Class 3 CA 1 O=Buypass AS-983163327
+# Label: "Buypass Class 3 CA 1"
+# Serial: 2
+# MD5 Fingerprint: df:3c:73:59:81:e7:39:50:81:04:4c:34:a2:cb:b3:7b
+# SHA1 Fingerprint: 61:57:3a:11:df:0e:d8:7e:d5:92:65:22:ea:d0:56:d7:44:b3:23:71
+# SHA256 Fingerprint: b7:b1:2b:17:1f:82:1d:aa:99:0c:d0:fe:50:87:b1:28:44:8b:a8:e5:18:4f:84:c5:1e:02:b5:c8:fb:96:2b:24
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg
+Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL
+MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD
+VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg
+isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z
+NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI
++MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R
+hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+
+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD
+AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP
+Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s
+EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2
+mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC
+e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow
+dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915
+-----END CERTIFICATE-----
+
+# Issuer: CN=EBG Elektronik Sertifika Hizmet Sağlayıcısı O=EBG Bilişim Teknolojileri ve Hizmetleri A.Ş.
+# Subject: CN=EBG Elektronik Sertifika Hizmet Sağlayıcısı O=EBG Bilişim Teknolojileri ve Hizmetleri A.Ş.
+# Label: "EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1"
+# Serial: 5525761995591021570
+# MD5 Fingerprint: 2c:20:26:9d:cb:1a:4a:00:85:b5:b7:5a:ae:c2:01:37
+# SHA1 Fingerprint: 8c:96:ba:eb:dd:2b:07:07:48:ee:30:32:66:a0:f3:98:6e:7c:ae:58
+# SHA256 Fingerprint: 35:ae:5b:dd:d8:f7:ae:63:5c:ff:ba:56:82:a8:f0:0b:95:f4:84:62:c7:10:8e:e9:a0:e5:29:2b:07:4a:af:b2
+-----BEGIN CERTIFICATE-----
+MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNV
+BAMML0VCRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
+c8SxMTcwNQYDVQQKDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXpt
+ZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4
+MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25payBTZXJ0aWZpa2Eg
+SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2ltIFRl
+a25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h
+4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk
+tiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4s
+tPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTL
+dlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4
+c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8Um
+TDGyY5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z
++kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0O
+Lna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMW
+OeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8owrXieqW
+fo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2
+l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
+/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgw
+FoAU587GT/wWZ5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+
+8ygjdsZs93/mQJ7ANtyVDR2tFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI
+6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgmzJNSroIBk5DKd8pNSe/iWtkqvTDO
+TLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64kXPBfrAowzIpAoHME
+wfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqTbCmY
+Iai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJn
+xk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q
+DgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9q
+Kd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11t
+hie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH4
+7ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7
+QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT
+-----END CERTIFICATE-----
+
+# Issuer: O=certSIGN OU=certSIGN ROOT CA
+# Subject: O=certSIGN OU=certSIGN ROOT CA
+# Label: "certSIGN ROOT CA"
+# Serial: 35210227249154
+# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17
+# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b
+# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb
+-----BEGIN CERTIFICATE-----
+MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT
+AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD
+QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP
+MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do
+0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ
+UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d
+RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ
+OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv
+JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C
+AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O
+BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ
+LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY
+MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ
+44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I
+Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw
+i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN
+9u6wWk5JRFRYX0KD
+-----END CERTIFICATE-----
+
+# Issuer: CN=CNNIC ROOT O=CNNIC
+# Subject: CN=CNNIC ROOT O=CNNIC
+# Label: "CNNIC ROOT"
+# Serial: 1228079105
+# MD5 Fingerprint: 21:bc:82:ab:49:c4:13:3b:4b:b2:2b:5c:6b:90:9c:19
+# SHA1 Fingerprint: 8b:af:4c:9b:1d:f0:2a:92:f7:da:12:8e:b9:1b:ac:f4:98:60:4b:6f
+# SHA256 Fingerprint: e2:83:93:77:3d:a8:45:a6:79:f2:08:0c:c7:fb:44:a3:b7:a1:c3:79:2c:b7:eb:77:29:fd:cb:6a:8d:99:ae:a7
+-----BEGIN CERTIFICATE-----
+MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD
+TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2
+MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF
+Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh
+IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6
+dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO
+V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC
+GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN
+v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB
+AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB
+Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO
+76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK
+OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH
+ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi
+yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL
+buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj
+2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE=
+-----END CERTIFICATE-----
+
+# Issuer: O=Japanese Government OU=ApplicationCA
+# Subject: O=Japanese Government OU=ApplicationCA
+# Label: "ApplicationCA - Japanese Government"
+# Serial: 49
+# MD5 Fingerprint: 7e:23:4e:5b:a7:a5:b4:25:e9:00:07:74:11:62:ae:d6
+# SHA1 Fingerprint: 7f:8a:b0:cf:d0:51:87:6a:66:f3:36:0f:47:c8:8d:8c:d3:35:fc:74
+# SHA256 Fingerprint: 2d:47:43:7d:e1:79:51:21:5a:12:f3:c5:8e:51:c7:29:a5:80:26:ef:1f:cc:0a:5f:b3:d9:dc:01:2f:60:0d:19
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc
+MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp
+b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT
+AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs
+aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H
+j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K
+f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55
+IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw
+FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht
+QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm
+/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ
+k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ
+MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC
+seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ
+hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+
+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U
+DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj
+B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL
+rosot4LKGAfmt1t06SAZf7IbiVQ=
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
+# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
+# Label: "GeoTrust Primary Certification Authority - G3"
+# Serial: 28809105769928564313984085209975885599
+# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05
+# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd
+# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
+mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
+MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
+cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ
+BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
+MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0
+BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz
++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm
+hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn
+5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W
+JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL
+DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC
+huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB
+AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB
+zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN
+kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
+SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
+spki4cErx5z481+oghLrGREt
+-----END CERTIFICATE-----
+
+# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
+# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
+# Label: "thawte Primary Root CA - G2"
+# Serial: 71758320672825410020661621085256472406
+# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f
+# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12
+# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57
+-----BEGIN CERTIFICATE-----
+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
+IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
+BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
+MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
+d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
+YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
+dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
+BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
+papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
+DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
+KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
+XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
+# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
+# Label: "thawte Primary Root CA - G3"
+# Serial: 127614157056681299805556476275995414779
+# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31
+# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2
+# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
+rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
+BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
+Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
+LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
+MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
+ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
+gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
+YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
+b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
+9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
+zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
+OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
+HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
+2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
+oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
+KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
+m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
+MdRAGmI0Nj81Aa6sY6A=
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
+# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
+# Label: "GeoTrust Primary Certification Authority - G2"
+# Serial: 80682863203381065782177908751794619243
+# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a
+# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0
+# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66
+-----BEGIN CERTIFICATE-----
+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
+MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
+KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
+MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
+BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
+NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
+BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
+So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
+tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
+CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
+qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
+rD6ogRLQy7rQkgu2npaqBA+K
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
+# Label: "VeriSign Universal Root Certification Authority"
+# Serial: 85209574734084581917763752644031726877
+# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19
+# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54
+# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
+vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
+ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
+IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
+IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
+bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
+9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
+H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
+LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
+/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
+rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
+WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
+exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
+sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
+seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
+4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
+lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
+7M2CYfE45k+XmCpajQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
+# Label: "VeriSign Class 3 Public Primary Certification Authority - G4"
+# Serial: 63143484348153506665311985501458640051
+# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41
+# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a
+# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp
+U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg
+SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln
+biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm
+GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve
+fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
+aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj
+aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW
+kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
+4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
+FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=NetLock Arany (Class Gold) Főtanúsítvány O=NetLock Kft. OU=Tanúsítványkiadók (Certification Services)
+# Subject: CN=NetLock Arany (Class Gold) Főtanúsítvány O=NetLock Kft. OU=Tanúsítványkiadók (Certification Services)
+# Label: "NetLock Arany (Class Gold) Főtanúsítvány"
+# Serial: 80544274841616
+# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88
+# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91
+# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG
+EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3
+MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl
+cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR
+dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB
+pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM
+b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm
+aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz
+IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT
+lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz
+AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5
+VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG
+ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2
+BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG
+AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M
+U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh
+bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C
++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
+bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F
+uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2
+XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden
+# Subject: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden
+# Label: "Staat der Nederlanden Root CA - G2"
+# Serial: 10000012
+# MD5 Fingerprint: 7c:a5:0f:f8:5b:9a:7d:6d:30:ae:54:5a:e3:42:a2:8a
+# SHA1 Fingerprint: 59:af:82:79:91:86:c7:b4:75:07:cb:cf:03:57:46:eb:04:dd:b7:16
+# SHA256 Fingerprint: 66:8c:83:94:7d:a6:3b:72:4b:ec:e1:74:3c:31:a0:e6:ae:d0:db:8e:c5:b3:1b:e3:77:bb:78:4f:91:b6:71:6f
+-----BEGIN CERTIFICATE-----
+MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
+TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX
+DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl
+ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv
+b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291
+qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp
+uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU
+Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE
+pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp
+5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M
+UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN
+GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy
+5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv
+6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK
+eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6
+B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/
+BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov
+L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG
+SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS
+CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen
+5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897
+IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK
+gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL
++63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL
+vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm
+bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk
+N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC
+Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z
+ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=CA Disig O=Disig a.s.
+# Subject: CN=CA Disig O=Disig a.s.
+# Label: "CA Disig"
+# Serial: 1
+# MD5 Fingerprint: 3f:45:96:39:e2:50:87:f7:bb:fe:98:0c:3c:20:98:e6
+# SHA1 Fingerprint: 2a:c8:d5:8b:57:ce:bf:2f:49:af:f2:fc:76:8f:51:14:62:90:7a:41
+# SHA256 Fingerprint: 92:bf:51:19:ab:ec:ca:d0:b1:33:2d:c4:e1:d0:5f:ba:75:b5:67:90:44:ee:0c:a2:6e:93:1f:74:4f:2f:33:cf
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzET
+MBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UE
+AxMIQ0EgRGlzaWcwHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQsw
+CQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcg
+YS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgmGErE
+Nx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnX
+mjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYD
+XcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW
+S8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8Kp
+FhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQD
+AgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cu
+ZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5z
+ay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2sv
+Y2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEw
+DQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA/ec8J9B6
+yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq
+EEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/
+CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeB
+EicTXxChds6KezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFN
+PGO+I++MzVpQuGhU+QqZMxEA4Z7CRneC9VkGjCFMhwnN5ag=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Juur-SK O=AS Sertifitseerimiskeskus
+# Subject: CN=Juur-SK O=AS Sertifitseerimiskeskus
+# Label: "Juur-SK"
+# Serial: 999181308
+# MD5 Fingerprint: aa:8e:5d:d9:f8:db:0a:58:b7:8d:26:87:6c:82:35:55
+# SHA1 Fingerprint: 40:9d:4b:d9:17:b5:5c:27:b6:9b:64:cb:98:22:44:0d:cd:09:b8:89
+# SHA256 Fingerprint: ec:c3:e9:c3:40:75:03:be:e0:91:aa:95:2f:41:34:8f:f8:8b:aa:86:3b:22:64:be:fa:c8:07:90:15:74:e9:39
+-----BEGIN CERTIFICATE-----
+MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw
+MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw
+CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ
+MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB
+SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz
+ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH
+LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP
+PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL
+2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w
+ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC
+MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk
+AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0
+AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz
+AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz
+AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f
+BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
+FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY
+P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi
+CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g
+kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95
+HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS
+na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q
+qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z
+TbvGRNs2yyqcjg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post
+# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post
+# Label: "Hongkong Post Root CA 1"
+# Serial: 1000
+# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca
+# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58
+# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2
+-----BEGIN CERTIFICATE-----
+MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx
+FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg
+Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG
+A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr
+b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ
+jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn
+PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh
+ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9
+nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h
+q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED
+MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC
+mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3
+7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB
+oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs
+EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO
+fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi
+AmvZWg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc.
+# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc.
+# Label: "SecureSign RootCA11"
+# Serial: 1
+# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26
+# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3
+# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr
+MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG
+A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0
+MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp
+Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD
+QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz
+i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8
+h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV
+MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9
+UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni
+8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC
+h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
+AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm
+KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ
+X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr
+QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5
+pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN
+QSdJQO7e5iNEOdyhIta6A/I=
+-----END CERTIFICATE-----
+
+# Issuer: CN=ACEDICOM Root O=EDICOM OU=PKI
+# Subject: CN=ACEDICOM Root O=EDICOM OU=PKI
+# Label: "ACEDICOM Root"
+# Serial: 7029493972724711941
+# MD5 Fingerprint: 42:81:a0:e2:1c:e3:55:10:de:55:89:42:65:96:22:e6
+# SHA1 Fingerprint: e0:b4:32:2e:b2:f6:a5:68:b6:54:53:84:48:18:4a:50:36:87:43:84
+# SHA256 Fingerprint: 03:95:0f:b4:9a:53:1f:3e:19:91:94:23:98:df:a9:e0:ea:32:d7:ba:1c:dd:9b:c8:5d:b5:7e:d9:40:0b:43:4a
+-----BEGIN CERTIFICATE-----
+MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE
+AwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x
+CzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW
+MBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZF
+RElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHkWLn7
+09gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7
+XBZXehuDYAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5P
+Grjm6gSSrj0RuVFCPYewMYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAK
+t0SdE3QrwqXrIhWYENiLxQSfHY9g5QYbm8+5eaA9oiM/Qj9r+hwDezCNzmzAv+Yb
+X79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbkHQl/Sog4P75n/TSW9R28
+MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTTxKJxqvQU
+fecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI
+2Sf23EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyH
+K9caUPgn6C9D4zq92Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEae
+ZAwUswdbxcJzbPEHXEUkFDWug/FqTYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAP
+BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz4SsrSbbXc6GqlPUB53NlTKxQ
+MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU9QHnc2VMrFAw
+RAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv
+bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWIm
+fQwng4/F9tqgaHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3
+gvoFNTPhNahXwOf9jU8/kzJPeGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKe
+I6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1PwkzQSulgUV1qzOMPPKC8W64iLgpq0i
+5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1ThCojz2GuHURwCRi
+ipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oIKiMn
+MCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZ
+o5NjEFIqnxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6
+zqylfDJKZ0DcMDQj3dcEI2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacN
+GHk0vFQYXlPKNFHtRQrmjseCNj6nOGOpMCwXEGCSn1WHElkQwg9naRHMTh5+Spqt
+r0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3otkYNbn5XOmeUwssfnHdK
+Z05phkOTOPu220+DkdRgfks+KzgHVZhepA==
+-----END CERTIFICATE-----
+
+# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
+# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
+# Label: "Verisign Class 3 Public Primary Certification Authority"
+# Serial: 80507572722862485515306429940691309246
+# MD5 Fingerprint: ef:5a:f1:33:ef:f1:cd:bb:51:02:ee:12:14:4b:96:c4
+# SHA1 Fingerprint: a1:db:63:93:91:6f:17:e4:18:55:09:40:04:15:c7:02:40:b0:ae:6b
+# SHA256 Fingerprint: a4:b6:b3:99:6f:c2:f3:06:b3:fd:86:81:bd:63:41:3d:8c:50:09:cc:4f:a3:29:c2:cc:f0:e2:fa:1b:14:03:05
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i
+2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ
+2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ
+-----END CERTIFICATE-----
+
+# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd.
+# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd.
+# Label: "Microsec e-Szigno Root CA 2009"
+# Serial: 14014712776195784473
+# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1
+# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e
+# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78
+-----BEGIN CERTIFICATE-----
+MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
+VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0
+ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G
+CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y
+OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx
+FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp
+Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
+dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP
+kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc
+cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U
+fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7
+N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC
+xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1
++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM
+Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG
+SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h
+mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk
+ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
+tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c
+2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t
+HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW
+-----END CERTIFICATE-----
+
+# Issuer: CN=e-Guven Kok Elektronik Sertifika Hizmet Saglayicisi O=Elektronik Bilgi Guvenligi A.S.
+# Subject: CN=e-Guven Kok Elektronik Sertifika Hizmet Saglayicisi O=Elektronik Bilgi Guvenligi A.S.
+# Label: "E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi"
+# Serial: 91184789765598910059173000485363494069
+# MD5 Fingerprint: 3d:41:29:cb:1e:aa:11:74:cd:5d:b0:62:af:b0:43:5b
+# SHA1 Fingerprint: dd:e1:d2:a9:01:80:2e:1d:87:5e:84:b3:80:7e:4b:b1:fd:99:41:34
+# SHA256 Fingerprint: e6:09:07:84:65:a4:19:78:0c:b6:ac:4c:1c:0b:fb:46:53:d9:d9:cc:6e:b3:94:6e:b7:f3:d6:99:97:ba:d5:98
+-----BEGIN CERTIFICATE-----
+MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1
+MQswCQYDVQQGEwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxp
+Z2kgQS5TLjE8MDoGA1UEAxMzZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZp
+a2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3MDEwNDExMzI0OFoXDTE3MDEwNDEx
+MzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0cm9uaWsgQmlsZ2kg
+R3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9uaWsg
+U2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdU
+MZTe1RK6UxYC6lhj71vY8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlT
+L/jDj/6z/P2douNffb7tC+Bg62nsM+3YjfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H
+5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAIJjjcJRFHLfO6IxClv7wC
+90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk9Ok0oSy1
+c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoE
+VtstxNulMA0GCSqGSIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLP
+qk/CaOv/gKlR6D1id4k9CnU58W5dF4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S
+/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwqD2fK/A+JYZ1lpTzlvBNbCNvj
+/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4Vwpm+Vganf2X
+KWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq
+fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX
+-----END CERTIFICATE-----
+
+# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
+# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
+# Label: "GlobalSign Root CA - R3"
+# Serial: 4835703278459759426209954
+# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28
+# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad
+# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
+MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
+RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
+gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
+KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
+QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
+XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
+LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
+RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
+jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
+6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
+mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
+Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
+WD9f
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Subject: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Label: "TC TrustCenter Universal CA III"
+# Serial: 2010889993983507346460533407902964
+# MD5 Fingerprint: 9f:dd:db:ab:ff:8e:ff:45:21:5f:f0:6c:9d:8f:fe:2b
+# SHA1 Fingerprint: 96:56:cd:7b:57:96:98:95:d0:e1:41:46:68:06:fb:b8:c6:11:06:87
+# SHA256 Fingerprint: 30:9b:4a:87:f6:ca:56:c9:31:69:aa:a9:9c:6d:98:88:54:d7:89:2b:d5:43:7e:2d:07:b2:9c:be:da:55:d3:5d
+-----BEGIN CERTIFICATE-----
+MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy
+MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl
+ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm
+BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF
+5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv
+DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v
+zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT
+yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj
+dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh
+MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB
+Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI
+4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz
+dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY
+aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G
+DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV
+CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH
+LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
+# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
+# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068"
+# Serial: 6047274297262753887
+# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3
+# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa
+# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE
+BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h
+cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy
+MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg
+Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9
+thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM
+cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG
+L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i
+NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h
+X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b
+m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy
+Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja
+EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T
+KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF
+6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh
+OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD
+VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
+cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv
+ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl
+AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF
+661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9
+am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1
+ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481
+PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS
+3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k
+SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF
+3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM
+ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g
+StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz
+Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB
+jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
+-----END CERTIFICATE-----
+
+# Issuer: CN=Izenpe.com O=IZENPE S.A.
+# Subject: CN=Izenpe.com O=IZENPE S.A.
+# Label: "Izenpe.com"
+# Serial: 917563065490389241595536686991402621
+# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73
+# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19
+# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f
+-----BEGIN CERTIFICATE-----
+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
+MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
+ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD
+VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j
+b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq
+scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO
+xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H
+LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX
+uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD
+yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+
+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q
+rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN
+BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L
+hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB
+QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+
+HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu
+Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg
+QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB
+BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA
+A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb
+laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56
+awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo
+JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw
+LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT
+VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk
+LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb
+UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/
+QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+
+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
+QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A.
+# Subject: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A.
+# Label: "Chambers of Commerce Root - 2008"
+# Serial: 11806822484801597146
+# MD5 Fingerprint: 5e:80:9e:84:5a:0e:65:0b:17:02:f3:55:18:2a:3e:d7
+# SHA1 Fingerprint: 78:6a:74:ac:76:ab:14:7f:9c:6a:30:50:ba:9e:a8:7e:fe:9a:ce:3c
+# SHA256 Fingerprint: 06:3e:4a:fa:c4:91:df:d3:32:f3:08:9b:85:42:e9:46:17:d8:93:d7:fe:94:4e:10:a7:93:7e:e2:9d:96:93:c0
+-----BEGIN CERTIFICATE-----
+MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD
+VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
+IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3
+MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz
+IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz
+MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj
+dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw
+EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp
+MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9
+28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq
+VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q
+DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR
+5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL
+ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a
+Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl
+UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s
++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5
+Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
+ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx
+hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV
+HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1
++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN
+YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t
+L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy
+ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt
+IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV
+HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w
+DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW
+PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF
+5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1
+glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH
+FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2
+pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD
+xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG
+tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq
+jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De
+fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
+OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ
+d0jQ
+-----END CERTIFICATE-----
+
+# Issuer: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A.
+# Subject: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A.
+# Label: "Global Chambersign Root - 2008"
+# Serial: 14541511773111788494
+# MD5 Fingerprint: 9e:80:ff:78:01:0c:2e:c1:36:bd:fe:96:90:6e:08:f3
+# SHA1 Fingerprint: 4a:bd:ee:ec:95:0d:35:9c:89:ae:c7:52:a1:2c:5b:29:f6:d6:aa:0c
+# SHA256 Fingerprint: 13:63:35:43:93:34:a7:69:80:16:a0:d3:24:de:72:28:4e:07:9d:7b:52:20:bb:8f:bd:74:78:16:ee:be:ba:ca
+-----BEGIN CERTIFICATE-----
+MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD
+VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
+IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3
+MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
+aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx
+MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy
+cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG
+A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl
+BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed
+KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7
+G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2
+zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4
+ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG
+HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2
+Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V
+yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e
+beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r
+6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
+wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog
+zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW
+BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr
+ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp
+ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk
+cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt
+YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC
+CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow
+KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI
+hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ
+UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz
+X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x
+fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz
+a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd
+Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd
+SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O
+AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso
+M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge
+v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
+09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
+-----END CERTIFICATE-----
+
+# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
+# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
+# Label: "Go Daddy Root Certificate Authority - G2"
+# Serial: 0
+# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01
+# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b
+# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
+EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
+ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
+NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
+EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
+AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
+E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
+/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
+DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
+GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
+tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
+AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
+WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
+9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
+gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
+2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
+4uJEvlz36hz1
+-----END CERTIFICATE-----
+
+# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Label: "Starfield Root Certificate Authority - G2"
+# Serial: 0
+# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96
+# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e
+# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
+ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
+MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
+aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
+Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
+nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
+HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
+Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
+dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
+HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
+CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
+sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
+4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
+8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
+mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+
+# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Label: "Starfield Services Root Certificate Authority - G2"
+# Serial: 0
+# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2
+# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f
+# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
+ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
+VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
+ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
+dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
+OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
+8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
+Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
+hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
+6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
+AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
+bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
+ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
+qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
+0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
+sSi6
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Commercial O=AffirmTrust
+# Subject: CN=AffirmTrust Commercial O=AffirmTrust
+# Label: "AffirmTrust Commercial"
+# Serial: 8608355977964138876
+# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7
+# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7
+# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP
+Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr
+ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL
+MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1
+yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr
+VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/
+nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG
+XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj
+vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt
+Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
+N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
+nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Networking O=AffirmTrust
+# Subject: CN=AffirmTrust Networking O=AffirmTrust
+# Label: "AffirmTrust Networking"
+# Serial: 8957382827206547757
+# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f
+# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f
+# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y
+YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua
+kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL
+QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp
+6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG
+yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i
+QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO
+tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu
+QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ
+Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
+olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
+x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Premium O=AffirmTrust
+# Subject: CN=AffirmTrust Premium O=AffirmTrust
+# Label: "AffirmTrust Premium"
+# Serial: 7893706540734352110
+# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57
+# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27
+# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
+dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG
+A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U
+cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf
+qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ
+JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ
++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS
+s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5
+HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7
+70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG
+V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S
+qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S
+5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia
+C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX
+OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE
+FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2
+KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B
+8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ
+MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc
+0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ
+u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF
+u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH
+YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8
+GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
+RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
+KeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust
+# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust
+# Label: "AffirmTrust Premium ECC"
+# Serial: 8401224907861490260
+# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d
+# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb
+# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
+cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
+BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
+VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
+0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
+ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
+A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
+aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
+flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority
+# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority
+# Label: "Certum Trusted Network CA"
+# Serial: 279744
+# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78
+# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e
+# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM
+MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D
+ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU
+cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3
+WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg
+Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw
+IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH
+UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM
+TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU
+BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM
+kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x
+AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV
+HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y
+sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL
+I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8
+J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY
+VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Certinomis - Autorité Racine O=Certinomis OU=0002 433998903
+# Subject: CN=Certinomis - Autorité Racine O=Certinomis OU=0002 433998903
+# Label: "Certinomis - Autorité Racine"
+# Serial: 1
+# MD5 Fingerprint: 7f:30:78:8c:03:e3:ca:c9:0a:e2:c9:ea:1e:aa:55:1a
+# SHA1 Fingerprint: 2e:14:da:ec:28:f0:fa:1e:8e:38:9a:4e:ab:eb:26:c0:0a:d3:83:c3
+# SHA256 Fingerprint: fc:bf:e2:88:62:06:f7:2b:27:59:3c:8b:07:02:97:e1:2d:76:9e:d1:0e:d7:93:07:05:a8:09:8e:ff:c1:4d:17
+-----BEGIN CERTIFICATE-----
+MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET
+MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk
+BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4
+Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl
+cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0
+aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY
+F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N
+8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe
+rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K
+/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu
+7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC
+28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6
+lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E
+nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB
+0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09
+5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj
+WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN
+jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ
+KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s
+ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM
+OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q
+619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn
+2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj
+o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v
+nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG
+5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq
+pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb
+dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0
+BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5
+-----END CERTIFICATE-----
+
+# Issuer: CN=Root CA Generalitat Valenciana O=Generalitat Valenciana OU=PKIGVA
+# Subject: CN=Root CA Generalitat Valenciana O=Generalitat Valenciana OU=PKIGVA
+# Label: "Root CA Generalitat Valenciana"
+# Serial: 994436456
+# MD5 Fingerprint: 2c:8c:17:5e:b1:54:ab:93:17:b5:36:5a:db:d1:c6:f2
+# SHA1 Fingerprint: a0:73:e5:c5:bd:43:61:0d:86:4c:21:13:0a:85:58:57:cc:9c:ea:46
+# SHA256 Fingerprint: 8c:4e:df:d0:43:48:f3:22:96:9e:7e:29:a4:cd:4d:ca:00:46:55:06:1c:16:e1:b0:76:42:2e:f3:42:ad:63:0e
+-----BEGIN CERTIFICATE-----
+MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJF
+UzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJ
+R1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcN
+MDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3WjBoMQswCQYDVQQGEwJFUzEfMB0G
+A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScw
+JQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+
+WmmmO3I2F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKj
+SgbwJ/BXufjpTjJ3Cj9BZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGl
+u6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQD0EbtFpKd71ng+CT516nDOeB0/RSrFOy
+A8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXteJajCq+TA81yc477OMUxk
+Hl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMBAAGjggM7
+MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBr
+aS5ndmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIIC
+IwYKKwYBBAG/VQIBADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8A
+cgBpAGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIA
+YQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIAYQBsAGkAdABhAHQAIABWAGEA
+bABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQByAGEAYwBpAPMA
+bgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA
+aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMA
+aQBvAG4AYQBtAGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQA
+ZQAgAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEA
+YwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBuAHQAcgBhACAAZQBuACAAbABhACAA
+ZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAAOgAvAC8AdwB3AHcA
+LgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0dHA6
+Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+y
+eAT8MIGVBgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQsw
+CQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0G
+A1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVu
+Y2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRhTvW1yEICKrNcda3Fbcrn
+lD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdzCkj+IHLt
+b8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg
+9J63NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XF
+ducTZnV+ZfsBn5OHiJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmC
+IoaZM3Fa6hlXPZHNqcCjbgcTpsnt+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
+-----END CERTIFICATE-----
+
+# Issuer: CN=A-Trust-nQual-03 O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH OU=A-Trust-nQual-03
+# Subject: CN=A-Trust-nQual-03 O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH OU=A-Trust-nQual-03
+# Label: "A-Trust-nQual-03"
+# Serial: 93214
+# MD5 Fingerprint: 49:63:ae:27:f4:d5:95:3d:d8:db:24:86:b8:9c:07:53
+# SHA1 Fingerprint: d3:c0:63:f2:19:ed:07:3e:34:ad:5d:75:0b:32:76:29:ff:d5:9a:f2
+# SHA256 Fingerprint: 79:3c:bf:45:59:b9:fd:e3:8a:b2:2d:f1:68:69:f6:98:81:ae:14:c4:b0:13:9a:c7:88:a7:8a:1a:fc:ca:02:fb
+-----BEGIN CERTIFICATE-----
+MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJB
+VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp
+bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5R
+dWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAw
+MFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRy
+dXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0ZW52
+ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMM
+EEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj
+lUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZ
+znF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH
+2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1
+k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs
+2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYD
+VR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
+AQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fG
+KOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdCoLXEjq/+
+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R
+FGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS
+mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmE
+DNuxUCAKGkq6ahq97BvIxYSazQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA
+# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA
+# Label: "TWCA Root Certification Authority"
+# Serial: 1
+# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79
+# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48
+# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES
+MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU
+V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz
+WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO
+LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE
+AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH
+K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX
+RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z
+rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx
+3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq
+hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC
+MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls
+XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D
+lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn
+aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ
+YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
+-----END CERTIFICATE-----
+
+# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2
+# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2
+# Label: "Security Communication RootCA2"
+# Serial: 0
+# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43
+# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74
+# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl
+MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe
+U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX
+DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy
+dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj
+YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV
+OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr
+zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM
+VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ
+hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO
+ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw
+awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs
+OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF
+coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc
+okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8
+t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy
+1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/
+SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
+-----END CERTIFICATE-----
+
+# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority
+# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority
+# Label: "Hellenic Academic and Research Institutions RootCA 2011"
+# Serial: 0
+# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9
+# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d
+# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71
+-----BEGIN CERTIFICATE-----
+MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix
+RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1
+dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p
+YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw
+NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK
+EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl
+cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
+c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz
+dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ
+fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns
+bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD
+75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP
+FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV
+HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp
+5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu
+b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA
+A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p
+6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
+TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7
+dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys
+Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI
+l7WdmplNsDz4SgCbZN2fOUvRJ9e4
+-----END CERTIFICATE-----
+
+# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967
+# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967
+# Label: "Actalis Authentication Root CA"
+# Serial: 6271844772424770508
+# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6
+# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac
+# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66
+-----BEGIN CERTIFICATE-----
+MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
+BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
+MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
+IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC
+SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1
+ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv
+UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX
+4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9
+KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/
+gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb
+rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ
+51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F
+be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe
+KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F
+v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn
+fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7
+jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz
+ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
+ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL
+e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70
+jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz
+WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V
+SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j
+pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX
+X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok
+fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R
+K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU
+ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
+LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
+LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
+-----END CERTIFICATE-----
+
+# Issuer: O=Trustis Limited OU=Trustis FPS Root CA
+# Subject: O=Trustis Limited OU=Trustis FPS Root CA
+# Label: "Trustis FPS Root CA"
+# Serial: 36053640375399034304724988975563710553
+# MD5 Fingerprint: 30:c9:e7:1e:6b:e6:14:eb:65:b2:16:69:20:31:67:4d
+# SHA1 Fingerprint: 3b:c0:38:0b:33:c3:f6:a6:0c:86:15:22:93:d9:df:f5:4b:81:c0:04
+# SHA256 Fingerprint: c1:b4:82:99:ab:a5:20:8f:e9:63:0a:ce:55:ca:68:a0:3e:da:5a:51:9c:88:02:a0:d3:a6:73:be:8f:8e:55:7d
+-----BEGIN CERTIFICATE-----
+MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF
+MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL
+ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx
+MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc
+MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+
+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH
+iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj
+vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA
+0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB
+OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/
+BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E
+FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01
+GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW
+zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4
+1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE
+f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F
+jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN
+ZetX2fNXlrtIzYE=
+-----END CERTIFICATE-----
+
+# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Label: "StartCom Certification Authority"
+# Serial: 45
+# MD5 Fingerprint: c9:3b:0d:84:41:fc:a4:76:79:23:08:57:de:10:19:16
+# SHA1 Fingerprint: a3:f1:33:3f:e2:42:bf:cf:c5:d1:4e:8f:39:42:98:40:68:10:d1:a0
+# SHA256 Fingerprint: e1:78:90:ee:09:a3:fb:f4:f4:8b:9c:41:4a:17:d6:37:b7:a5:06:47:e9:bc:75:23:22:72:7f:cc:17:42:a9:11
+-----BEGIN CERTIFICATE-----
+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul
+F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC
+ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w
+ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk
+aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0
+YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg
+c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93
+d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG
+CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF
+wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS
+Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst
+0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc
+pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl
+CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF
+P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK
+1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm
+KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
+8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
+fyWl8kgAwKQB2j8=
+-----END CERTIFICATE-----
+
+# Issuer: CN=StartCom Certification Authority G2 O=StartCom Ltd.
+# Subject: CN=StartCom Certification Authority G2 O=StartCom Ltd.
+# Label: "StartCom Certification Authority G2"
+# Serial: 59
+# MD5 Fingerprint: 78:4b:fb:9e:64:82:0a:d3:b8:4c:62:f3:64:f2:90:64
+# SHA1 Fingerprint: 31:f1:fd:68:22:63:20:ee:c6:3b:3f:9d:ea:4a:3e:53:7c:7c:39:17
+# SHA256 Fingerprint: c7:ba:65:67:de:93:a7:98:ae:1f:aa:79:1e:71:2d:37:8f:ae:1f:93:c4:39:7f:ea:44:1b:b7:cb:e6:fd:59:95
+-----BEGIN CERTIFICATE-----
+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1
+OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG
+A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ
+JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD
+vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo
+D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/
+Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW
+RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK
+HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN
+nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM
+0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i
+UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9
+Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg
+TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL
+BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX
+UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl
+6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK
+9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ
+HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI
+wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY
+XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l
+IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo
+hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr
+so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI
+-----END CERTIFICATE-----
+
+# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
+# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
+# Label: "Buypass Class 2 Root CA"
+# Serial: 2
+# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29
+# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99
+# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
+Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow
+TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw
+HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
+BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr
+6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV
+L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91
+1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx
+MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ
+QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB
+arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr
+Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi
+FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS
+P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN
+9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP
+AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz
+uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h
+9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
+A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t
+OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo
++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7
+KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2
+DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us
+H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ
+I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7
+5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h
+3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz
+Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327
+# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327
+# Label: "Buypass Class 3 Root CA"
+# Serial: 2
+# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec
+# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57
+# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
+Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow
+TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw
+HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
+BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y
+ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E
+N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9
+tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX
+0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c
+/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X
+KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY
+zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS
+O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D
+34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP
+K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3
+AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv
+Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj
+QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
+cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS
+IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2
+HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa
+O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv
+033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u
+dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE
+kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41
+3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD
+u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq
+4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc=
+-----END CERTIFICATE-----
+
+# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center
+# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center
+# Label: "T-TeleSec GlobalRoot Class 3"
+# Serial: 1
+# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef
+# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1
+# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
+KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
+BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
+YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1
+OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy
+aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50
+ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN
+8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/
+RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4
+hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5
+ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM
+EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1
+A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy
+WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ
+1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30
+6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT
+91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p
+TpPDpFQUWw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus
+# Subject: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus
+# Label: "EE Certification Centre Root CA"
+# Serial: 112324828676200291871926431888494945866
+# MD5 Fingerprint: 43:5e:88:d4:7d:1a:4a:7e:fd:84:2e:52:eb:01:d4:6f
+# SHA1 Fingerprint: c9:a8:b9:e7:55:80:5e:58:e3:53:77:a7:25:eb:af:c3:7b:27:cc:d7
+# SHA256 Fingerprint: 3e:84:ba:43:42:90:85:16:e7:75:73:c0:99:2f:09:79:ca:08:4e:46:85:68:1f:f1:95:cc:ba:8a:22:9b:8a:76
+-----BEGIN CERTIFICATE-----
+MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
+CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy
+MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl
+ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS
+b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy
+euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO
+bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw
+WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d
+MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE
+1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/
+zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB
+BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF
+BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV
+v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG
+E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
+uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW
+iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v
+GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0=
+-----END CERTIFICATE-----
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..9fc9faf
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,604 @@
+AC_INIT([tlsdate],[0.0.13],[jacob at appelbaum.net])
+AC_CONFIG_AUX_DIR([config])
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_CANONICAL_TARGET
+AC_ARG_PROGRAM
+AC_USE_SYSTEM_EXTENSIONS
+
+AM_INIT_AUTOMAKE([-Wall -Werror -Wno-portability subdir-objects foreign tar-ustar])
+
+AC_PREREQ([2.63])
+
+AC_CONFIG_HEADERS([config.h:config.in])dnl Keep filename to 8.3 for MS-DOS.
+
+PKG_PROG_PKG_CONFIG
+LT_PREREQ([2.2])
+LT_INIT
+LT_LANG([C])
+gl_VISIBILITY
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+CONFIG_EXTRA
+AX_PLATFORM
+
+dnl Here we should build a small program to fetch the build system time in a portable
+dnl manner. We have no Win32 users, we can fix this if we ever find one that
+dnl cares.
+dnl
+dnl In Debian GNU/Linux and other Debian GNU/* systems, we wish to make this a
+dnl deterministic build process. There is only one part of the build process that
+dnl is entropic and that is this COMPILE_DATE value. We want to check to see if
+dnl COMPILE_DATE is defined by the debian/rules file and if it is - we want to use
+dnl the value provided by the environment. If it isn't we'll use one that we
+dnl generate here.
+dnl
+echo "checking for \$COMPILE_DATE in the environment..."
+if test "${COMPILE_DATE+set}" = set; then
+ echo "...we've found \$COMPILE_DATE in the environment."
+ echo "...\$COMPILE_DATE is set to: $COMPILE_DATE"
+else
+ echo "...no \$COMPILE_DATE found in our build environment. Generating now..."
+ COMPILE_DATE=`date +%s`
+ echo "...\$COMPILE_DATE is set to: $COMPILE_DATE"
+fi
+
+AC_SUBST([COMPILE_DATE])
+AC_DEFINE_UNQUOTED([RECENT_COMPILE_DATE],
+ [${COMPILE_DATE}L],
+ [Time in seconds since the Disco epoch at build time])
+
+dnl Build up the directory we will use to install certs
+TLSDATE_CA_ROOTS="${sysconfdir}/$PACKAGE_NAME/ca-roots"
+AC_SUBST([TLSDATE_CA_ROOTS])
+
+dnl Place we install our config file
+TLSDATE_CONF_DIR="${sysconfdir}/$PACKAGE_NAME/"
+AC_SUBST([TLSDATE_CONF_DIR])
+
+dnl HTTPS User-agent
+AC_ARG_WITH([https-user-agent],
+ [AS_HELP_STRING([--with-https-user-agent=AGENT],
+ [a User-Agent value to send when running in HTTPS mode])],
+ [],
+ [with_https_user_agent="TLSDate/$VERSION"])
+AC_DEFINE_UNQUOTED([HTTPS_USER_AGENT],
+ ["${with_https_user_agent}"],
+ [User-Agent value to send when running as an HTTPS client])
+
+dnl check for PolarSSL
+OPT_POLARSSL=yes
+
+AC_MSG_CHECKING([PolarSSL])
+AC_ARG_WITH([polarssl],
+ [AS_HELP_STRING([--with-polarssl=DIR],
+ [where to look for PolarSSL, DIR points to the installation root])])
+
+AS_CASE([$with_polarssl],
+ [""|yes|no], [POLARSSL_DIR=""],
+ [*], [POLARSSL_DIR=$with_polarssl])
+OPT_POLARSSL=$with_polarssl
+
+SSL_FLAGS=""
+SSL_LDFLAGS=""
+SSL_LIBS="-lssl -lcrypto"
+
+AS_IF([test "x${OPT_POLARSSL}" != "xno"], [
+ AS_IF([test -z "${POLARSSL_DIR}"], [
+ dnl check for lib first without setting any new path
+ AC_CHECK_LIB(polarssl, ssl_init,
+ dnl libpolarssl found, set the variable
+ [
+ AC_DEFINE(USE_POLARSSL, 1, [if PolarSSL is enabled])
+ AC_SUBST(USE_POLARSSL, [1])
+ POLARSSL_ENABLED=1
+ USE_POLARSSL="yes"
+ ])
+ ])
+
+ addld=""
+ addlib=""
+ addcflags=""
+ polarssllib=""
+
+ AS_IF([test "x${USE_POLARSSL}" != "xyes"], [
+ dnl add the path and test again
+ addld=-L${POLARSSL_DIR}/lib$libsuff
+ addcflags=-I${POLARSSL_DIR}/include
+ polarssllib=${POLARSSL_DIR}/lib$libsuff
+
+ LDFLAGS="$LDFLAGS $addld"
+ AS_IF([test "$addcflags" != "-I/usr/include"], [
+ AX_APPEND_COMPILE_FLAGS(["$addcflags"])
+ CPPFLAGS="$CPPFLAGS $addcflags"
+ ])
+
+ AC_CHECK_LIB(polarssl, ssl_init,
+ [
+ AC_DEFINE(USE_POLARSSL, 1, [if PolarSSL is enabled])
+ AC_SUBST(USE_POLARSSL, [1])
+ POLARSSL_ENABLED=1
+ USE_POLARSSL="yes"
+ SSL_CFLAGS=$addcflags
+ SSL_LDFLAGS=$addld
+ ])
+ ])
+
+ AS_IF([test "x${USE_POLARSSL}" = "xyes"], [
+ AC_MSG_NOTICE([detected PolarSSL])
+ SSL_LIBS="-lpolarssl"
+
+ AS_IF([test -n "$polarssllib"], [
+ dnl when shared libs were found in a path that the run-time
+ dnl linker doesn't search through, we need to add it to
+ dnl LD_LIBRARY_PATH to prevent further configure tests to fail
+ dnl due to this
+ AS_IF([test "x$cross_compiling" != "xyes"], [
+ LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$polarssllib"
+ export LD_LIBRARY_PATH
+ AC_MSG_NOTICE([Added $polarssllib to LD_LIBRARY_PATH])
+ ])
+ ])
+ ])
+])
+AC_SUBST(SSL_CFLAGS)
+AC_SUBST(SSL_LDFLAGS)
+AC_SUBST(SSL_LIBS)
+AM_CONDITIONAL(POLARSSL, test "x${USE_POLARSSL}" = "xyes")
+
+dnl Required headers
+AS_IF([test "x${USE_POLARSSL}" != "xyes"], [
+ dnl First check to see if openssl is installed
+ AC_CHECK_HEADERS([openssl/ssl.h], ,[AC_MSG_ERROR([OpenSSL is not installed, openssl/sslh is missing])])
+ AC_CHECK_HEADERS([openssl/bio.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+ AC_CHECK_HEADERS([openssl/err.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+ AC_CHECK_HEADERS([openssl/evp.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+])
+
+AC_CHECK_HEADERS([arpa/inet.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([getopt.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([grp.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([pwd.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([stdint.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([stdio.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([stdlib.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([sys/mman.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([sys/socket.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([sys/time.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([sys/types.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([sys/wait.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([time.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+AC_CHECK_HEADERS([unistd.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+
+AC_CHECK_HEADERS([linux/rtc.h])
+AC_CHECK_TYPES([struct rtc_time], [], [], [
+#ifdef HAVE_LINUX_RTC_H
+#include <linux/rtc.h>
+#endif
+])
+
+AC_CHECK_FUNCS([strchrnul])
+AM_CONDITIONAL(HAVE_STRCHRNUL, [test "x${ac_cv_func_strchrnul}" = xyes])
+
+AC_CHECK_FUNCS([strnlen])
+AM_CONDITIONAL(HAVE_STRNLEN, [test "x${ac_cv_func_strnlen}" = xyes])
+
+AC_CHECK_FUNCS_ONCE(m4_flatten([
+ gettimeofday
+ prctl
+ preadv
+ pwritev
+ setresuid
+]))
+
+AC_CHECK_FUNCS([fmemopen funopen])
+AM_CONDITIONAL(HAVE_FMEMOPEN, [test "x${ac_cv_func_fmemopen}" = xyes])
+AM_CONDITIONAL(HAVE_FUNOPEN, [test "x${ac_cv_func_funopen}" = xyes])
+
+case "$host" in
+ *-darwin*)
+ dnl This is for Mac OS X (10.8.2)
+ AC_CHECK_HEADERS([mach/clock.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+ AC_CHECK_HEADERS([mach/mach.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nogroup@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nobody"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *-freebsd*)
+ dnl This is for FreeBSD
+ dnl clock_gettime is either part of libc or unavailable.
+ AC_CHECK_FUNC([clock_gettime], ,
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])
+ dnl If the autoconf goo picks up a compiler that runs in pre-POSIX mode,
+ dnl the fmemopen prototype is hidden causing the unit tests to segfault.
+ dnl This can happen if gcc is a symlink to gcc46 and is preferred to clang.
+ AC_CHECK_FUNC([fmemopen], ,
+ [AC_MSG_WARN([Missing fmemopen, unit tests are likely to segfault. Try CC=clang.])])
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nobody@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nobody"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *kfreebsd*-gnu*)
+ dnl This is for Debian GNU/kFreeBSD
+ dnl clock_gettime is either part of libc or unavailable.
+ dnl Check for clock_gettime. Some systems put it into -lc, while
+ dnl others use -lrt. Try the first and fallback to the latter.
+ RT_LIB=
+ AC_CHECK_FUNC([clock_gettime], [:],
+ [AC_CHECK_LIB([rt], [clock_gettime], [RT_LIB="-lrt"],
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])])
+ AC_SUBST(RT_LIB)
+ dnl If the autoconf goo picks up a compiler that runs in pre-POSIX mode,
+ dnl the fmemopen prototype is hidden causing the unit tests to segfault.
+ dnl This can happen if gcc is a symlink to gcc46 and is preferred to clang.
+ AC_CHECK_FUNC([fmemopen], ,
+ [AC_MSG_ERROR([Missing fmemopen, unit tests are likely to segfault. Try CC=clang.])])
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nobody@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nobody"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *-netbsd*)
+ dnl This is for NetBSD
+ dnl clock_gettime is either part of libc or unavailable.
+ AC_CHECK_FUNC([clock_gettime], ,
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])
+ if test "x${ac_cv_func_fmemopen}" != xyes; then
+ if test "x${ac_cv_func_funopen}" != xyes; then
+ AC_MSG_ERROR([We need fmemopen or funopen for unit tests.])
+ fi
+ fi
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nobody@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nobody"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *-openbsd*)
+ dnl This is for OpenBSD
+ dnl clock_gettime is either part of libc or unavailable.
+ AC_CHECK_FUNC([clock_gettime], ,
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])
+ dnl If the autoconf goo picks up a compiler that runs in pre-POSIX mode,
+ dnl the fmemopen prototype is hidden causing the unit tests to segfault.
+ dnl This can happen if gcc is a symlink to gcc46 and is preferred to clang.
+ AC_CHECK_FUNC([fmemopen], ,
+ [AC_MSG_WARN([Missing fmemopen, unit tests are likely to segfault. Try CC=clang.])])
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nobody@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nobody"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *dragonfly*)
+ dnl This is for DragonFly BSD
+ dnl clock_gettime is either part of libc or unavailable.
+ AC_CHECK_FUNC([clock_gettime], ,
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])
+ dnl If the autoconf goo picks up a compiler that runs in pre-POSIX mode,
+ dnl the fmemopen prototype is hidden causing the unit tests to segfault.
+ dnl This can happen if gcc is a symlink to gcc46 and is preferred to clang.
+ AC_CHECK_FUNC([fmemopen], ,
+ [AC_MSG_WARN([Missing fmemopen, unit tests are likely to segfault. Try CC=clang.])])
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nobody@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nobody"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *-bsd*)
+ dnl This is a generic catch for BSD variants
+ dnl This likely needs to be tuned to catch all
+ dnl clock_gettime is either part of libc or unavailable.
+ AC_CHECK_FUNC([clock_gettime], ,
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])
+ dnl If the autoconf goo picks up a compiler that runs in pre-POSIX mode,
+ dnl the fmemopen prototype is hidden causing the unit tests to segfault.
+ dnl This can happen if gcc is a symlink to gcc46 and is preferred to clang.
+ AC_CHECK_FUNC([fmemopen], ,
+ [AC_MSG_ERROR([Missing fmemopen, unit tests are likely to segfault. Try CC=clang.])])
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nobody@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nobody"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *-linux*)
+ dnl This is for GNU/Linux
+ dnl Check for clock_gettime. Some systems put it into -lc, while
+ dnl others use -lrt. Try the first and fallback to the latter.
+ RT_LIB=
+ AC_CHECK_FUNC([clock_gettime], [:],
+ [AC_CHECK_LIB([rt], [clock_gettime], [RT_LIB="-lrt"],
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])])
+ AC_SUBST(RT_LIB)
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nogroup@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nogroup"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ case "$host" in
+ *-linux-androideabi)
+ dnl This is for Android NDK as it is a special case of linux
+ AC_DEFINE(HAVE_ANDROID,1, [Defined if we are to build for an Android system])
+ AC_SUBST(HAVE_ANDROID, [1])
+ HAVE_ANDROID="yes"
+ ;;
+ esac
+ ;;
+ *-gnu0.*)
+ dnl This is a generic catch for GNU/Hurd variants
+ dnl Check for clock_gettime. Some systems put it into -lc, while
+ dnl others use -lrt. Try the first and fallback to the latter.
+ RT_LIB=
+ AC_CHECK_FUNC([clock_gettime], [:],
+ [AC_CHECK_LIB([rt], [clock_gettime], [RT_LIB="-lrt"],
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])])
+ AC_SUBST(RT_LIB)
+ dnl If the autoconf goo picks up a compiler that runs in pre-POSIX mode,
+ dnl the fmemopen prototype is hidden causing the unit tests to segfault.
+ dnl This can happen if gcc is a symlink to gcc46 and is preferred to clang.
+ AC_CHECK_FUNC([fmemopen], ,
+ [AC_MSG_ERROR([Missing fmemopen, unit tests are likely to segfault. Try CC=clang.])])
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nobody@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nogroup"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *-cygwin*)
+ dnl This is for Cygwin
+ dnl Check for clock_gettime. Some systems put it into -lc, while
+ dnl others use -lrt. Try the first and fallback to the latter.
+ RT_LIB=
+ AC_CHECK_FUNC([clock_gettime], [:],
+ [AC_CHECK_LIB([rt], [clock_gettime], [RT_LIB="-lrt"],
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])])
+ AC_SUBST(RT_LIB)
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nogroup@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nogroup"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *-mingw32*)
+ dnl This is for MINGW32_NT
+ dnl Check for clock_gettime. Some systems put it into -lc, while
+ dnl others use -lrt. Try the first and fallback to the latter.
+ RT_LIB=
+ AC_CHECK_FUNC([clock_gettime], [:],
+ [AC_CHECK_LIB([rt], [clock_gettime], [RT_LIB="-lrt"],
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])])
+ AC_SUBST(RT_LIB)
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nogroup@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nogroup"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+ *-beos*|*-haiku*)
+ dnl This is for BeOS and Haiku; we probably only support Haiku with gcc4
+ dnl Check for clock_gettime. Some systems put it into -lc, while
+ dnl others use -lrt. Try the first and fallback to the latter.
+ dnl on Haiku we require the bsd library for strsep
+ RT_LIB=
+ AC_CHECK_FUNC([clock_gettime], [:],
+ [AC_CHECK_LIB([rt], [clock_gettime], [RT_LIB="-lrt"],
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])])
+ AC_SUBST(RT_LIB)
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nogroup@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nogroup"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ LDFLAGS="$LDFLAGS -lbsd"
+ CC="/boot/develop/abi/x86/gcc4/tools/gcc-4.6.3-haiku-121101/bin/gcc"
+ ;;
+ *)
+ AC_ARG_WITH([unpriv-group],
+ [AS_HELP_STRING([--with-unpriv-group=<group>],
+ [Group to drop privs to @<:@default: nogroup@:>@])])
+ AS_CASE([$with_unpriv_group],
+ [""|yes|no], [UNPRIV_GROUP="nogroup"],
+ [*], [UNPRIV_GROUP=$with_unpriv_group])
+ AC_DEFINE_UNQUOTED([UNPRIV_GROUP], ["${UNPRIV_GROUP}"], [Unprivileged group])
+ ;;
+esac
+
+dnl Android conditional
+AM_CONDITIONAL(HAVE_ANDROID, test "x${HAVE_ANDROID}" = "xyes")
+
+AC_MSG_CHECKING([user/group to drop privs to])
+
+AC_ARG_WITH([unpriv-user],
+ [AS_HELP_STRING([--with-unpriv-user=<user>],
+ [User to drop privs to @<:@default: nobody@:>@])])
+AS_CASE([$with_unpriv_user],
+ [""|yes|no], [UNPRIV_USER="nobody"],
+ [*], [UNPRIV_USER=$with_unpriv_user])
+AC_DEFINE_UNQUOTED([UNPRIV_USER], ["${UNPRIV_USER}"], [Unprivileged user])
+AC_SUBST([UNPRIV_USER])
+
+AC_MSG_RESULT(${UNPRIV_USER}:${UNPRIV_GROUP})
+
+AC_MSG_CHECKING([group to allow DBus calls from])
+AC_ARG_WITH([dbus-client-group],
+ [AS_HELP_STRING([--with-dbus-client-group=<group>],
+ [Allow dbus method calls from group @<:@default: root@:>@])])
+AS_CASE([$with_dbus_client_group],
+ [""|yes|no], [DBUS_CLIENT_GROUP="root"],
+ [*], [DBUS_CLIENT_GROUP=$with_dbus_client_group])
+AC_DEFINE_UNQUOTED([DBUS_CLIENT_GROUP], ["${DBUS_CLIENT_GROUP}"], [DBus client group])
+AC_MSG_RESULT(${DBUS_CLIENT_GROUP})
+AC_SUBST([DBUS_CLIENT_GROUP])
+
+dnl Check for clock_gettime. Some systems put it into -lc, while
+dnl others use -lrt. Try the first and fallback to the latter.
+RT_LIB=
+AC_CHECK_FUNC([clock_gettime], [:],
+ [AC_CHECK_LIB([rt], [clock_gettime], [RT_LIB="-lrt"],
+ [AC_MSG_ERROR([Your system lacks clock_gettime])])])
+AC_SUBST(RT_LIB)
+
+PKG_CHECK_MODULES([LIBEVENT], [libevent >= 2.0])
+
+have_dbus=false
+AC_ARG_ENABLE([dbus],
+ [AS_HELP_STRING([--disable-dbus],
+ [Disable automatically dbus support])])
+AS_IF([test "x$enable_dbus" = xyes], [
+ PKG_CHECK_MODULES([DBUS], [dbus-1], [
+ have_dbus=true
+ AC_DEFINE([HAVE_DBUS], [1], [dbus enabled])
+ ], [
+ AS_IF([test "x$enable_dbus" = xyes],
+ [AC_MSG_ERROR([dbus requested but not found])])
+ ])
+ ])
+AM_CONDITIONAL([HAVE_DBUS], ${have_dbus})
+
+AC_SUBST(DBUS_CFLAGS)
+AC_SUBST(DBUS_LIBS)
+AC_SUBST(LIBEVENT_CFLAGS)
+AC_SUBST(LIBEVENT_LIBS)
+
+have_seccomp_filter=false
+AC_ARG_ENABLE([seccomp_filter],
+ [AS_HELP_STRING([--enable-seccomp-filter],
+ [Require seccomp filter])])
+
+AC_MSG_CHECKING([kernel for seccomp_filter support])
+AS_IF([test "x$enable_seccomp_filter" = xyes], [
+ dnl Force seccomp filter use
+ have_seccomp_filter=true
+ AC_MSG_RESULT([forced])
+ ], [
+ AS_IF([test "x$enable_seccomp_filter" = xno], [
+ have_seccomp_filter=no
+ AC_MSG_RESULT([disabled])
+ ], [
+ dnl Detect seccomp filter support.
+ AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+ #include <errno.h>
+ #include <linux/audit.h>
+ #include <linux/filter.h>
+ #include <stdlib.h>
+ #include <sys/prctl.h>
+ #include "src/seccomp-compat.h"
+ ]],
+ [[ errno = 0;
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
+ exit(1);
+ prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0);
+ exit(errno == EFAULT ? 0 : 1); ]])],
+ [ AC_MSG_RESULT([yes])
+ have_seccomp_filter=true
+ ], [
+ AC_MSG_RESULT([no])
+ ],
+ [ AC_MSG_RESULT([cross-compiling, assuming yes])
+ have_seccomp_filter=true
+ ]
+ )
+])])
+
+AS_IF([${have_seccomp_filter}], [
+ AC_DEFINE([HAVE_SECCOMP_FILTER], [1], [Enable seccomp filter])
+ ])
+AM_CONDITIONAL([HAVE_SECCOMP_FILTER], ${have_seccomp_filter})
+
+
+
+have_seccomp_debug=false
+AC_ARG_ENABLE([seccomp_debugging],
+ [AS_HELP_STRING([--enable-seccomp-debugging],
+ [Enable seccomp filter debugging])])
+AS_IF([test "x$enable_seccomp_debugging" = xyes], [
+ AC_DEFINE([SECCOMP_FILTER_DEBUG], [1], [Enable seccomp filter debugging])
+ have_seccomp_debug=true
+ ])
+AM_CONDITIONAL([SECCOMP_FILTER_DEBUG], ${have_seccomp_debug})
+
+
+AC_MSG_CHECKING([for CrOS-specific platform wake event support])
+AC_ARG_ENABLE([cros],
+ [AS_HELP_STRING([--disable-cros],
+ [Disable CrOS platform support])])
+
+AS_IF([test "x$enable_cros" = xyes -a "x$enable_dbus" != xyes ], [
+ AC_MSG_ERROR([--enable-dbus is required for --enable-cros])
+ ])
+
+have_cros=false
+AS_IF([test "x$enable_cros" = xyes], [
+ have_cros=true
+ AC_DEFINE([HAVE_CROS], [1], [Enable CrOS support])
+ AC_MSG_RESULT([yes])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+AM_CONDITIONAL([HAVE_CROS], ${have_cros})
+
+dnl Debug and hardening flags all in one shot
+dnl Always do this at the end, otherwise you end up filtering system/other libraries
+AC_ARG_ENABLE([hardened-checks],
+ [AS_HELP_STRING([--disable-hardened-checks],
+ [Disable automatically enabling hardened toolchain options])])
+AC_DEFUN([LOCAL_CHECK_FLAGS],[
+ AC_REQUIRE([AX_CHECK_LINK_FLAG])
+ AC_REQUIRE([AX_APPEND_COMPILE_FLAGS])
+ AC_LANG_PUSH([C])
+ AS_IF([test "x$enable_hardened_checks" != xno], [
+ AX_APPEND_COMPILE_FLAGS([-g -O1])
+ ], [
+ AC_MSG_WARN([using hardened flags is HIGHLY RECOMMENDED and disabling them is a BAD IDEA])
+ ])
+ AX_APPEND_COMPILE_FLAGS([-Wall -fno-strict-aliasing])
+ AS_IF([test "x$enable_hardened_checks" != xno], [
+ AX_APPEND_COMPILE_FLAGS([-D_FORTIFY_SOURCE=2 -fstack-protector-all])
+ AX_APPEND_COMPILE_FLAGS([-fwrapv -fPIE -Wstack-protector])
+ AX_APPEND_COMPILE_FLAGS([--param=ssp-buffer-size=1])
+ AX_CHECK_LINK_FLAG([-z relro -z now])
+ AX_CHECK_LINK_FLAG([-pie])
+ ])
+ AC_LANG_POP
+ ])
+LOCAL_CHECK_FLAGS
+
+AC_ARG_ENABLE([code-coverage-checks],
+ [AS_HELP_STRING([--enable-code-coverage-checks],
+ [Enable gcov/lcov compile time options])],
+ [AX_APPEND_COMPILE_FLAGS([-ftest-coverage -fprofile-arcs])])
+
+AC_CONFIG_FILES([dbus/org.torproject.tlsdate.conf])
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/dbus/org.torproject.tlsdate.conf.in b/dbus/org.torproject.tlsdate.conf.in
new file mode 100644
index 0000000..80c83c1
--- /dev/null
+++ b/dbus/org.torproject.tlsdate.conf.in
@@ -0,0 +1,31 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- Only certain user can own the tlsdated service -->
+ <policy user="@UNPRIV_USER@">
+ <allow own="org.torproject.tlsdate"/>
+ </policy>
+
+ <!-- Allow anyone in the given group to invoke methods -->
+ <policy group="@DBUS_CLIENT_GROUP@">
+ <allow send_destination="org.torproject.tlsdate"
+ send_interface="org.torproject.tlsdate"
+ send_member="LastSyncInfo"/>
+ <allow send_destination="org.torproject.tlsdate"
+ send_interface="org.torproject.tlsdate"
+ send_member="SetTime"/>
+ <allow send_destination="org.torproject.tlsdate"
+ send_interface="org.torproject.tlsdate"
+ send_member="CanSetTime"/>
+ </policy>
+
+ <!-- Disallow anyone to invoke methods on tlsdated interface -->
+ <policy context="default">
+ <deny send_interface="org.torproject.tlsdate" />
+ <allow send_destination="org.torproject.tlsdate"
+ send_interface="org.torproject.tlsdate"
+ send_member="LastSyncInfo"/>
+ </policy>
+</busconfig>
diff --git a/dbus/org.torproject.tlsdate.service b/dbus/org.torproject.tlsdate.service
new file mode 100644
index 0000000..36ee56d
--- /dev/null
+++ b/dbus/org.torproject.tlsdate.service
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.torproject.tlsdate
+Exec=/usr/bin/tlsdated
diff --git a/dbus/org.torproject.tlsdate.xml b/dbus/org.torproject.tlsdate.xml
new file mode 100644
index 0000000..2023494
--- /dev/null
+++ b/dbus/org.torproject.tlsdate.xml
@@ -0,0 +1,42 @@
+<!DOCTYPE node PUBLIC
+"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+
+ <interface name="org.torproject.tlsdate">
+ <method name="SetTime">
+ <arg name="time" direction="in" type="x">
+ <doc:doc><doc:summary>The requested time to set the system clock to. It may be tested
+ with:
+ dbus-send --print-reply --system --dest=org.torproject.tlsdate --type=method_call \
+ /org/torproject/tlsdate org.torproject.tlsdate.SetTime int64:12345678
+ </doc:summary></doc:doc>
+ </arg>
+ <arg name="code" direction="out" type="u">
+ <doc:doc><doc:summary>Returns success or failure via an enum:
+ OK:0, Bad value:1, Not allowed:2, Bad call format:3
+ </doc:summary></doc:doc>
+ </arg>
+ </method>
+ <method name="CanSetTime">
+ <arg name="code" direction="out" type="b">
+ <doc:doc><doc:summary>Returns TRUE is SetTime is allowed.
+ </doc:summary></doc:doc>
+ </arg>
+ </method>
+ <method name="LastSyncInfo">
+ <arg name="network_synchronized" direction="out" type="b">
+ <doc:doc><doc:summary>Whether the time is rooted in a network synchronization source since
+ fallback to "system-clock" happens at steady state intervals.
+ </doc:summary></doc:doc>
+ </arg>
+ <arg name="source" direction="out" type="s">
+ <doc:doc><doc:summary>Name of the last source</doc:summary></doc:doc>
+ </arg>
+ <arg name="time" direction="out" type="x">
+ <doc:doc><doc:summary>Last sync time</doc:summary></doc:doc>
+ </arg>
+ </method>
+
+ </interface>
+</node>
diff --git a/etc/tlsdated.conf b/etc/tlsdated.conf
new file mode 100644
index 0000000..ca42029
--- /dev/null
+++ b/etc/tlsdated.conf
@@ -0,0 +1,24 @@
+# tlsdated example config file
+# for boolean options, "yes" enables them, any other value disables them.
+# see tlsdated.conf(5) for details about the options
+
+base-path /var/cache/tlsdated
+dry-run no
+jitter 0
+max-tries 10
+min-steady-state-interval 86400
+should-load-disk yes
+should-netlink yes
+should-save-disk yes
+should-sync-hwclock yes
+steady-state-interval 86400
+subprocess-timeout 30
+verbose no
+wait-between-tries 10
+
+# Host configuration.
+source
+ host google.com
+ port 443
+ proxy none
+end
diff --git a/events.dot b/events.dot
new file mode 100644
index 0000000..658240b
--- /dev/null
+++ b/events.dot
@@ -0,0 +1,58 @@
+/* This DOT file represents the logical interaction between
+ * the events in the system and the "state" of tlsdated.
+ */
+digraph tlsdated {
+ graph[compound=true];
+
+ node[style=filled,color=lightblue];
+
+ subgraph cluster_states {
+ state_label[shape=box,style=dashed,label="States"];
+ sleep -> wake;
+ wake -> sync;
+ sync -> save;
+ save -> sleep;
+ wake -> terminate;
+ sync -> terminate;
+ save -> terminate;
+ }
+
+ subgraph cluster_wake {
+ color=purple;
+ style=filled;
+ wake_label[shape=box,style=dashed,label="Wake Events"];
+ periodic_local_clock_check -> wake;
+ periodic_network_sync -> wake;
+ random_sigterm -> wake;
+ random_route_change -> wake;
+ }
+
+ subgraph cluster_dbus {
+ dbus_label[shape=box,style=dashed,label="DBus Events"];
+ dbus-> cros_shill_manager_change -> wake;
+ dbus-> cros_shill_service_change -> wake;
+ dbus -> cros_proxy_resolved -> {proxy_ok, proxy_failed};
+ dbus -> cros_user_set_time -> save;
+ cros_user_set_time -> sync [style=dotted];
+ get_proxy -> cros_resolve_proxy -> dbus;
+ announce -> dbus;
+ }
+
+ subgraph cluster_sync {
+ sync_label[shape=box,style=dashed,label="Network Sync"];
+ sync -> get_proxy -> {proxy_ok, proxy_failed, proxy_timed_out} -> tlsdate;
+ tlsdate -> tlsdate_ok -> save;
+ tlsdate -> tlsdate_fail;
+ tlsdate_fail -> tlsdate [label="retry",style=dotted];
+ tlsdate_fail -> terminate;
+ };
+
+ subgraph cluster_save {
+ save_label[shape=box,style=dashed,label="Save to the system"];
+ save -> { synchronize_rtc, synchronize_kernel, synchronize_disk } -> { save_ok, save_fail, save_bad_time };
+ save_ok -> announce -> sleep;
+ save_fail -> terminate;
+ save_bad_time -> sleep;
+ }
+}
+
diff --git a/init/tlsdated-cros.conf b/init/tlsdated-cros.conf
new file mode 100644
index 0000000..f5b46a4
--- /dev/null
+++ b/init/tlsdated-cros.conf
@@ -0,0 +1,22 @@
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description "Run the tlsdate daemon to set the system time"
+author "chromium-os-dev@chromium.org"
+
+start on started system-services
+stop on stopping system-services
+respawn
+
+script
+ GOOGLE_CERTS=/usr/share/chromeos-ca-certificates
+ mkdir -m 755 -p /var/cache/tlsdated
+ # Make sure the timestamp file has the proper permissions.
+ chmod 0644 /var/cache/tlsdated/timestamp || true
+ # When it runs tlsdate, tlsdated stitches together an argument vector for it
+ # as follows: it begins with everything supplied to it after the --, then
+ # appends -H $host -p $port, and maybe -x $proxy if it has a proxy to use.
+ exec tlsdated -v -- /usr/bin/tlsdate -v -C "$GOOGLE_CERTS" -l \
+ 2>&1 | logger -t tlsdate
+end script
diff --git a/m4/ax_append_compile_flags.m4 b/m4/ax_append_compile_flags.m4
new file mode 100644
index 0000000..1f8e708
--- /dev/null
+++ b/m4/ax_append_compile_flags.m4
@@ -0,0 +1,65 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS])
+#
+# DESCRIPTION
+#
+# For every FLAG1, FLAG2 it is checked whether the compiler works with the
+# flag. If it does, the flag is added FLAGS-VARIABLE
+#
+# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
+# CFLAGS) is used. During the check the flag is always added to the
+# current language's flags.
+#
+# If EXTRA-FLAGS is defined, it is added to the current language's default
+# flags (e.g. CFLAGS) when the check is done. The check is thus made with
+# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
+# force the compiler to issue an error when a bad flag is given.
+#
+# NOTE: This macro depends on the AX_APPEND_FLAG and
+# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
+# AX_APPEND_LINK_FLAGS.
+#
+# LICENSE
+#
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 3
+
+AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
+[AC_REQUIRE([AX_CHECK_COMPILE_FLAG])
+AC_REQUIRE([AX_APPEND_FLAG])
+for flag in $1; do
+ AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3])
+done
+])dnl AX_APPEND_COMPILE_FLAGS
diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4
new file mode 100644
index 0000000..1d38b76
--- /dev/null
+++ b/m4/ax_append_flag.m4
@@ -0,0 +1,69 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
+#
+# DESCRIPTION
+#
+# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
+# added in between.
+#
+# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
+# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
+# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
+# FLAG.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 2
+
+AC_DEFUN([AX_APPEND_FLAG],
+[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
+AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl
+AS_VAR_SET_IF(FLAGS,
+ [case " AS_VAR_GET(FLAGS) " in
+ *" $1 "*)
+ AC_RUN_LOG([: FLAGS already contains $1])
+ ;;
+ *)
+ AC_RUN_LOG([: FLAGS="$FLAGS $1"])
+ AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"])
+ ;;
+ esac],
+ [AS_VAR_SET(FLAGS,["$1"])])
+AS_VAR_POPDEF([FLAGS])dnl
+])dnl AX_APPEND_FLAG
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
new file mode 100644
index 0000000..c3a8d69
--- /dev/null
+++ b/m4/ax_check_compile_flag.m4
@@ -0,0 +1,72 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS])
+#
+# DESCRIPTION
+#
+# Check whether the given FLAG works with the current language's compiler
+# or gives an error. (Warnings, however, are ignored)
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# If EXTRA-FLAGS is defined, it is added to the current language's default
+# flags (e.g. CFLAGS) when the check is done. The check is thus made with
+# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
+# force the compiler to issue an error when a bad flag is given.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 2
+
+AC_DEFUN([AX_CHECK_COMPILE_FLAG],
+[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
+AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
+ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
+ _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
+AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_COMPILE_FLAGS
diff --git a/m4/ax_check_link_flag.m4 b/m4/ax_check_link_flag.m4
new file mode 100644
index 0000000..e2d0d36
--- /dev/null
+++ b/m4/ax_check_link_flag.m4
@@ -0,0 +1,71 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS])
+#
+# DESCRIPTION
+#
+# Check whether the given FLAG works with the linker or gives an error.
+# (Warnings, however, are ignored)
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# If EXTRA-FLAGS is defined, it is added to the linker's default flags
+# when the check is done. The check is thus made with the flags: "LDFLAGS
+# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
+# issue an error when a bad flag is given.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 2
+
+AC_DEFUN([AX_CHECK_LINK_FLAG],
+[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
+AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
+ ax_check_save_flags=$LDFLAGS
+ LDFLAGS="$LDFLAGS $4 $1"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM()],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ LDFLAGS=$ax_check_save_flags])
+AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_LINK_FLAGS
diff --git a/m4/ax_platform.m4 b/m4/ax_platform.m4
new file mode 100644
index 0000000..f3da57d
--- /dev/null
+++ b/m4/ax_platform.m4
@@ -0,0 +1,103 @@
+# ===========================================================================
+# http://
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PLATFORM
+#
+# DESCRIPTION
+#
+# Provide target and host defines.
+#
+# LICENSE
+#
+# Copyright (c) 2012 Brian Aker <brian@tangent.org>
+# Copyleft (ↄ) 2013 Jacob Appelbaum <jacob@appelbaum.net>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 1
+ AC_DEFUN([AX_PLATFORM],
+ [AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([AC_CANONICAL_TARGET])
+
+ AC_DEFINE_UNQUOTED([HOST_VENDOR],["$host_vendor"],[Vendor of Build System])
+ AC_DEFINE_UNQUOTED([HOST_OS],["$host_os"], [OS of Build System])
+ AC_DEFINE_UNQUOTED([HOST_CPU],["$host_cpu"], [CPU of Build System])
+
+ AC_DEFINE_UNQUOTED([TARGET_VENDOR],["$target_vendor"],[Vendor of Target System])
+ AC_DEFINE_UNQUOTED([TARGET_OS],["$target_os"], [OS of Target System])
+ AC_DEFINE_UNQUOTED([TARGET_CPU],["$target_cpu"], [CPU of Target System])
+
+ AS_CASE([$target_os],
+ [*mingw32*],
+ [TARGET_OS_WINDOWS="true"
+ AC_DEFINE([TARGET_OS_WINDOWS], [1], [Whether we are building for Windows])
+ AC_DEFINE([WINVER], [WindowsXP], [Version of Windows])
+ AC_DEFINE([_WIN32_WINNT], [0x0501], [Magical number to make things work])
+ AC_DEFINE([EAI_SYSTEM], [11], [Another magical number])
+ AH_BOTTOM([
+#ifndef HAVE_SYS_SOCKET_H
+# define SHUT_RD SD_RECEIVE
+# define SHUT_WR SD_SEND
+# define SHUT_RDWR SD_BOTH
+#endif
+ ])],
+ [*mingw*],
+ [TARGET_OS_MINGW="true"
+ AC_DEFINE([TARGET_OS_MINGW],[1],[Whether we build for MinGW])],
+ [*cygwin*],
+ [TARGET_OS_CYGWIN="true"
+ AC_DEFINE([TARGET_OS_CYGWIN],[1],[Whether we build for Cygwin])],
+ [*haiku*],
+ [TARGET_OS_HAIKU="true"
+ AC_DEFINE([TARGET_OS_HAIKU],[1],[Whether we build for Haiku])],
+ [*freebsd*],
+ [TARGET_OS_FREEBSD="true"
+ AC_DEFINE([TARGET_OS_FREEBSD],[1],[Whether we are building for FreeBSD])],
+ [*kfreebsd*-gnu],
+ [TARGET_OS_GNUKFREEBSD="true"
+ TARGET_OS_FREEBSD="true"
+ AC_DEFINE([TARGET_OS_FREEBSD],[1],[Whether we are building for FreeBSD])
+ AC_DEFINE([TARGET_OS_GNUKFREEBSD],[1],[Whether we are building for GNU/kFreeBSD])],
+ [*netbsd*],
+ [TARGET_OS_NETBSD="true"
+ AC_DEFINE([TARGET_OS_NETBSD],[1],[Whether we are building for NetBSD])],
+ [*openbsd*],
+ [TARGET_OS_OPENBSD="true"
+ AC_DEFINE([TARGET_OS_OPENBSD],[1],[Whether we are building for OpenBSD])],
+ [*dragonfly*],
+ [TARGET_OS_DRAGONFLYBSD="true"
+ AC_DEFINE([TARGET_OS_DRAGONFLYBSD],[1],[Whether we are building for DragonFly BSD])],
+ [*bsd*],
+ [TARGET_OS_BSD="true"
+ AC_DEFINE([TARGET_OS_BSD],[1],[Whether we are building for some other *BSD])],
+ [*solaris*],[AC_DEFINE([TARGET_OS_SOLARIS],[1],[Whether we are building for Solaris])],
+ [*darwin*],
+ [TARGET_OS_OSX="true"
+ AC_DEFINE([TARGET_OS_OSX],[1],[Whether we build for OSX])],
+ [*linux*],
+ [TARGET_OS_LINUX="true"
+ AC_DEFINE([TARGET_OS_LINUX],[1],[Whether we build for Linux])],
+ [*gnu*],
+ [TARGET_OS_GNUHURD="true"
+ AC_DEFINE([TARGET_OS_GNUHURD],[1],[Whether we build for GNU/Hurd])])
+
+ AM_CONDITIONAL([TARGET_WIN32],[test "x${TARGET_OS_WINDOWS}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_MINGW],[test "x${TARGET_OS_MINGW}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_CYGWIN],[test "x${TARGET_OS_CYGWIN}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_HAIKU],[test "x${TARGET_OS_HAIKU}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_OSX],[test "x${TARGET_OS_OSX}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_GNUHURD],[test "x${TARGET_OS_GNUHURD}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_LINUX],[test "x${TARGET_OS_LINUX}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_FREEBSD],[test "x${TARGET_OS_FREEBSD}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_GNUKFREEBSD],[test "x${TARGET_OS_GNUKFREEBSD}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_NETBSD],[test "x${TARGET_OS_NETBSD}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_OPENBSD],[test "x${TARGET_OS_OPENBSD}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_DRAGONFLYBSD],[test "x${TARGET_OS_DRAGONFLYBSD}" = "xtrue"])
+ AM_CONDITIONAL([TARGET_BSD],[test "x${TARGET_OS_BSD}" = "xtrue"])
+ ])
diff --git a/m4/bottom.m4 b/m4/bottom.m4
new file mode 100644
index 0000000..28e1c30
--- /dev/null
+++ b/m4/bottom.m4
@@ -0,0 +1,12 @@
+AC_DEFUN([CONFIG_EXTRA],[
+
+ AH_TOP([
+#pragma once
+
+/* _SYS_FEATURE_TESTS_H is Solaris, _FEATURES_H is GCC */
+#if defined( _SYS_FEATURE_TESTS_H) || defined(_FEATURES_H)
+#error "You should include config.h as your first include file"
+#endif
+
+ ])
+ ])
diff --git a/m4/visibility.m4 b/m4/visibility.m4
new file mode 100644
index 0000000..75c34b6
--- /dev/null
+++ b/m4/visibility.m4
@@ -0,0 +1,77 @@
+# visibility.m4 serial 4 (gettext-0.18.2)
+dnl Copyright (C) 2005, 2008, 2010-2011 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+dnl Tests whether the compiler supports the command-line option
+dnl -fvisibility=hidden and the function and variable attributes
+dnl __attribute__((__visibility__("hidden"))) and
+dnl __attribute__((__visibility__("default"))).
+dnl Does *not* test for __visibility__("protected") - which has tricky
+dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on
+dnl MacOS X.
+dnl Does *not* test for __visibility__("internal") - which has processor
+dnl dependent semantics.
+dnl Does *not* test for #pragma GCC visibility push(hidden) - which is
+dnl "really only recommended for legacy code".
+dnl Set the variable CFLAG_VISIBILITY.
+dnl Defines and sets the variable HAVE_VISIBILITY.
+
+AC_DEFUN([gl_VISIBILITY],
+[
+ AC_REQUIRE([AC_PROG_CC])
+ CFLAG_VISIBILITY=
+ HAVE_VISIBILITY=0
+ if test -n "$GCC"; then
+ dnl First, check whether -Werror can be added to the command line, or
+ dnl whether it leads to an error because of some other option that the
+ dnl user has put into $CC $CFLAGS $CPPFLAGS.
+ AC_MSG_CHECKING([whether the -Werror option is usable])
+ AC_CACHE_VAL([gl_cv_cc_vis_werror], [
+ gl_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror"
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([[]], [[]])],
+ [gl_cv_cc_vis_werror=yes],
+ [gl_cv_cc_vis_werror=no])
+ CFLAGS="$gl_save_CFLAGS"])
+ AC_MSG_RESULT([$gl_cv_cc_vis_werror])
+ dnl Now check whether visibility declarations are supported.
+ AC_MSG_CHECKING([for simple visibility declarations])
+ AC_CACHE_VAL([gl_cv_cc_visibility], [
+ gl_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -fvisibility=hidden"
+ dnl We use the option -Werror and a function dummyfunc, because on some
+ dnl platforms (Cygwin 1.7) the use of -fvisibility triggers a warning
+ dnl "visibility attribute not supported in this configuration; ignored"
+ dnl at the first function definition in every compilation unit, and we
+ dnl don't want to use the option in this case.
+ if test $gl_cv_cc_vis_werror = yes; then
+ CFLAGS="$CFLAGS -Werror"
+ fi
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[extern __attribute__((__visibility__("hidden"))) int hiddenvar;
+ extern __attribute__((__visibility__("default"))) int exportedvar;
+ extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void);
+ extern __attribute__((__visibility__("default"))) int exportedfunc (void);
+ void dummyfunc (void) {}
+ ]],
+ [[]])],
+ [gl_cv_cc_visibility=yes],
+ [gl_cv_cc_visibility=no])
+ CFLAGS="$gl_save_CFLAGS"])
+ AC_MSG_RESULT([$gl_cv_cc_visibility])
+ if test $gl_cv_cc_visibility = yes; then
+ CFLAG_VISIBILITY="-fvisibility=hidden"
+ HAVE_VISIBILITY=1
+ fi
+ fi
+ AC_SUBST([CFLAG_VISIBILITY])
+ AC_SUBST([HAVE_VISIBILITY])
+ AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY],
+ [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.])
+])
diff --git a/man/tlsdate-helper.1 b/man/tlsdate-helper.1
new file mode 100644
index 0000000..aedfe2b
--- /dev/null
+++ b/man/tlsdate-helper.1
@@ -0,0 +1,39 @@
+.\" Process this file with
+.\" groff -man -Tascii foo.1
+.\"
+.TH TLSDATE 1 "OCTOBER 2012" Linux "User Manuals"
+.SH NAME
+tlsdate-helper \- secure parasitic rdate replacement
+.SH SYNOPSIS
+.B tlsdate-helper host port protocol ca_racket verbose certdir setclock \
+showtime timewarp leapaway proxy-type://proxyhost:proxyport httpmode
+.SH DESCRIPTION
+.B tlsdate-helper
+is a tool for setting the system clock by hand or by communication
+with the network. It does not set the Real Time Clock. It is designed to be as
+secure as TLS (RFC 2246) but of course the security of TLS is often reduced to
+whichever CA racket you believe is trustworthy. By default, tlsdate-helper
+trusts your local CA root store - so any of these companies could assist in a
+MITM attack against you and you'd be screwed.
+
+The proxy argument expects HTTP, SOCKS4A or SOCKS5 formatted as followed:
+
+ http://127.0.0.1:8118
+ socks4a://127.0.0.1:9050
+ socks5://127.0.0.1:9050
+
+This tool is designed to be run by hand or as a system daemon. It must be
+run as root or otherwise have the proper caps; it will not be able to set
+the system time without running as root or another privileged user.
+.SH BUGS
+It's likely! Let us know by contacting jacob@appelbaum.net
+
+Note that
+.B tlsdate(1)
+is in Beta, and may not work as expected.
+.SH AUTHOR
+Jacob Appelbaum <jacob at appelbaum dot net>
+.SH "SEE ALSO"
+.B tlsdate(1),
+.B tlsdated(8),
+.B tlsdated.conf(5)
diff --git a/man/tlsdate.1 b/man/tlsdate.1
new file mode 100644
index 0000000..b052e48
--- /dev/null
+++ b/man/tlsdate.1
@@ -0,0 +1,95 @@
+.\" Process this file with
+.\" groff -man -Tascii foo.1
+.\"
+.TH TLSDATE 1 "OCTOBER 2012" Linux "User Manuals"
+.SH NAME
+tlsdate \- secure parasitic rdate replacement
+.SH SYNOPSIS
+.B tlsdate [\-hnvVstlw] [\-H [hostname]] [\-p [port]] [\-P [sslv23|sslv3|tlsv1]] \
+[\-\-certdir [dirname]] [\-x [\-\-proxy] proxy\-type://proxyhost:proxyport]
+.SH DESCRIPTION
+.B tlsdate
+is a tool for setting the system clock by hand or by communication
+with the network. It does not set the Real Time Clock. It is designed to be as
+secure as TLS (RFC 2246) but of course the security of TLS is often reduced to
+whichever CA racket you believe is trustworthy. By default, tlsdate trusts your
+local CA root store - so any of these companies could assist in a MITM attack
+against you and you'd be screwed.
+
+This tool is designed to be run by hand or as a system daemon. It must be
+run as root or otherwise have the proper caps; it will not be able to set
+the system time without running as root or another privileged user.
+.SH OPTIONS
+.IP "\-h | \-\-help"
+Print the help message
+.IP "\-s | \-\-skip\-verification"
+Skip certificate verification
+.IP "\-H | \-\-host [hostname|ip]"
+Set remote hostname (default: 'google.com')
+.IP "\-n | \-\-dont\-set\-clock"
+Do not set the system clock to the time of the remote server
+.IP "\-p | \-\-port [port]"
+Set remote port (default: '443')
+.IP "\-P | \-\-protocol [sslv23|sslv3|tlsv1]"
+Set protocol to use when communicating with server (default: 'tlsv1')
+.IP "\-C | \-\-certdir [dirname]"
+Set the local directory where certificates are located
+(default: '/etc/ssl/certs')
+This allows for certificate or certificate authority (CA) pinning. To ensure
+that signatures are only valid if they are signed by a specific CA or
+certificate, set the path to a directory containing only the desired
+certificates.
+.IP "\-x | \-\-proxy [proxy\-type://proxyhost:proxyport]"
+The proxy argument expects HTTP, SOCKS4A or SOCKS5 formatted as followed:
+
+ http://127.0.0.1:8118
+ socks4a://127.0.0.1:9050
+ socks5://127.0.0.1:9050
+
+The proxy support should not leak DNS requests and is suitable for use with Tor.
+.IP "\-v | \-\-verbose"
+Provide verbose output
+.IP "\-V | \-\-showtime [human|raw]"
+Show the time retrieved from the remote server in a human-readable format or as
+a raw time_t.
+.IP "\-t | \-\-timewarp"
+If the local clock is before RECENT_COMPILE_DATE; we set the clock to the
+RECENT_COMPILE_DATE. If the local clock is after RECENT_COMPILE_DATE, we leave
+the clock alone. Clock setting is performed as the first operation and will
+impact certificate verification. Specifically, this option is helpful if on
+first boot, the local system clock is set back to the era of Disco and Terrible
+Hair. This should ensure that X509_V_ERR_CERT_NOT_YET_VALID or
+X509_V_ERR_CERT_HAS_EXPIRED are not encountered because of a broken RTC or the
+lack of a local RTC; we assume that tlsdate is recompiled yearly and that all
+certificates are otherwise considered valid.
+.IP "\-l | \-\-leap"
+Normally, the passing of time or time yet to come ensures that SSL verify
+functions will fail to validate certificates. Commonly,
+X509_V_ERR_CERT_NOT_YET_VALID and X509_V_ERR_CERT_HAS_EXPIRED are painfully
+annoying but still very important error states. When the only issue with the
+certificates in question is the timing information, this option allows you to
+trust the remote system's time, as long as it is after RECENT_COMPILE_DATE and
+before MAX_REASONABLE_TIME. The connection will only be trusted if
+X509_V_ERR_CERT_NOT_YET_VALID and/or X509_V_OKX509_V_ERR_CERT_HAS_EXPIRED are
+the only errors encountered. The SSL verify function will not return X509_V_OK
+if there are any other issues, such as self-signed certificates or if the user
+pins to a CA that is not used by the remote server. This is useful if your RTC
+is broken on boot and you are unable to use DNSEC until you've at least had
+some kind of leap of cryptographically assured data.
+.IP "\-w | \-\-http"
+Run in web mode: look for the time in an HTTP "Date" header inside an
+HTTPS connection, rather than in the TLS connection itself. The provided
+hostname and port must support HTTPS.
+.SH BUGS
+It's likely! Let us know by contacting jacob@appelbaum.net
+
+Note that
+.B tlsdate(1)
+is in Beta, and may not work as expected.
+.SH AUTHOR
+Jacob Appelbaum <jacob at appelbaum dot net>
+.SH "SEE ALSO"
+.B tlsdate(1),
+.B tlsdate-helper(1),
+.B tlsdated(8),
+.B tlsdated.conf(5)
diff --git a/man/tlsdated.8 b/man/tlsdated.8
new file mode 100644
index 0000000..24f79fb
--- /dev/null
+++ b/man/tlsdated.8
@@ -0,0 +1,73 @@
+.\" Process this file with
+.\" groff -man -Tascii foo.1
+.\"
+.TH TLSDATED 8 "OCTOBER 2012" Linux "User Manuals"
+.SH NAME
+tlsdated \- secure parasitic rdate replacement daemon
+.SH SYNOPSIS
+.B tlsdated [\-wprlsvh] \
+[\-t <n>] \
+[\-d <n>] \
+[\-T <n>] \
+[\-D <n>] \
+[\-c /path/to ] \
+[\-a seconds ] \
+[\-\-] \
+[commands to be passed to tlsdate]
+.SH DESCRIPTION
+.B tlsdated
+is a daemon that runs tlsdate. It must be run as root or otherwise have the
+proper caps; it will not be able to set the system time without running as root
+or another privileged user.
+.SH OPTIONS
+.IP "\-w"
+don't set hwclock
+.IP "\-p"
+dry run (don't really set time)
+.IP "\-r"
+use stdin instead of netlink for routes
+.IP "\-t [n]"
+try up to n times if unsuccessful to synchronize the time
+.IP "\-d [n]"
+delay n seconds between tries
+.IP "\-T [n]"
+give subprocess n chances to exit
+.IP "\-D [n]"
+delay n seconds between wait attempts
+.IP "\-c [/path/to/cache/directory/]"
+set the cache directory
+.IP "\-a [n]"
+run at most every n seconds in steady state
+.IP "\-l"
+don't load disk timestamps
+.IP "\-s"
+don't save disk timestamp
+.IP "\-j [n]"
+add up to n seconds of jitter to steady-state fetches
+.IP "\-v"
+be verbose
+.IP "\-b"
+be extra verbose (debugging)
+.IP "\-U"
+do not use DBus if supported
+.IP "\-h"
+print help message
+.IP "\-f [/path/to/config/file]"
+use alternate config file
+.IP "\-x [proxy]"
+override the proxy supplied to sources in the config file
+.IP "[tlsdate command arguments]"
+arguments to be passed to tlsdate at launch time
+
+.SH BUGS
+It's likely! Let us know by contacting jacob@appelbaum.net
+
+Note that
+.B tlsdate(8)
+is in Beta, and may not work as expected.
+.SH AUTHOR
+Jacob Appelbaum <jacob at appelbaum dot net>
+.SH "SEE ALSO"
+.B tlsdate(1),
+.B tlsdate-helper(1),
+.B tlsdated.conf(5)
diff --git a/man/tlsdated.conf.5 b/man/tlsdated.conf.5
new file mode 100644
index 0000000..d4f763d
--- /dev/null
+++ b/man/tlsdated.conf.5
@@ -0,0 +1,75 @@
+.\" Process this file with
+.\" groff -man -Tascii foo.1
+.\"
+.TH TLSDATED 5 "JANUARY 2013" "File Formats and Conversions"
+.SH NAME
+tlsdated.conf \- tlsdated config file
+.SH SYNTAX
+\fBtlsdated.conf\fR is the configuration file for the \fBtlsdated(8)\fR daemon.
+The config file is formatted as a list of key-value pairs, one per line,
+separated by whitespace. Whitespace inside values is preserved, so
+.RS
+foo bar baz quxx
+.RE
+represents the key \fBfoo\fR mapping to the value \fBbar baz quxx\fR. Empty
+lines and lines beginning with \fB#\fR are ignored; leading whitespace on lines
+is stripped. For boolean options, the value \fByes\fR or no value at all
+indicates that the option should be switched on, and all other values indicate
+that the option should be switched off. \fINote that trailing whitespace is
+preserved in values.\fR
+.SH OPTIONS
+.IP "base-path [string]"
+Sets the path to tlsdated's cache directory.
+.IP "dry-run [bool]"
+If enabled, don't actually adjust the system time.
+.IP "jitter [int]"
+Add or subtract up to this many seconds from the steady-state interval when
+checking. This helps prevent correlation between sequential checks and smooth
+load on time hosts.
+.IP "max-tries [int]"
+How many times to try running the tlsdate subprocess.
+.IP "min-steady-state-interval [int]"
+Do not check more than once this many seconds when in steady state.
+.IP "should-load-disk [bool]"
+If enabled, try loading the current timestamp out of the cache directory.
+.IP "should-netlink [bool]"
+If enabled, use a netlink socket to get network events; otherwise, read network
+events from stdin.
+.IP "should-save-disk [bool]"
+If enabled, save the current timestamp to the cache directory every so often and
+at exit.
+.IP "should-sync-hwclock [bool]"
+If enabled, set the hwclock to the fetched time.
+.IP "steady-state-interval [int]"
+Check at least once this many seconds when in steady state.
+.IP "subprocess-timeout [int]"
+How many seconds to wait for the subprocess to exit.
+.IP "verbose [bool]"
+If enabled, tlsdated will be annoyingly verbose in syslog and on stdout.
+.IP "wait-between-tries [int]"
+How long to wait between runs of the subprocess.
+.SH SOURCES
+You can list one or more sources to fetch time from. The format of these is:
+.RS 4
+source
+.RS 4
+host www.example.com
+.br
+port 443
+.br
+proxy socks5://127.0.0.1:9050
+.RE
+end
+.RE
+.SH BUGS
+It's likely! Let us know by contacting jacob@appelbaum.net
+
+Note that
+.B tlsdated(8)
+is in Beta, and may not work as expected.
+.SH AUTHOR
+Jacob Appelbaum <jacob at appelbaum dot net>
+.SH "SEE ALSO"
+.B tlsdate(1),
+.B tlsdate-helper(1),
+.B tlsdated(8),
diff --git a/mkfile b/mkfile
new file mode 100644
index 0000000..00a51a9
--- /dev/null
+++ b/mkfile
@@ -0,0 +1,12 @@
+</$objtype/mkfile
+
+#src/tlsdate: src/tlsdate.c
+# $CC -I. $prereq
+
+src/tlsdatehelper: config.h
+ $CC -I. ./src/util-plan9.c ./src/proxy-bio-plan9.c ./src/tlsdate-helper-plan9.c /$objtype/lib/ape/libssl.a /$objtype/lib/ape/libcrypto.a
+
+config.h:
+ touch config.h
+
+CC=pcc -DHAVE_TIME_H -D_PLAN9_SOURCE -D_REENTRANT_SOURCE -D_BSD_EXTENSION -D_SUSV2_SOURCE -D_POSIX_SOURCE
diff --git a/run-tests b/run-tests
new file mode 100755
index 0000000..1e43b05
--- /dev/null
+++ b/run-tests
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+run_test() {
+ # Clear the last results
+ rm -f "$1"/result
+ [ -x "$1"/setup ] && "$1"/setup
+ if [ -r "$1"/tlsdated-flags ]; then
+ flags=$(cat "$1"/tlsdated-flags | sed "s/@TESTDIR@/$1/g")
+ elif [ -r "$1"/test.conf ]; then
+ flags="-U -w -p -r -l -s -b -f $1/test.conf -v"
+ else
+ flags="-U -w -p -r -l -s -b -f test.conf -v"
+ fi
+ # flags are deliberately unquoted here so that they'll be interpolated
+ (test -x "$1"/input.sh && "$1"/input.sh) |
+ timeout 8 src/tlsdated $flags -- "$1"/subproc.sh \
+ >"$1"/run-output 2>"$1"/run-err
+ [ -x "$1"/teardown ] && "$1"/teardown
+}
+
+test_passed() {
+ f="$t"/result
+ test -f "$f" && grep -q ok "$f"
+}
+
+total=0
+passed=0
+
+if ! test -x src/test/emit; then
+ echo "Make sure src/test/emit has been built (make check)!"
+ exit 1
+fi
+for t in tests/*; do
+ [ ! -d "$t" ] && continue
+ name="$(basename "$t")"
+ echo -n "$name: "
+ run_test "$t"
+ if test_passed "$t"; then
+ echo "ok"
+ passed=$((passed + 1))
+ else
+ echo "failed"
+ fi
+ total=$((total + 1))
+done
+echo "Passed: $passed/$total"
+[ $passed != $total ]
+exit $?
diff --git a/src/common/android.c b/src/common/android.c
new file mode 100644
index 0000000..655eb0b
--- /dev/null
+++ b/src/common/android.c
@@ -0,0 +1,18 @@
+#include "android.h"
+
+#include <string.h>
+
+char *strchrnul(const char *s, int c)
+{
+ char * matched_char = strchr(s, c);
+ if (matched_char == NULL) {
+ matched_char = (char*) s + strlen(s);
+ }
+ return matched_char;
+}
+
+int MIN(int a, int b) {
+ return a < b ? a : b;
+}
+
+
diff --git a/src/common/android.h b/src/common/android.h
new file mode 100644
index 0000000..f2908c2
--- /dev/null
+++ b/src/common/android.h
@@ -0,0 +1,25 @@
+/*
+ * Android's libc lacks fmemopen, so here is our implementation.
+ */
+
+#include <stdio.h>
+
+/**
+ * fmemopen expects this function
+ * defined in android.c
+ */
+int MIN(int a, int b);
+
+
+/*
+ * Android's libc does not provide strchrnul, so here
+ * is our own implementation. strchrnul behaves like
+ * strchr except instead of returning NULL if c is not
+ * in s, strchrnul returns a pointer to the \0 byte at
+ * the end of s.
+ * defined in android.c
+ */
+char *strchrnul(const char *s, int c);
+
+/* defined in fmemopen.c */
+FILE *fmemopen(void *buf, size_t size, const char *mode);
diff --git a/src/common/fmemopen-funopen.c b/src/common/fmemopen-funopen.c
new file mode 100644
index 0000000..87c8675
--- /dev/null
+++ b/src/common/fmemopen-funopen.c
@@ -0,0 +1,158 @@
+/*
+ * POSIX 2008 fmemopen(3) implemented in terms of BSD funopen(3)
+ */
+
+/*
+ * Copyright (c) 2013 Taylor R. Campbell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define _BSD_SOURCE
+#define _NETBSD_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fmemopen.h"
+
+struct fmem_cookie {
+ void *fmc_buffer;
+ size_t fmc_index;
+ size_t fmc_limit;
+};
+
+static int
+fmem_read(void *cookie, char *buffer, int n)
+{
+ struct fmem_cookie *const fmc = cookie;
+
+ if (n < 0) { /* paranoia */
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (n > (fmc->fmc_limit - fmc->fmc_index))
+ n = (fmc->fmc_limit - fmc->fmc_index);
+
+ (void)memcpy(buffer, (char *)fmc->fmc_buffer + fmc->fmc_index, n);
+ fmc->fmc_index += n;
+ return n;
+}
+
+static int
+fmem_write(void *cookie, const char *buffer, int n)
+{
+ struct fmem_cookie *const fmc = cookie;
+
+ if (n < 0) { /* paranoia */
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (n > (fmc->fmc_limit - fmc->fmc_index))
+ n = (fmc->fmc_limit - fmc->fmc_index);
+
+ (void)memcpy((char *)fmc->fmc_buffer + fmc->fmc_index, buffer, n);
+ fmc->fmc_index += n;
+ return n;
+}
+
+static fpos_t
+fmem_seek(void *cookie, fpos_t offset, int cmd)
+{
+ struct fmem_cookie *const fmc = cookie;
+
+ switch (cmd) {
+ case SEEK_SET:
+ if ((offset < 0) || (fmc->fmc_limit < offset))
+ goto einval;
+ fmc->fmc_index = offset;
+ return 0;
+
+ case SEEK_CUR:
+ if (offset < 0) {
+ /* Assume two's-complement arithmetic. */
+ if ((offset == ~(fpos_t)0) || (-offset > fmc->fmc_index))
+ goto einval;
+ } else {
+ if (offset > (fmc->fmc_limit - fmc->fmc_index))
+ goto einval;
+ }
+ fmc->fmc_index += offset;
+ return 0;
+
+ case SEEK_END:
+ /* Assume two's-complement arithmetic. */
+ if ((offset >= 0) || (offset == ~(fpos_t)0) || (fmc->fmc_limit < -offset))
+ goto einval;
+ fmc->fmc_index = (fmc->fmc_limit + offset);
+ return 0;
+
+ default:
+ goto einval;
+ }
+
+einval:
+ errno = EINVAL;
+ return -1;
+}
+
+static int
+fmem_close(void *cookie)
+{
+ struct fmem_cookie *const fmc = cookie;
+
+ free(fmc);
+
+ return 0;
+}
+
+FILE *
+fmemopen(void *buffer, size_t len, const char *mode)
+{
+ struct fmem_cookie *fmc;
+ FILE *file;
+
+ fmc = malloc(sizeof(*fmc));
+ if (fmc == NULL)
+ goto fail0;
+
+ (void)memset(fmc, 0, sizeof(*fmc));
+ fmc->fmc_buffer = buffer;
+ fmc->fmc_index = 0;
+ fmc->fmc_limit = len;
+
+ file = funopen(fmc, &fmem_read, &fmem_write, &fmem_seek, &fmem_close);
+ if (file == NULL)
+ goto fail1;
+
+ return file;
+
+fail1:
+ free(fmc);
+fail0:
+ return NULL;
+}
diff --git a/src/common/fmemopen.c b/src/common/fmemopen.c
new file mode 100644
index 0000000..d42fc30
--- /dev/null
+++ b/src/common/fmemopen.c
@@ -0,0 +1,225 @@
+/*
+ This file was retrieved from
+ http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/lib/libc/stdio/fmemopen.c
+ on 26/04/2013 by Abel Luck for inclusion in tlsdate for the Android port.
+*/
+#include "android.h"
+/* $NetBSD: fmemopen.c,v 1.4 2010/09/27 16:50:13 tnozaki Exp $ */
+
+/*-
+ * Copyright (c)2007, 2010 Takehiko NOZAKI,
+ * Copyright (c) 2012, Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+//#include "local.h"
+//#include "priv_stdio.h"
+
+struct fmemopen_cookie {
+ char *head, *tail, *cur, *eob;
+};
+
+static int
+fmemopen_read(void *cookie, char *buf, int nbytes)
+{
+ struct fmemopen_cookie *p;
+ char *s;
+ int len;
+
+ assert(cookie != NULL);
+ assert(buf != NULL && nbytes > 0);
+
+ p = cookie;
+ s = p->cur;
+ len = MIN(p->tail - p->cur, nbytes);
+ bcopy(p->cur, buf, len);
+ p->cur += len;
+
+ return (int)(p->cur - s);
+}
+
+static int
+fmemopen_write(void *cookie, const char *buf, int nbytes)
+{
+ struct fmemopen_cookie *p;
+ char *s;
+ int len;
+
+ assert(cookie != NULL);
+ assert(buf != NULL && nbytes > 0);
+
+ p = cookie;
+ if (p->cur >= p->tail)
+ return 0;
+ s = p->cur;
+
+ len = MIN(p->tail - p->cur, nbytes);
+
+ bcopy(buf, p->cur, len);
+
+ p->cur += len - 1;
+ if (p->cur == p->tail - 1) {
+ *p->cur = '\0';
+ if (buf[len - 1] == '\0')
+ p->cur++;
+ } else {
+ *++p->cur = '\0';
+ }
+
+ if (p->cur > p->eob)
+ p->eob = p->cur;
+
+ return (int)(p->cur - s);
+}
+
+static fpos_t
+fmemopen_seek(void *cookie, fpos_t offset, int whence)
+{
+ struct fmemopen_cookie *p;
+
+ assert(cookie != NULL);
+
+ p = (struct fmemopen_cookie *)cookie;
+ switch (whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ offset += p->cur - p->head;
+ break;
+ case SEEK_END:
+ offset += p->eob - p->head;
+ break;
+ default:
+ errno = EINVAL;
+ goto error;
+ }
+ if (offset >= (fpos_t)0 && offset <= p->tail - p->head) {
+ p->cur = p->head + (ptrdiff_t)offset;
+ return (fpos_t)(p->cur - p->head);
+ }
+error:
+ return (fpos_t)-1;
+}
+
+static int
+fmemopen_close0(void *cookie)
+{
+ assert(cookie != NULL);
+
+ free(cookie);
+
+ return 0;
+}
+
+static int
+fmemopen_close1(void *cookie)
+{
+ struct fmemopen_cookie *p;
+
+ assert(cookie != NULL);
+
+ p = cookie;
+ free(p->head);
+ free(p);
+
+ return 0;
+}
+
+
+FILE *
+fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
+{
+ int flags, oflags;
+ FILE *fp;
+ struct fmemopen_cookie *cookie;
+
+ if (size < (size_t)1)
+ goto invalid;
+
+ flags = __sflags(mode, &oflags);
+ if (flags == 0)
+ return NULL;
+
+ if ((oflags & O_RDWR) == 0 && buf == NULL)
+ goto invalid;
+
+ fp = __sfp();
+ if (fp == NULL)
+ return NULL;
+
+ cookie = malloc(sizeof(*cookie));
+ if (cookie == NULL)
+ goto release;
+
+ if (buf == NULL) {
+ cookie->head = malloc(size);
+ if (cookie->head == NULL) {
+ free(cookie);
+ goto release;
+ }
+ *cookie->head = '\0';
+ fp->_close = &fmemopen_close1;
+ } else {
+ cookie->head = (char *)buf;
+ if (oflags & O_TRUNC)
+ *cookie->head = '\0';
+ fp->_close = &fmemopen_close0;
+ }
+
+ cookie->tail = cookie->head + size;
+ cookie->eob = cookie->head;
+ do {
+ if (*cookie->eob == '\0')
+ break;
+ ++cookie->eob;
+ } while (--size > 0);
+
+ cookie->cur = (oflags & O_APPEND) ? cookie->eob : cookie->head;
+
+ // fp->pub._flags = flags;
+ fp->_write = (flags & __SRD) ? NULL : &fmemopen_write;
+ fp->_read = (flags & __SWR) ? NULL : &fmemopen_read;
+ fp->_seek = &fmemopen_seek;
+ fp->_cookie = (void *)cookie;
+
+ return fp;
+
+invalid:
+ errno = EINVAL;
+ return NULL;
+
+release:
+ //fp->pub._flags = 0;
+ return NULL;
+}
+
+
diff --git a/src/common/fmemopen.h b/src/common/fmemopen.h
new file mode 100644
index 0000000..28a2500
--- /dev/null
+++ b/src/common/fmemopen.h
@@ -0,0 +1,8 @@
+#ifndef TLSDATE_FMEMOPEN_H
+#define TLSDATE_FMEMOPEN_H
+
+#include <stdio.h>
+
+FILE *fmemopen(void *, size_t, const char *);
+
+#endif /* TLSDATE_FMEMOPEN_H */
diff --git a/src/common/strnlen.c b/src/common/strnlen.c
new file mode 100644
index 0000000..38e56e1
--- /dev/null
+++ b/src/common/strnlen.c
@@ -0,0 +1,19 @@
+/*
+ * Trivial strnlen(3) implementation
+ */
+
+#include <stddef.h>
+
+#include "strnlen.h"
+
+size_t
+strnlen(const char *s, size_t limit)
+{
+ size_t len;
+
+ for (len = 0; len < limit; len++)
+ if (*s++ == '\0')
+ break;
+
+ return len;
+}
diff --git a/src/common/strnlen.h b/src/common/strnlen.h
new file mode 100644
index 0000000..945c0d4
--- /dev/null
+++ b/src/common/strnlen.h
@@ -0,0 +1,8 @@
+#ifndef TLSDATE_STRNLEN_H
+#define TLSDATE_STRNLEN_H
+
+#include <stddef.h>
+
+size_t strnlen(const char *, size_t);
+
+#endif /* TLSDATE_STRNLEN_H */
diff --git a/src/compat/clock-darwin.c b/src/compat/clock-darwin.c
new file mode 100644
index 0000000..13cc82a
--- /dev/null
+++ b/src/compat/clock-darwin.c
@@ -0,0 +1,110 @@
+/* Copyright (c) 2012, David Goulet <dgoulet@ev0ke.net>
+ * Jacob Appelbaum <jacob@torproject.org>
+ * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file clock-darwin.c
+ * \brief Contains clock primitives for Mac OS X (Tested on 10.8.2)
+ **/
+
+#include "config.h"
+#include "clock.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+
+#ifdef __APPLE__
+#include <mach/clock.h>
+#include <mach/clock_priv.h>
+#include <mach/mach.h>
+#include <mach/clock_types.h>
+#include <mach/mach_traps.h>
+#include <mach/clock_reply.h>
+#include <mach/mach_time.h>
+#include <mach/mach_error.h>
+#endif
+
+#include <assert.h>
+
+/**
+ * Get current real time value and store it into time.
+ *
+ * @param time where the current time is stored
+ * @return clock_gettime syscall return value
+ */
+int clock_get_real_time(struct tlsdate_time *time)
+{
+ /* Safety net */
+ assert(time);
+
+ kern_return_t r;
+ clock_serv_t cclock;
+ mach_timespec_t mts;
+
+ r = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+ if (r != KERN_SUCCESS)
+ {
+ fprintf(stderr, "host_get_clock_service failed!\n");
+ return -1;
+ }
+
+ r = clock_get_time(cclock, &mts);
+ if (r != KERN_SUCCESS)
+ {
+ fprintf(stderr, "clock_get_time failed!\n");
+ return -1;
+ }
+
+ r = mach_port_deallocate(mach_task_self(), cclock);
+ if (r != KERN_SUCCESS)
+ {
+ fprintf(stderr, "mach_port_deallocate failed!\n");
+ return -1;
+ }
+
+ time->tp.tv_sec = mts.tv_sec;
+ time->tp.tv_nsec = mts.tv_nsec;
+ return r;
+}
+
+/**
+ * Set current real time clock using time.
+ *
+ * @param time where the current time to set is stored
+ * @return clock_settime syscall return value
+ */
+int clock_set_real_time(const struct tlsdate_time *time)
+{
+ /* Safety net */
+ assert(time);
+
+ //printf ("V: server time %u\n", (unsigned int) time->tp.tv_sec);
+ int r;
+ struct timeval tv = {time->tp.tv_sec, 0};
+
+ r = settimeofday(&tv, NULL);
+ if (r != 0)
+ {
+ fprintf(stderr, "setimeofday failed!\n");
+ return -1;
+ }
+
+ return r;
+}
+
+/**
+ * Init a tlsdate_time structure.
+ *
+ * @param sec is the seconds
+ * @param nsec is the nanoseconds
+ */
+void clock_init_time(struct tlsdate_time *time, time_t sec,
+ long nsec)
+{
+ /* Safety net */
+ assert(time);
+
+ time->tp.tv_sec = sec;
+ time->tp.tv_nsec = nsec;
+}
diff --git a/src/compat/clock-hurd.c b/src/compat/clock-hurd.c
new file mode 100644
index 0000000..3d62068
--- /dev/null
+++ b/src/compat/clock-hurd.c
@@ -0,0 +1,59 @@
+/* Copyright (c) 2012, David Goulet <dgoulet@ev0ke.net>
+ * Jacob Appelbaum
+ * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file clock-linux.c
+ * \brief Contains clock primitives for GNU/Linux OS
+ **/
+
+#include "config.h"
+
+#include <assert.h>
+
+#include "src/compat/clock.h"
+
+/**
+ * Get current real time value and store it into time.
+ *
+ * @param time where the current time is stored
+ * @return clock_gettime syscall return value
+ */
+int clock_get_real_time(struct tlsdate_time *time)
+{
+ /* Safety net */
+ assert(time);
+
+ return clock_gettime(CLOCK_REALTIME, &time->tp);
+}
+
+/**
+ * Set current real time clock using time.
+ *
+ * @param time where the current time to set is stored
+ * @return clock_settime syscall return value
+ */
+int clock_set_real_time(const struct tlsdate_time *time)
+{
+ /* Safety net */
+ assert(time);
+
+ return clock_settime(CLOCK_REALTIME, &time->tp);
+}
+
+/**
+ * Init a tlsdate_time structure.
+ *
+ * @param sec is the seconds
+ * @param nsec is the nanoseconds
+ */
+void clock_init_time(struct tlsdate_time *time, time_t sec,
+ long nsec)
+{
+ /* Safety net */
+ assert(time);
+
+ time->tp.tv_sec = sec;
+ time->tp.tv_nsec = nsec;
+}
diff --git a/src/compat/clock-linux.c b/src/compat/clock-linux.c
new file mode 100644
index 0000000..84bc934
--- /dev/null
+++ b/src/compat/clock-linux.c
@@ -0,0 +1,56 @@
+/* Copyright (c) 2012, David Goulet <dgoulet@ev0ke.net>
+ * Jacob Appelbaum
+ * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file clock-linux.c
+ * \brief Contains clock primitives for GNU/Linux OS
+ **/
+
+#include "config.h"
+
+#include <assert.h>
+
+#include "src/compat/clock.h"
+
+/**
+ * Get current real time value and store it into time.
+ *
+ * @param time where the current time is stored
+ * @return clock_gettime syscall return value
+ */
+int clock_get_real_time(struct tlsdate_time *time)
+{
+ /* Safety net */
+ assert (time);
+ return clock_gettime (CLOCK_REALTIME, &time->tp);
+}
+
+/**
+ * Set current real time clock using time.
+ *
+ * @param time where the current time to set is stored
+ * @return clock_settime syscall return value
+ */
+int clock_set_real_time(const struct tlsdate_time *time)
+{
+ /* Safety net */
+ assert (time);
+ return clock_settime (CLOCK_REALTIME, &time->tp);
+}
+
+/**
+ * Init a tlsdate_time structure.
+ *
+ * @param sec is the seconds
+ * @param nsec is the nanoseconds
+ */
+void clock_init_time(struct tlsdate_time *time, time_t sec,
+ long nsec)
+{
+ /* Safety net */
+ assert (time);
+ time->tp.tv_sec = sec;
+ time->tp.tv_nsec = nsec;
+}
diff --git a/src/compat/clock.h b/src/compat/clock.h
new file mode 100644
index 0000000..15f3223
--- /dev/null
+++ b/src/compat/clock.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2012, David Goulet <dgoulet@ev0ke.net>
+ * Jacob Appelbaum <jacob@torproject.org>
+ * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file clock.h
+ * \brief Header file for the clock primitives.
+ **/
+
+#pragma once
+#ifndef CLOCK_HEADER_GUARD
+#define CLOCK_HEADER_GUARD 1
+
+#include <src/visibility.h>
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#ifdef TARGET_OS_OPENBSD
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_MACH_CLOCK_H
+#include <mach/clock.h>
+#endif
+#ifdef HAVE_MACH_MACH_H
+#include <mach/mach.h>
+#endif
+
+struct tlsdate_time {
+#if defined(__linux__) || defined(__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__DragonFly__)
+ struct timespec tp;
+#elif defined(__APPLE__)
+ mach_timespec_t tp;
+#elif _WIN32
+ void *tp;
+#elif TARGET_OS_HAIKU
+ struct timespec tp;
+#elif TARGET_OS_CYGWIN
+ struct timespec tp;
+#elif TARGET_OS_MINGW
+ struct timespec tp;
+#elif TARGET_OS_GNUHURD
+ struct timespec tp;
+#else
+ struct timespec tp;
+#endif
+};
+
+TLSDATE_API
+int clock_get_real_time(struct tlsdate_time *time);
+
+TLSDATE_API
+int clock_set_real_time(const struct tlsdate_time *time);
+
+TLSDATE_API
+void clock_init_time(struct tlsdate_time *time, time_t sec, long nsec);
+
+/* Helper macros to access time values */
+#define CLOCK_SEC(time) ((time)->tp.tv_sec)
+#define CLOCK_MSEC(time) ((time)->tp.tv_nsec / 1000000)
+#define CLOCK_USEC(time) ((time)->tp.tv_nsec / 1000)
+#define CLOCK_NSEC(time) ((time)->tp.tv_nsec)
+
+/* Helper macros to access time values. TODO: Complete them */
+/*
+#define CLOCK_SEC(time)
+#define CLOCK_MSEC(time)
+#define CLOCK_USEC(time)
+#define CLOCK_NSEC(time)
+*/
+#endif // CLOCK_HEADER_GUARD
diff --git a/src/compat/include.am b/src/compat/include.am
new file mode 100644
index 0000000..f499c70
--- /dev/null
+++ b/src/compat/include.am
@@ -0,0 +1,59 @@
+# vim:ft=automake
+
+noinst_LTLIBRARIES+= src/compat/libtlsdate_compat.la
+
+noinst_HEADERS+= src/compat/clock.h
+
+src_compat_libtlsdate_compat_la_SOURCES =
+src_compat_libtlsdate_compat_la_CFLAGS = -DBUILDING_TLSDATE
+src_compat_libtlsdate_compat_la_LIBADD =
+
+if TARGET_OSX
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-darwin.c
+endif
+
+if TARGET_LINUX
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-linux.c
+endif
+
+if TARGET_FREEBSD
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-linux.c
+endif
+
+if TARGET_NETBSD
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-linux.c
+endif
+
+if TARGET_OPENBSD
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-linux.c
+endif
+
+if TARGET_DRAGONFLYBSD
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-linux.c
+endif
+
+if TARGET_BSD
+if !TARGET_NETBSD
+if !TARGET_FREEBSD
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-linux.c
+endif
+endif
+endif
+
+if TARGET_GNUHURD
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-hurd.c
+endif
+
+if TARGET_CYGWIN
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-linux.c
+endif
+
+if TARGET_MINGW
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-linux.c
+endif
+
+if TARGET_HAIKU
+src_compat_libtlsdate_compat_la_SOURCES+= src/compat/clock-linux.c
+endif
+
+src_compat_libtlsdate_compat_la_LIBADD+= @RT_LIB@
diff --git a/src/conf-unittest.c b/src/conf-unittest.c
new file mode 100644
index 0000000..0cc7a56
--- /dev/null
+++ b/src/conf-unittest.c
@@ -0,0 +1,95 @@
+/*
+ * conf-unittest.c - config parser unit tests
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/conf.h"
+#include "src/test_harness.h"
+
+#ifdef HAVE_ANDROID_SYSTEM
+#include "src/common/fmemopen.h"
+#endif
+
+#ifndef HAVE_FMEMOPEN
+#include "src/common/fmemopen.h"
+#endif
+
+FILE *fopenstr (const char *str)
+{
+ /* strlen(str) instead of strlen(str) + 1 because files shouldn't appear
+ * null-terminated. Cast away constness because we're in read mode, but the
+ * fmemopen prototype has no way to express that. */
+ return fmemopen ( (char *) str, strlen (str), "r");
+}
+
+TEST (parse_empty)
+{
+ /* can't do a truly empty file - fmemopen() combusts */
+ FILE *f = fopenstr ("\n");
+ ASSERT_NE (NULL, f);
+ struct conf_entry *e = conf_parse (f);
+ EXPECT_NULL (e);
+ conf_free (e);
+}
+
+TEST (parse_basic)
+{
+ FILE *f = fopenstr ("foo bar\nbaz quxx\n");
+ ASSERT_NE (NULL, f);
+ struct conf_entry *e = conf_parse (f);
+ ASSERT_NE (NULL, e);
+ EXPECT_STREQ (e->key, "foo");
+ EXPECT_STREQ (e->value, "bar");
+ ASSERT_NE (NULL, e->next);
+ EXPECT_STREQ (e->next->key, "baz");
+ EXPECT_STREQ (e->next->value, "quxx");
+ ASSERT_NULL (e->next->next);
+ conf_free (e);
+}
+
+TEST (parse_novalue)
+{
+ FILE *f = fopenstr ("abcdef\n");
+ ASSERT_NE (NULL, f);
+ struct conf_entry *e = conf_parse (f);
+ ASSERT_NE (NULL, e);
+ EXPECT_STREQ (e->key, "abcdef");
+ EXPECT_NULL (e->value);
+ EXPECT_NULL (e->next);
+ conf_free (e);
+}
+
+TEST (parse_whitespace)
+{
+ FILE *f = fopenstr (" fribble grotz \n");
+ ASSERT_NE (NULL, f);
+ struct conf_entry *e = conf_parse (f);
+ ASSERT_NE (NULL, e);
+ EXPECT_STREQ (e->key, "fribble");
+ EXPECT_STREQ (e->value, "grotz ");
+ EXPECT_NULL (e->next);
+ conf_free (e);
+}
+
+TEST (parse_comment)
+{
+ FILE *f = fopenstr ("#foo bar\nbaz quxx\n");
+ ASSERT_NE (NULL, f);
+ struct conf_entry *e = conf_parse (f);
+ ASSERT_NE (NULL, e);
+ EXPECT_STREQ (e->key, "baz");
+ EXPECT_STREQ (e->value, "quxx");
+ EXPECT_NULL (e->next);
+ conf_free (e);
+}
+
+TEST_HARNESS_MAIN
diff --git a/src/conf.c b/src/conf.c
new file mode 100644
index 0000000..abb1b92
--- /dev/null
+++ b/src/conf.c
@@ -0,0 +1,119 @@
+/* conf.c - config file parser */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* strchrnul */
+#endif
+#include "config.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/conf.h"
+
+#ifdef TARGET_OS_NETBSD
+#include "src/common/android.h" // XXX: Dirty hack - make this more generic later
+#endif
+
+#ifdef TARGET_OS_OPENBSD
+#include "src/common/android.h" // XXX: Dirty hack - make this more generic later
+#endif
+
+#ifdef TARGET_OS_DRAGONFLYBSD
+#include "src/common/android.h" // XXX: Dirty hack - make this more generic later
+#endif
+
+#ifdef TARGET_OS_HAIKU
+#include "src/common/android.h" // XXX: Dirty hack - make this more generic later
+#endif
+
+#ifdef TARGET_OS_FREEBSD
+#ifndef HAVE_STRCHRNUL
+#include "src/common/android.h" // XXX: Dirty hack - make this more generic later
+#endif
+#endif
+
+#ifdef HAVE_ANDROID
+#include "src/common/android.h"
+#endif
+
+void strip_newlines (char *line)
+{
+ *strchrnul (line, '\n') = '\0';
+ *strchrnul (line, '\r') = '\0';
+}
+
+char *eat_whitespace (char *line)
+{
+ while (isspace ((int)(unsigned char)*line))
+ line++;
+ return line;
+}
+
+int is_ignored_line (char *line)
+{
+ return !*line || *line == '#';
+}
+
+struct conf_entry *conf_parse (FILE *f)
+{
+ struct conf_entry *head = NULL;
+ struct conf_entry *tail = NULL;
+ char buf[CONF_MAX_LINE];
+
+ while (fgets (buf, sizeof (buf), f))
+ {
+ struct conf_entry *e;
+ char *start = buf;
+ char *key;
+ char *val;
+ strip_newlines (start);
+ start = eat_whitespace (start);
+ if (is_ignored_line (start))
+ continue;
+ key = strtok (start, " \t");
+ val = strtok (NULL, "");
+ if (val)
+ val = eat_whitespace (val);
+ e = malloc (sizeof *e);
+ if (!e)
+ goto fail;
+ e->next = NULL;
+ e->key = strdup (key);
+ e->value = val ? strdup (val) : NULL;
+ if (!e->key || (val && !e->value))
+ {
+ free (e->key);
+ free (e->value);
+ goto fail;
+ }
+ if (!head)
+ {
+ head = e;
+ tail = e;
+ }
+ else
+ {
+ tail->next = e;
+ tail = e;
+ }
+ }
+
+ return head;
+fail:
+ conf_free (head);
+ return NULL;
+}
+
+void conf_free (struct conf_entry *e)
+{
+ struct conf_entry *n;
+ while (e)
+ {
+ n = e->next;
+ free (e->key);
+ free (e->value);
+ free (e);
+ e = n;
+ }
+}
diff --git a/src/conf.h b/src/conf.h
new file mode 100644
index 0000000..d01290b
--- /dev/null
+++ b/src/conf.h
@@ -0,0 +1,20 @@
+/* conf.h - config file parser */
+
+#ifndef CONF_H
+#define CONF_H
+
+#include <stdio.h>
+
+#define CONF_MAX_LINE 16384
+
+struct conf_entry
+{
+ struct conf_entry *next;
+ char *key;
+ char *value;
+};
+
+struct conf_entry *conf_parse (FILE *f);
+void conf_free (struct conf_entry *e);
+
+#endif /* !CONF_H */
diff --git a/src/dbus.c b/src/dbus.c
new file mode 100644
index 0000000..b83e9ef
--- /dev/null
+++ b/src/dbus.c
@@ -0,0 +1,578 @@
+/*
+ * dbus.c - event loop dbus integration
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+#include <event2/event.h>
+#include "src/dbus.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+/* Pointers are needed so that we don't have to deal with array-to-pointer
+ * weirdness with DBus argument passing.
+ */
+static const char kServiceInterfaceData[] = "org.torproject.tlsdate";
+static const char *kServiceInterface = kServiceInterfaceData;
+static const char kServicePathData[] = "/org/torproject/tlsdate";
+static const char *kServicePath = kServicePathData;
+static const char kServiceSetTimeData[] = "SetTime";
+static const char *kServiceSetTime = kServiceSetTimeData;
+static const char kServiceCanSetTimeData[] = "CanSetTime";
+static const char *kServiceCanSetTime = kServiceCanSetTimeData;
+static const char kServiceLastSyncInfoData[] = "LastSyncInfo";
+static const char *kServiceLastSyncInfo = kServiceLastSyncInfoData;
+
+static const char kTimeUpdatedData[] = "TimeUpdated";
+static const char *kTimeUpdated = kTimeUpdatedData;
+
+static
+short
+dbus_to_event (unsigned int flags)
+{
+ short events = 0;
+ if (flags & DBUS_WATCH_READABLE)
+ events |= EV_READ;
+ if (flags & DBUS_WATCH_WRITABLE)
+ events |= EV_WRITE;
+ return events;
+}
+
+static
+unsigned int
+event_to_dbus (short events)
+{
+ unsigned int flags = 0;
+ if (events & EV_READ)
+ flags |= DBUS_WATCH_READABLE;
+ if (events & EV_WRITE)
+ flags |= DBUS_WATCH_WRITABLE;
+ return flags;
+}
+
+static
+void
+watch_handler (evutil_socket_t fd, short what, void *arg)
+{
+ DBusWatch *watch = arg;
+ struct dbus_event_data *data = dbus_watch_get_data (watch);
+ unsigned int flags = event_to_dbus (what);
+ dbus_connection_ref (data->state->conn);
+ while (!dbus_watch_handle (watch, flags))
+ {
+ info ("dbus_watch_handle waiting for memory . . .");
+ /* TODO(wad) this seems like a bad idea. */
+ sleep (1);
+ }
+ while (dbus_connection_dispatch (data->state->conn) ==
+ DBUS_DISPATCH_DATA_REMAINS);
+ dbus_connection_unref (data->state->conn);
+}
+
+static
+dbus_bool_t
+add_watch (DBusWatch *watch, void *user_data)
+{
+ struct state *tlsdate_state = user_data;
+ struct dbus_state *state = tlsdate_state->dbus;
+ struct dbus_event_data *data;
+ /* Don't add anything if it isn't active. */
+ data = dbus_malloc0 (sizeof (struct dbus_event_data));
+ if (!data)
+ return FALSE;
+ data->state = state;
+ data->event = event_new (tlsdate_state->base,
+ dbus_watch_get_unix_fd (watch),
+ EV_PERSIST|dbus_to_event (dbus_watch_get_flags (watch)),
+ watch_handler,
+ watch);
+ if (!data->event)
+ {
+ dbus_free (data);
+ return FALSE;
+ }
+ event_priority_set (data->event, PRI_WAKE);
+
+ dbus_watch_set_data (watch, data, dbus_free);
+ if (!dbus_watch_get_enabled (watch))
+ return TRUE;
+ /* Only add the event if it is enabled. */
+ if (event_add (data->event, NULL))
+ {
+ error ("Could not add a new watch!");
+ event_free (data->event);
+ dbus_free (data);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static
+void
+remove_watch (DBusWatch *watch, void *user_data)
+{
+ struct dbus_event_data *data = dbus_watch_get_data (watch);
+ /* TODO(wad) should this just be in a free_function? */
+ if (data && data->event)
+ {
+ event_del (data->event);
+ event_free (data->event);
+ }
+}
+
+static
+void
+toggle_watch (DBusWatch *watch, void *user_data)
+{
+ struct dbus_event_data *data = dbus_watch_get_data (watch);
+ if (!data || !data->event) /* should not be possible */
+ return;
+ /* If the event is pending, then we have to remove it to
+ * disable it or remove it before re-enabling it.
+ */
+ if (event_pending (data->event,
+ dbus_to_event (dbus_watch_get_flags (watch)), NULL))
+ event_del (data->event);
+ if (dbus_watch_get_enabled (watch))
+ {
+ event_add (data->event, NULL);
+ }
+}
+
+static
+void
+timeout_handler (evutil_socket_t fd, short what, void *arg)
+{
+ DBusTimeout *t = arg;
+ struct dbus_event_data *data = dbus_timeout_get_data (t);
+ dbus_connection_ref (data->state->conn);
+ dbus_timeout_handle (t);
+ dbus_connection_unref (data->state->conn);
+}
+
+static
+dbus_bool_t
+add_timeout (DBusTimeout *t, void *user_data)
+{
+ struct state *tlsdate_state = user_data;
+ struct dbus_state *state = tlsdate_state->dbus;
+ struct dbus_event_data *data;
+ int ms = dbus_timeout_get_interval (t);
+ struct timeval interval;
+ data = dbus_malloc0 (sizeof (struct dbus_event_data));
+ if (!data)
+ return FALSE;
+ interval.tv_sec = ms / 1000;
+ interval.tv_usec = (ms % 1000) * 1000;
+ data->state = state;
+ data->event = event_new (tlsdate_state->base,
+ -1,
+ EV_TIMEOUT|EV_PERSIST,
+ timeout_handler,
+ t);
+ if (!data->event)
+ {
+ dbus_free (data);
+ return FALSE;
+ }
+ event_priority_set (data->event, PRI_WAKE);
+ dbus_timeout_set_data (t, data, dbus_free);
+ /* Only add it to the queue if it is enabled. */
+ if (!dbus_timeout_get_enabled (t))
+ return TRUE;
+ if (event_add (data->event, &interval))
+ {
+ error ("Could not add a new timeout!");
+ event_free (data->event);
+ dbus_free (data);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static
+void
+remove_timeout (DBusTimeout *t, void *user_data)
+{
+ struct dbus_event_data *data = dbus_timeout_get_data (t);
+ if (data && data->event)
+ {
+ event_del (data->event);
+ event_free (data->event);
+ }
+}
+
+static
+void
+toggle_timeout (DBusTimeout *t, void *user_data)
+{
+ struct dbus_event_data *data = dbus_timeout_get_data (t);
+ int ms = dbus_timeout_get_interval (t);
+ struct timeval interval;
+ /* If the event is pending, then we have to remove it to
+ * disable it or remove it before re-enabling it.
+ */
+ if (evtimer_pending (data->event, NULL))
+ event_del (data->event);
+ if (dbus_timeout_get_enabled (t))
+ {
+ interval.tv_sec = ms / 1000;
+ interval.tv_usec = (ms % 1000) * 1000;
+ event_add (data->event, &interval);
+ }
+}
+
+void
+dbus_announce (struct state *global_state)
+{
+ struct dbus_state *state = global_state->dbus;
+ DBusConnection *conn;
+ DBusMessage *msg;
+ uint32_t ignored;
+ const char *sync_type = sync_type_str (global_state->last_sync_type);
+
+#ifndef TLSDATED_MAIN
+ /* Return early if we're not linked to tlsdated. */
+ return;
+#endif
+
+ conn = state->conn;
+ msg = dbus_message_new_signal (kServicePath, kServiceInterface, kTimeUpdated);
+ if (!msg)
+ {
+ error ("[dbus] could not allocate new announce signal");
+ return;
+ }
+ if (!dbus_message_append_args (msg,
+ DBUS_TYPE_STRING, &sync_type,
+ DBUS_TYPE_INVALID))
+ {
+ error ("[dbus] could not allocate new announce args");
+ return;
+ }
+ if (!dbus_connection_send (conn, msg, &ignored))
+ {
+ error ("[dbus] could not send announce signal");
+ return;
+ }
+}
+
+static
+DBusHandlerResult
+send_time_reply (DBusConnection *connection,
+ DBusMessage *message,
+ dbus_uint32_t code)
+{
+ DBusMessage *reply;
+ DBusMessageIter args;
+ dbus_uint32_t serial = dbus_message_get_serial (message);
+
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ {
+ error ("[dbus] no memory to reply to SetTime");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!dbus_message_set_reply_serial (reply, serial))
+ {
+ error ("[dbus] no memory to set serial for reply to SetTime");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ dbus_message_iter_init_append (reply, &args);
+ if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_UINT32, &code))
+ {
+ error ("[dbus] no memory to add reply args to SetTime");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!dbus_connection_send (connection, reply, &serial))
+ {
+ error ("[dbus] unable to send SetTime reply");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_connection_flush (connection);
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+send_can_reply (DBusConnection *connection,
+ DBusMessage *message,
+ dbus_bool_t allowed)
+{
+ DBusMessage *reply;
+ DBusMessageIter args;
+ dbus_uint32_t serial = dbus_message_get_serial (message);
+
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ {
+ error ("[dbus] no memory to reply to CanSetTime");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!dbus_message_set_reply_serial (reply, serial))
+ {
+ error ("[dbus] no memory to set serial for reply to CanSetTime");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ dbus_message_iter_init_append (reply, &args);
+ if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_BOOLEAN, &allowed))
+ {
+ error ("[dbus] no memory to add reply args to CanSetTime");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!dbus_connection_send (connection, reply, &serial))
+ {
+ error ("[dbus] unable to send CanSetTime reply");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_connection_flush (connection);
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+/* Returns 0 if time cannot be set, and 1 otherwise. */
+static
+int
+can_set_time (struct state *state)
+{
+ time_t delta = state->clock_delta;
+ /* Force a synchronization check. */
+ if (check_continuity (&delta) > 0)
+ {
+ info ("[event:%s] clock delta desync detected (%ld != %ld)",
+ __func__, state->clock_delta, delta);
+ delta = state->clock_delta = 0;
+ invalidate_time (state);
+ }
+ /* Only use the time if we're not synchronized. */
+ return !state->clock_delta;
+}
+
+static
+DBusHandlerResult
+handle_set_time (DBusConnection *connection,
+ DBusMessage *message,
+ struct state *state)
+{
+ DBusMessageIter iter;
+ DBusError error;
+ dbus_int64_t requested_time = 0;
+ verb_debug ("[event:%s]: fired", __func__);
+ dbus_error_init (&error);
+
+ /* Expects DBUS_TYPE_INT64:<time_t> */
+ if (!dbus_message_iter_init (message, &iter))
+ return send_time_reply (connection, message, SET_TIME_BAD_CALL);
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT64)
+ return send_time_reply (connection, message, SET_TIME_BAD_CALL);
+ dbus_message_iter_get_basic (&iter, &requested_time);
+ if (!is_sane_time ((time_t) requested_time))
+ {
+ error ("event:%s] invalid time from user: %ld", __func__,
+ (time_t) requested_time);
+ return send_time_reply (connection, message, SET_TIME_INVALID);
+ }
+ if (!can_set_time (state))
+ {
+ info ("[event:%s]: time is already synchronized.", __func__);
+ return send_time_reply (connection, message, SET_TIME_NOT_ALLOWED);
+ }
+
+ state->last_time = requested_time;
+ state->last_sync_type = SYNC_TYPE_PLATFORM;
+ trigger_event (state, E_SAVE, -1);
+ /* Kick off a network sync for good measure. */
+ action_kickoff_time_sync (-1, EV_TIMEOUT, state);
+
+ return send_time_reply (connection, message, SET_TIME_OK);
+}
+
+static
+DBusHandlerResult
+handle_can_set_time (DBusConnection *connection,
+ DBusMessage *message,
+ struct state *state)
+{
+ verb_debug ("[event:%s]: fired", __func__);
+ return send_can_reply (connection, message, can_set_time (state));
+}
+
+static
+DBusHandlerResult
+handle_last_sync_info (DBusConnection *connection,
+ DBusMessage *message,
+ struct state *state)
+{
+ DBusMessage *reply;
+ DBusMessageIter args;
+ dbus_uint32_t serial = dbus_message_get_serial (message);
+ dbus_bool_t net_synced = !!state->clock_delta;
+ const char *sync = sync_type_str (state->last_sync_type);
+ int64_t t = state->last_time;
+
+ verb_debug ("[dbus]: handler fired");
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ {
+ error ("[dbus] no memory to reply to LastSyncInfo");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!dbus_message_set_reply_serial (reply, serial))
+ {
+ error ("[dbus] no memory to set serial for reply to LastSyncInfo");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ dbus_message_iter_init_append (reply, &args);
+ if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_BOOLEAN, &net_synced))
+ {
+ error ("[dbus] no memory to add reply args to LastSyncInfo");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &sync))
+ {
+ error ("[dbus] no memory to add reply args to LastSyncInfo");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_INT64, &t))
+ {
+ error ("[dbus] no memory to add reply args to LastSyncInfo");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!dbus_connection_send (connection, reply, &serial))
+ {
+ error ("[dbus] unable to send LastSyncInfo reply");
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_connection_flush (connection);
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+void
+unregister_service (DBusConnection *conn, void *data)
+{
+ info ("dbus service has been unregistered");
+}
+
+static
+DBusHandlerResult
+service_dispatch (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct state *state = data;
+ const char *interface;
+ const char *method;
+
+ verb_debug ("[dbus] service dispatcher called");
+ if (dbus_message_get_type (msg) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ interface = dbus_message_get_interface (msg);
+ method = dbus_message_get_member (msg);
+ if (!interface || !method)
+ {
+ verb_debug ("[dbus] service request fired with bogus data");
+ /* Consume it */
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ if (strcmp (interface, kServiceInterface))
+ {
+ verb_debug ("[dbus] invalid interface supplied");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ if (!strcmp (method, kServiceSetTime))
+ return handle_set_time (conn, msg, state);
+ else if (!strcmp (method, kServiceCanSetTime))
+ return handle_can_set_time (conn, msg, state);
+ else if (!strcmp (method, kServiceLastSyncInfo))
+ return handle_last_sync_info (conn, msg, state);
+ verb_debug ("[dbus] invalid method supplied");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable service_vtable = {
+ .unregister_function = unregister_service,
+ .message_function = service_dispatch,
+};
+
+int
+init_dbus (struct state *tlsdate_state)
+{
+ DBusError error;
+ dbus_error_init (&error);
+ struct dbus_state *state = calloc (1, sizeof (struct dbus_state));
+ if (!state)
+ return 1;
+ tlsdate_state->dbus = state;
+ state->conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (state->conn == NULL || dbus_error_is_set (&error))
+ {
+ error ("[dbus] error when connecting to the bus: %s",
+ error.message);
+ goto err;
+ }
+ if (!dbus_connection_set_timeout_functions (state->conn, add_timeout,
+ remove_timeout, toggle_timeout, tlsdate_state, dbus_free))
+ {
+ error ("[dbus] dbus_connection_set_timeout_functions failed");
+ /* TODO(wad) disconnect from DBus */
+ goto err;
+ }
+ if (!dbus_connection_set_watch_functions (state->conn, add_watch,
+ remove_watch, toggle_watch, tlsdate_state, dbus_free))
+ {
+ error ("[dbus] dbus_connection_set_watch_functions failed");
+ goto err;
+ }
+ if (!dbus_bus_request_name (state->conn, kServiceInterface, 0, &error) ||
+ dbus_error_is_set (&error))
+ {
+ error ("[dbus] failed to get name: %s", error.message);
+ goto err;
+ }
+
+ /* Setup the vtable for dispatching incoming messages. */
+ if (dbus_connection_register_object_path (
+ state->conn, kServicePath, &service_vtable, tlsdate_state) == FALSE)
+ {
+ error ("[dbus] failed to register object path: %s", kServicePath);
+ goto err;
+ }
+
+ verb_debug ("[dbus] initialized");
+ return 0;
+err:
+ tlsdate_state->dbus = NULL;
+ free (state);
+ return 1;
+}
diff --git a/src/dbus.h b/src/dbus.h
new file mode 100644
index 0000000..296ba86
--- /dev/null
+++ b/src/dbus.h
@@ -0,0 +1,47 @@
+/*
+ * dbus.h - event loop dbus integration
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef DBUS_H_
+#define DBUS_H_
+
+#include "config.h"
+
+#ifdef HAVE_DBUS
+#include <dbus/dbus.h>
+
+#define SET_TIME_OK 0
+#define SET_TIME_INVALID 1
+#define SET_TIME_NOT_ALLOWED 2
+#define SET_TIME_BAD_CALL 3
+
+struct state;
+int init_dbus (struct state *state);
+
+struct dbus_state
+{
+ DBusConnection *conn;
+};
+
+struct dbus_event_data
+{
+ struct dbus_state *state;
+ struct event *event;
+};
+
+void dbus_announce (struct state *);
+
+#else /* !HAVE_DBUS */
+struct state;
+static inline int init_dbus (struct state *state)
+{
+ return 0;
+}
+static inline void dbus_announce (struct state *global_state)
+{
+}
+#endif
+
+#endif /* DBUS_H_ */
diff --git a/src/events/check_continuity.c b/src/events/check_continuity.c
new file mode 100644
index 0000000..9340fa1
--- /dev/null
+++ b/src/events/check_continuity.c
@@ -0,0 +1,77 @@
+/*
+ * check_continuity.c - periodically check local clock deltas
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <time.h>
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+
+/* Returns < 0 on error,
+ * 0 on sync'd,
+ * and > 0 on desync'd.
+ * Old delta is in |delta|. |delta| is overwritten
+ * if >= 0 is returned.
+ *
+ * This event catches any sort of real-time clock jump. A jump is observed
+ * when settimeofday() or adjtimex() is called, or if the RTC misbehaves on
+ * return from suspend. If a jump is detected between a cycle-oriented clock
+ * (MONOTONIC_RAW) and a potentially RTC managed clock (REALTIME), then a
+ * network resynchronization will be required. To avoid requiring this on
+ * every resume-from-suspend, a larger delta represents the largest time jump
+ * allowed before needing a resync.
+ *
+ * Note, CLOCK_BOOTTIME does not resolve this on platforms without a persistent
+ * clock because the RTC still determines the time considered "suspend time".
+ */
+int
+check_continuity (time_t *delta)
+{
+ time_t new_delta;
+ struct timespec monotonic, real;
+ if (clock_gettime (CLOCK_REALTIME, &real) < 0)
+ return -1;
+ if (clock_gettime (CLOCK_MONOTONIC_RAW, &monotonic) < 0)
+ return -1;
+ new_delta = real.tv_sec - monotonic.tv_sec;
+ if (*delta)
+ {
+ /* The allowed delta matches the interval for now. */
+ static const time_t kDelta = CONTINUITY_INTERVAL;
+ if (new_delta < *delta - kDelta || new_delta > *delta + kDelta)
+ {
+ *delta = new_delta;
+ return 1;
+ }
+ }
+ /* First delta after de-sync. */
+ *delta = new_delta;
+ return 0;
+}
+
+/* Sets up a wake event just in case there has not been a wake event
+ * recently enough to catch clock desynchronization. This does not
+ * invalidate the time like the action_invalidate_time event.
+ */
+int setup_event_timer_continuity (struct state *state)
+{
+ struct event *event;
+ struct timeval interval = { state->opts.continuity_interval, 0 };
+ event = event_new (state->base, -1, EV_TIMEOUT|EV_PERSIST,
+ action_kickoff_time_sync, state);
+ if (!event)
+ {
+ error ("Failed to create interval event");
+ return 1;
+ }
+ event_priority_set (event, PRI_WAKE);
+ return event_add (event, &interval);
+}
diff --git a/src/events/kickoff_time_sync.c b/src/events/kickoff_time_sync.c
new file mode 100644
index 0000000..2ed2b0b
--- /dev/null
+++ b/src/events/kickoff_time_sync.c
@@ -0,0 +1,170 @@
+/*
+ * kickoff_time_sync.c - network time synchronization
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#ifdef USE_POLARSSL
+#include <polarssl/entropy.h>
+#include <polarssl/ctr_drbg.h>
+#else
+#include <openssl/rand.h>
+#endif
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+#ifdef USE_POLARSSL
+static int random_init = 0;
+static entropy_context entropy;
+static ctr_drbg_context ctr_drbg;
+static char *pers = "tlsdated";
+#endif
+
+int
+add_jitter (int base, int jitter)
+{
+ int n = 0;
+ if (!jitter)
+ return base;
+#ifdef USE_POLARSSL
+ if (0 == random_init)
+ {
+ entropy_init(&entropy);
+ if (0 > ctr_drbg_init(&ctr_drbg, entropy_func, &entropy,
+ (unsigned char *) pers, strlen(pers)))
+ {
+ pfatal ("Failed to initialize random source");
+ }
+ random_init = 1;
+ }
+ if (0 != ctr_drbg_random(&ctr_drbg, (unsigned char *)&n, sizeof(n)))
+ fatal ("ctr_drbg_random() failed");
+#else
+ if (RAND_bytes ( (unsigned char *) &n, sizeof (n)) != 1)
+ fatal ("RAND_bytes() failed");
+#endif
+ return base + (abs (n) % (2 * jitter)) - jitter;
+}
+
+void
+invalidate_time (struct state *state)
+{
+ state->last_sync_type = SYNC_TYPE_RTC;
+ state->last_time = time (NULL);
+ /* Note(!) this does not invalidate the clock_delta implicitly.
+ * This allows forced invalidation to not lose synchronization
+ * data.
+ */
+}
+
+void
+action_invalidate_time (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ verb_debug ("[event:%s] fired", __func__);
+ /* If time is already invalid and being acquired, do nothing. */
+ if (state->last_sync_type == SYNC_TYPE_RTC &&
+ event_pending (state->events[E_TLSDATE], EV_TIMEOUT, NULL))
+ return;
+ /* Time out our trust in network synchronization but don't persist
+ * the change to disk or notify the system. Let a network sync
+ * failure or success do that.
+ */
+ invalidate_time (state);
+ /* Then trigger a network sync if possible. */
+ action_kickoff_time_sync (-1, EV_TIMEOUT, arg);
+}
+
+int
+setup_event_timer_sync (struct state *state)
+{
+ int wait_time = add_jitter (state->opts.steady_state_interval,
+ state->opts.jitter);
+ struct timeval interval = { wait_time, 0 };
+ state->events[E_STEADYSTATE] = event_new (state->base, -1,
+ EV_TIMEOUT|EV_PERSIST,
+ action_invalidate_time, state);
+ if (!state->events[E_STEADYSTATE])
+ {
+ error ("Failed to create interval event");
+ return 1;
+ }
+ event_priority_set (state->events[E_STEADYSTATE], PRI_ANY);
+ return event_add (state->events[E_STEADYSTATE], &interval);
+}
+
+/* Begins a network synchronization attempt. If the local clocks
+ * are synchronized, then make sure that the _current_ synchronization
+ * source is set to the real-time clock and note that the clock_delta
+ * is unreliable. If the clock was in sync and the last synchronization
+ * source was the network, then this action does nothing.
+ *
+ * In the case of desynchronization, the clock_delta value is used as a
+ * guard to indicate that even if the synchronization source isn't the
+ * network, the source is still tracking the clock delta that was
+ * established from a network source.
+ * TODO(wad) Change the name of clock_delta to indicate that it is the local
+ * clock delta after the last network sync.
+ */
+void action_kickoff_time_sync (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ verb_debug ("[event:%s] fired", __func__);
+ time_t delta = state->clock_delta;
+ int jitter = 0;
+ if (check_continuity (&delta) > 0)
+ {
+ info ("[event:%s] clock delta desync detected (%d != %d)", __func__,
+ state->clock_delta, delta);
+ /* Add jitter iff we had network synchronization once before. */
+ if (state->clock_delta)
+ jitter = add_jitter (30, 30); /* TODO(wad) make configurable */
+ /* Forget the old delta until we have time again. */
+ state->clock_delta = 0;
+ invalidate_time (state);
+ }
+ if (state->last_sync_type == SYNC_TYPE_NET)
+ {
+ verb_debug ("[event:%s] time in sync. skipping", __func__);
+ return;
+ }
+ /* Keep parity with run_tlsdate: for every wake, allow it to retry again. */
+ if (state->tries > 0)
+ {
+ state->tries -= 1;
+ /* Don't bother re-triggering tlsdate */
+ verb_debug ("[event:%s] called while tries are in progress", __func__);
+ return;
+ }
+ /* Don't over-schedule if the first attempt hasn't fired. If a wake event
+ * impacts the result of a proxy resolution, then the updated value can be
+ * acquired on the next run. If the wake comes in after E_TLSDATE is
+ * serviced, then the tries count will be decremented.
+ */
+ if (event_pending (state->events[E_TLSDATE], EV_TIMEOUT, NULL))
+ {
+ verb_debug ("[event:%s] called while tlsdate is pending", __func__);
+ return;
+ }
+ if (!state->events[E_RESOLVER])
+ {
+ trigger_event (state, E_TLSDATE, jitter);
+ return;
+ }
+ /* If the resolver relies on an external response, then make sure that a
+ * tlsdate event is waiting in the wings if the resolver is too slow. Even
+ * if this fires, it won't stop eventual handling of the resolver since it
+ * doesn't event_del() E_RESOLVER.
+ */
+ trigger_event (state, E_TLSDATE, jitter + RESOLVER_TIMEOUT);
+ trigger_event (state, E_RESOLVER, jitter);
+}
diff --git a/src/events/route_up.c b/src/events/route_up.c
new file mode 100644
index 0000000..0691cc7
--- /dev/null
+++ b/src/events/route_up.c
@@ -0,0 +1,93 @@
+/*
+ * route_up.c - wake events for route changes
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/routeup.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+void action_stdin_wakeup (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ char buf[1];
+ verb_debug ("[event:%s] fired", __func__);
+ if (what != EV_READ)
+ return;
+ if (IGNORE_EINTR (read (fd, buf, sizeof (buf))) != sizeof (buf))
+ {
+ error ("[event:%s] unregistering stdin handler - it's broken!",
+ __func__);
+ event_del (state->events[E_ROUTEUP]);
+ return;
+ }
+ action_kickoff_time_sync (-1, EV_TIMEOUT, arg);
+}
+
+void action_netlink_ready (evutil_socket_t fd, short what, void *arg)
+{
+ struct routeup routeup_cfg;
+ verb_debug ("[event:%s] fired", __func__);
+ routeup_cfg.netlinkfd = fd;
+ if (what & EV_READ)
+ {
+ if (routeup_process (&routeup_cfg) == 0)
+ {
+ verb_debug ("[event:%s] routes changed", __func__);
+ /* Fire off a proxy resolution attempt and a new sync request */
+ action_kickoff_time_sync (-1, EV_TIMEOUT, arg);
+ }
+ }
+}
+
+int setup_event_route_up (struct state *state)
+{
+ event_callback_fn handler;
+ int fd = -1;
+ struct routeup routeup_cfg;
+ if (state->opts.should_netlink)
+ {
+ if (routeup_setup (&routeup_cfg))
+ {
+ error ("routeup_setup() failed");
+ return 1;
+ }
+ fd = routeup_cfg.netlinkfd;
+ handler = action_netlink_ready;
+ }
+ else /* Listen for cues from stdin */
+ {
+ fd = STDIN_FILENO;
+ if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ perror ("stdin fcntl(O_NONBLOCK) failed");
+ return 1;
+ }
+ handler = action_stdin_wakeup;
+ }
+ state->events[E_ROUTEUP] = event_new (state->base, fd,
+ EV_READ|EV_PERSIST, handler, state);
+ if (!state->events[E_ROUTEUP])
+ {
+ if (state->opts.should_netlink)
+ {
+ routeup_teardown (&routeup_cfg);
+ }
+ return 1;
+ }
+ event_priority_set (state->events[E_ROUTEUP], PRI_WAKE);
+ event_add (state->events[E_ROUTEUP], NULL);
+ return 0;
+}
diff --git a/src/events/run_tlsdate.c b/src/events/run_tlsdate.c
new file mode 100644
index 0000000..544eb45
--- /dev/null
+++ b/src/events/run_tlsdate.c
@@ -0,0 +1,77 @@
+/*
+ * run_tlsdate.c - events for running tlsdate
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/dbus.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+/* TODO(wad) split out backoff logic to make this testable */
+void action_run_tlsdate (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ verb_debug ("[event:%s] fired", __func__);
+ if (state->last_sync_type == SYNC_TYPE_NET)
+ {
+ verb ("[event:%s] called, but network time isn't needed",
+ __func__);
+ return;
+ }
+ state->resolving = 0;
+ if (state->running)
+ {
+ /* It's possible that a network or proxy change occurred during a call. If
+ * the call succeeded, it doesn't matter. If the call fails, reissuing
+ * the attempt with the new configuration has a chance of succeeding. To
+ * avoid missing a retry, we decrement the try count and reset the
+ * backoff.
+ */
+ if (state->tries > 0)
+ {
+ state->tries--;
+ /* TODO(wad) Make a shorter retry constant for this. */
+ state->backoff = state->opts.wait_between_tries;
+ }
+ info ("[event:%s] requested re-run of tlsdate while tlsdate is running",
+ __func__);
+ return;
+ }
+ /* Enforce maximum retries here instead of in sigchld.c */
+ if (state->tries < state->opts.max_tries)
+ {
+ state->tries++;
+ }
+ else
+ {
+ state->tries = 0;
+ state->backoff = state->opts.wait_between_tries;
+ error ("[event:%s] tlsdate tried and failed to get the time", __func__);
+ return;
+ }
+ state->running = 1;
+ verb ("[event:%s] attempt %d backoff %d", __func__,
+ state->tries, state->backoff);
+ /* Setup a timeout before killing tlsdate */
+ trigger_event (state, E_TLSDATE_TIMEOUT,
+ state->opts.subprocess_wait_between_tries);
+ /* Add the response listener event */
+ trigger_event (state, E_TLSDATE_STATUS, -1);
+ /* Fire off the child process now! */
+ if (tlsdate (state))
+ {
+ /* TODO(wad) Should this be fatal? */
+ error ("[event:%s] tlsdate failed to launch!", __func__);
+ state->running = 0;
+ state->tries = 0;
+ event_del (state->events[E_TLSDATE_TIMEOUT]);
+ return;
+ }
+}
diff --git a/src/events/save.c b/src/events/save.c
new file mode 100644
index 0000000..8fa733e
--- /dev/null
+++ b/src/events/save.c
@@ -0,0 +1,63 @@
+/*
+ * save.c - send new time to the time setter
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+void action_sync_and_save (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ time_t t = state->last_time;
+ ssize_t bytes;
+ verb_debug ("[event:%s] fired", __func__);
+ /* For all non-net sources, don't write to disk by
+ * flagging the time negative. We don't use negative
+ * times and this won't effect shutdown (0) writes.
+ */
+ if (state->last_sync_type != SYNC_TYPE_NET)
+ t = -t;
+ if (what & EV_READ)
+ {
+ /* EPIPE/EBADF notification */
+ error ("[event:%s] time setter is gone!", __func__);
+ /* SIGCHLD will handle teardown. */
+ return;
+ }
+ bytes = IGNORE_EINTR (write (fd, &t, sizeof (t)));
+ if (bytes == -1)
+ {
+ if (errno == EPIPE)
+ {
+ error ("[event:%s] time setter is gone! (EPIPE)", __func__);
+ return;
+ }
+ if (errno == EAGAIN)
+ return; /* Get notified again. */
+ error ("[event:%s] Unexpected errno %d", __func__, errno);
+ }
+ if (bytes != sizeof (t))
+ pfatal ("[event:%s] unexpected write to time setter (%d)",
+ __func__, bytes);
+ /* If we're going down and we wrote the time, send a shutdown message. */
+ if (state->exitting && t)
+ {
+ state->last_time = 0;
+ action_sync_and_save (fd, what, arg);
+ /* TODO(wad) platform->pgrp_kill() ? */
+ }
+ return;
+}
diff --git a/src/events/sigchld.c b/src/events/sigchld.c
new file mode 100644
index 0000000..66d2fe0
--- /dev/null
+++ b/src/events/sigchld.c
@@ -0,0 +1,141 @@
+/*
+ * sigchld.c - event for SIGCHLD
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <event2/event.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+/* Returns 1 if a death was handled, otherwise 0. */
+int
+handle_child_death (struct state *state)
+{
+ siginfo_t info;
+ int ret;
+ info.si_pid = 0;
+ ret = waitid (P_ALL, -1, &info, WEXITED|WNOHANG);
+ if (ret == -1)
+ {
+ if (errno == ECHILD)
+ return 0;
+ perror ("[event:%s] waitid() failed after SIGCHLD", __func__);
+ return 0;
+ }
+ if (info.si_pid == 0)
+ {
+ return 0;
+ }
+ if (info.si_pid == state->setter_pid)
+ {
+ report_setter_error (&info);
+ event_base_loopbreak (state->base);
+ return 1;
+ }
+ if (info.si_pid != state->tlsdate_pid)
+ {
+ error ("[event:%s] SIGCHLD for an unknown process -- "
+ "pid:%d uid:%d status:%d code:%d", __func__,
+ info.si_pid, info.si_uid, info.si_status, info.si_code);
+ return 1;
+ }
+ verb ("[event:%s] tlsdate reaped => "
+ "pid:%d uid:%d status:%d code:%d", __func__,
+ info.si_pid, info.si_uid, info.si_status, info.si_code);
+
+ /* If it was still active, remove it. */
+ event_del (state->events[E_TLSDATE_TIMEOUT]);
+ state->running = 0;
+ state->tlsdate_pid = 0;
+ /* Clean exit - don't rerun! */
+ if (info.si_status == 0)
+ return 1;
+ verb_debug ("[event:%s] scheduling a retry", __func__);
+ /* Rerun a failed tlsdate */
+ if (state->backoff < MAX_SANE_BACKOFF)
+ state->backoff *= 2;
+ /* If there is no resolver, call tlsdate directly. */
+ if (!state->events[E_RESOLVER])
+ {
+ trigger_event (state, E_TLSDATE, state->backoff);
+ return 1;
+ }
+ /* Run tlsdate even if the resolver doesn't come back. */
+ trigger_event (state, E_TLSDATE, RESOLVER_TIMEOUT + state->backoff);
+ /* Schedule the resolver. This is always done after tlsdate in case there
+ * is no resolver.
+ */
+ trigger_event (state, E_RESOLVER, state->backoff);
+ return 1;
+}
+
+/* Returns 1 if a death was handled, otherwise 0. */
+int
+handle_child_stop (struct state *state)
+{
+ /* Handle unexpected external interactions */
+ siginfo_t info;
+ int ret;
+ info.si_pid = 0;
+ ret = waitid (P_ALL, -1, &info, WSTOPPED|WCONTINUED|WNOHANG);
+ if (ret == -1)
+ {
+ if (errno == ECHILD)
+ return 0;
+ perror ("[event:%s] waitid() failed after SIGCHLD", __func__);
+ return 0;
+ }
+ if (info.si_pid == 0)
+ return 0;
+ info ("[event:%s] a child has been STOPPED or CONTINUED. Killing it.",
+ __func__);
+ /* Kill it then catch the next SIGCHLD. */
+ if (kill (info.si_pid, SIGKILL))
+ {
+ if (errno == EPERM)
+ fatal ("[event:%s] cannot terminate STOPPED privileged child",
+ __func__);
+ if (errno == ESRCH)
+ info ("[event:%s] child gone before we could kill it",
+ __func__);
+ }
+ return 1;
+}
+
+void
+action_sigchld (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ verb_debug ("[event:%s] a child process has SIGCHLD'd!", __func__);
+ /* Process SIGCHLDs in two steps: death and stopped until all
+ * pending children are sorted.
+ */
+ if (!handle_child_death (state) && !handle_child_stop (state))
+ verb ("[event:%s] SIGCHLD fired but no children ready!", __func__);
+ while (handle_child_death (state) || handle_child_stop (state));
+}
+
+int
+setup_sigchld_event (struct state *state, int persist)
+{
+ state->events[E_SIGCHLD] = event_new (state->base, SIGCHLD,
+ EV_SIGNAL| (persist ? EV_PERSIST : 0),
+ action_sigchld, state);
+ if (!state->events[E_SIGCHLD])
+ return 1;
+ /* Make sure this is lower than SAVE so we get any error
+ * messages back from the time setter.
+ */
+ event_priority_set (state->events[E_SIGCHLD], PRI_NET);
+ event_add (state->events[E_SIGCHLD], NULL);
+ return 0;
+}
diff --git a/src/events/sigterm.c b/src/events/sigterm.c
new file mode 100644
index 0000000..ff09ab8
--- /dev/null
+++ b/src/events/sigterm.c
@@ -0,0 +1,33 @@
+/*
+ * sigterm.c - handler for SIGTERM
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <sys/time.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+/* On sigterm, grab the system clock and write it before terminating */
+void action_sigterm (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ struct timeval tv;
+ info ("[event:%s] starting graceful shutdown . . .", __func__);
+ state->exitting = 1;
+ if (platform->time_get (&tv))
+ {
+ pfatal ("[event:%s] couldn't gettimeofday to exit gracefully", __func__);
+ }
+ /* Don't change the last sync_type */
+ state->last_time = tv.tv_sec;
+ /* Immediately save and exit. */
+ trigger_event (state, E_SAVE, -1);
+}
diff --git a/src/events/time_set.c b/src/events/time_set.c
new file mode 100644
index 0000000..edc30c9
--- /dev/null
+++ b/src/events/time_set.c
@@ -0,0 +1,174 @@
+/*
+ * time_set.c - time setting functions
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/dbus.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+void
+handle_time_setter (struct state *state, int status)
+{
+ switch (status)
+ {
+ case SETTER_BAD_TIME:
+ info ("[event:%s] time setter received bad time", __func__);
+ /* This is the leaf node. Failure means that our source
+ * tried to walk back in time.
+ */
+ state->last_sync_type = SYNC_TYPE_RTC;
+ state->last_time = time (NULL);
+ break;
+ case SETTER_TIME_SET:
+ info ("[event:%s] time set from the %s (%ld)",
+ __func__, sync_type_str (state->last_sync_type), state->last_time);
+ if (state->last_sync_type == SYNC_TYPE_NET)
+ {
+ /* Update the delta so it doesn't fire again immediately. */
+ state->clock_delta = 0;
+ check_continuity (&state->clock_delta);
+ /* Reset the sources list! */
+ state->opts.cur_source = NULL;
+ }
+ /* Share our success. */
+ if (state->opts.should_dbus)
+ dbus_announce (state);
+ break;
+ case SETTER_NO_SBOX:
+ error ("[event:%s] time setter failed to sandbox", __func__);
+ break;
+ case SETTER_EXIT:
+ error ("[event:%s] time setter exited gracefully", __func__);
+ break;
+ case SETTER_SET_ERR:
+ error ("[event:%s] time setter could not settimeofday()", __func__);
+ break;
+ case SETTER_NO_RTC:
+ error ("[event:%s] time setter could sync rtc", __func__);
+ break;
+ case SETTER_NO_SAVE:
+ error ("[event:%s] time setter could not open save file", __func__);
+ break;
+ case SETTER_READ_ERR:
+ error ("[event:%s] time setter could not read time", __func__);
+ break;
+ default:
+ error ("[event:%s] received bogus status from time setter: %d",
+ __func__, status);
+ exit (status);
+ }
+}
+
+void
+action_time_set (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ int status = -1;
+ ssize_t bytes = 0;
+ verb_debug ("[event:%s] fired", __func__);
+ bytes = IGNORE_EINTR (read (fd, &status, sizeof (status)));
+ if (bytes == -1 && errno == EAGAIN)
+ return; /* Catch next wake up */
+ /* Catch the rest of the errnos and any truncation. */
+ if (bytes != sizeof (status))
+ {
+ /* Truncation of an int over a pipe shouldn't happen except in
+ * terminal cases.
+ */
+ perror ("[event:%s] time setter pipe truncated! (%d)", __func__,
+ bytes);
+ /* Let SIGCHLD do the teardown. */
+ close (fd);
+ return;
+ }
+ handle_time_setter (state, status);
+}
+
+int
+setup_time_setter (struct state *state)
+{
+ struct event *event;
+ int to_fds[2];
+ int from_fds[2];
+ if (pipe (to_fds) < 0)
+ {
+ perror ("pipe failed");
+ return 1;
+ }
+ if (pipe (from_fds) < 0)
+ {
+ perror ("pipe failed");
+ close (to_fds[0]);
+ close (to_fds[1]);
+ return 1;
+ }
+ /* The fd that tlsdated will write to */
+ state->setter_save_fd = to_fds[1];
+ state->setter_notify_fd = from_fds[0];
+ /* Make the notifications fd non-blocking. */
+ if (fcntl (from_fds[0], F_SETFL, O_NONBLOCK) < 0)
+ {
+ perror ("notifier_fd fcntl(O_NONBLOCK) failed");
+ goto close_and_fail;
+ }
+ /* Make writes non-blocking */
+ if (fcntl (to_fds[1], F_SETFL, O_NONBLOCK) < 0)
+ {
+ perror ("save_fd fcntl(O_NONBLOCK) failed");
+ goto close_and_fail;
+ }
+ event = event_new (state->base, from_fds[0], EV_READ|EV_PERSIST,
+ action_time_set, state);
+ if (!event)
+ {
+ error ("Failed to allocate tlsdate setter event");
+ goto close_and_fail;
+ }
+ event_priority_set (event, PRI_NET);
+ event_add (event, NULL);
+ /* fork */
+ state->setter_pid = fork();
+ if (state->setter_pid < 0)
+ {
+ perror ("fork()ing the time setter failed");
+ goto close_and_fail;
+ }
+ if (state->setter_pid == 0)
+ {
+ close (to_fds[1]);
+ close (from_fds[0]);
+ time_setter_coprocess (to_fds[0], from_fds[1], state);
+ _exit (1);
+ }
+ close (from_fds[1]);
+ close (to_fds[0]);
+ return 0;
+
+close_and_fail:
+ close (to_fds[0]);
+ close (to_fds[1]);
+ close (from_fds[0]);
+ close (from_fds[1]);
+ return 1;
+}
diff --git a/src/events/tlsdate_status.c b/src/events/tlsdate_status.c
new file mode 100644
index 0000000..9c6a6a9
--- /dev/null
+++ b/src/events/tlsdate_status.c
@@ -0,0 +1,148 @@
+/*
+ * tlsdate_status.c - handles tlsdate-monitor responses
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+/* Returns < 0 on error, > 0 on eagain, and 0 on success */
+int
+read_tlsdate_response (int fd, time_t *t)
+{
+ /* TLS passes time as a 32-bit value. */
+ uint32_t server_time = 0;
+ ssize_t ret = IGNORE_EINTR (read (fd, &server_time, sizeof (server_time)));
+ if (ret == -1 && errno == EAGAIN)
+ {
+ /* Full response isn't ready yet. */
+ return 1;
+ }
+ if (ret != sizeof (server_time))
+ {
+ /* End of pipe (0) or truncated: death probable. */
+ error ("[event:(%s)] invalid time read from tlsdate (rd:%d,ret:%zd).",
+ __func__, server_time, ret);
+ return -1;
+ }
+ /* uint32_t moves to signed long so there is room for silliness. */
+ *t = server_time;
+ return 0;
+}
+
+void
+action_tlsdate_timeout (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ info ("[event:%s] tlsdate timed out", __func__);
+ /* Force kill it and let action_sigchld rerun. */
+ if (state->tlsdate_pid)
+ kill (state->tlsdate_pid, SIGKILL);
+}
+
+void
+action_tlsdate_status (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ time_t t = 0;
+ int ret = read_tlsdate_response (fd, &t);
+ verb_debug ("[event:%s] fired", __func__);
+ if (ret < 0)
+ {
+ verb_debug ("[event:%s] forcibly timing out tlsdate", __func__);
+ trigger_event (state, E_TLSDATE_TIMEOUT, 0);
+ return;
+ }
+ if (ret)
+ {
+ /* EAGAIN'd: wait for the rest. */
+ trigger_event (state, E_TLSDATE_STATUS, -1);
+ return;
+ }
+ if (is_sane_time (t))
+ {
+ /* Note that last_time is from an online source */
+ state->last_sync_type = SYNC_TYPE_NET;
+ state->last_time = t;
+ trigger_event (state, E_SAVE, -1);
+ }
+ else
+ {
+ error ("[event:%s] invalid time received from tlsdate: %ld",
+ __func__, t);
+ }
+ /* Restore the backoff and tries count on success, insane or not.
+ * On failure, the event handler does it.
+ */
+ state->tries = 0;
+ state->backoff = state->opts.wait_between_tries;
+ return;
+}
+
+/* Returns 0 on success and populates |fds| */
+int
+new_tlsdate_monitor_pipe (int fds[2])
+{
+ if (pipe (fds) < 0)
+ {
+ perror ("pipe failed");
+ return -1;
+ }
+ /* TODO(wad): CLOEXEC, Don't leak these into tlsdate proper. */
+ return 0;
+}
+
+/* Create a fd pair that the tlsdate runner will communicate over */
+int
+setup_tlsdate_status (struct state *state)
+{
+ int fds[2] = { -1, -1 };
+ /* One pair of pipes are reused along with the event. */
+ if (new_tlsdate_monitor_pipe (fds))
+ {
+ return -1;
+ }
+ verb_debug ("[%s] monitor fd pair (%d, %d)", __func__, fds[0], fds[1]);
+ /* The fd that the monitor process will write to */
+ state->tlsdate_monitor_fd = fds[1];
+ /* Make the reader fd non-blocking and not leak into tlsdate. */
+ if (fcntl (fds[0], F_SETFL, O_NONBLOCK|O_CLOEXEC) < 0)
+ {
+ perror ("pipe[0] fcntl(O_NONBLOCK) failed");
+ return 1;
+ }
+ state->events[E_TLSDATE_STATUS] = event_new (state->base, fds[0],
+ EV_READ,
+ action_tlsdate_status, state);
+ if (!state->events[E_TLSDATE_STATUS])
+ {
+ error ("Failed to allocate tlsdate status event");
+ return 1;
+ }
+ event_priority_set (state->events[E_TLSDATE_STATUS], PRI_NET);
+ state->events[E_TLSDATE_TIMEOUT] = event_new (state->base, -1,
+ EV_TIMEOUT,
+ action_tlsdate_timeout, state);
+ if (!state->events[E_TLSDATE_TIMEOUT])
+ {
+ error ("Failed to allocate tlsdate timeout event");
+ return 1;
+ }
+ event_priority_set (state->events[E_TLSDATE_TIMEOUT], PRI_SAVE);
+ return 0;
+}
diff --git a/src/include.am b/src/include.am
new file mode 100644
index 0000000..ec091e5
--- /dev/null
+++ b/src/include.am
@@ -0,0 +1,489 @@
+# vim:ft=automake
+
+src_tlsdate_SOURCES=
+src_tlsdate_LDADD=
+
+src_tlsdate_helper_CFLAGS=
+src_tlsdate_helper_SOURCES=
+src_tlsdate_helper_LDADD=
+
+include src/compat/include.am
+
+# Our main program
+if TARGET_LINUX
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+if HAVE_SECCOMP_FILTER
+src_tlsdate_helper_SOURCES+= src/seccomp.c
+endif
+
+sbin_PROGRAMS+= src/tlsdated
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+
+if HAVE_ANDROID
+src_conf_unittest_SOURCES+= src/common/android.c src/common/fmemopen.c
+endif
+
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif # TARGET_LINUX
+
+if TARGET_GNUKFREEBSD
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+if !HAVE_STRCHRNUL
+src_conf_unittest_SOURCES+= src/common/android.c
+endif
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+
+if TARGET_FREEBSD
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+if !HAVE_STRCHRNUL
+src_conf_unittest_SOURCES+= src/common/android.c
+endif
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+
+if TARGET_NETBSD
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+src_conf_unittest_SOURCES+= src/common/android.c
+
+# XXX This conditional should apply for any system where we're building
+# conf_unittest, but I don't know how to tell that to automake.
+if !HAVE_FMEMOPEN
+if HAVE_FUNOPEN
+src_conf_unittest_SOURCES+= src/common/fmemopen-funopen.c
+endif
+endif
+
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+
+if TARGET_OPENBSD
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+src_conf_unittest_SOURCES+= src/common/android.c
+src_conf_unittest_SOURCES+= src/common/fmemopen.c
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+
+if TARGET_DRAGONFLYBSD
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+src_conf_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+
+if TARGET_BSD
+if !TARGET_FREEBSD
+if !TARGET_NETBSD
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+endif
+endif
+
+if TARGET_GNUHURD
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+src_conf_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+
+if TARGET_CYGWIN
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+src_conf_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+
+if TARGET_MINGW
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+src_conf_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+
+if TARGET_HAIKU
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+src_conf_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+
+if TARGET_OSX
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+endif
+
+src_tlsdate_SOURCES+= src/tlsdate.c
+src_tlsdate_CFLAGS = -DBUILDING_TLSDATE
+
+src_tlsdate_helper_CFLAGS+= @SSL_CFLAGS@
+src_tlsdate_helper_LDADD+= @SSL_LIBS@
+src_tlsdate_helper_LDADD+= src/compat/libtlsdate_compat.la
+src_tlsdate_helper_SOURCES+= src/tlsdate-helper.c
+
+if POLARSSL
+src_tlsdate_helper_SOURCES+= src/proxy-polarssl.c
+else
+# OpenSSL is our default if we're not using PolarSSL
+src_tlsdate_helper_SOURCES+= src/proxy-bio.c
+endif
+src_tlsdate_helper_SOURCES+= src/util.c
+
+if !HAVE_STRNLEN
+src_tlsdate_helper_SOURCES+= src/common/strnlen.c
+endif
+
+# This doesn't work on Mac OS X
+if TARGET_LINUX
+
+src_tlsdated_CFLAGS = $(DBUS_CFLAGS) $(LIBEVENT_CFLAGS) @SSL_CFLAGS@
+src_tlsdated_CPPFLAGS = -DTLSDATED_MAIN -DWITH_EVENTS
+if SECCOMP_FILTER_DEBUG
+src_tlsdated_CPPFLAGS += -DSECCOMP_FILTER_DEBUG=1
+endif
+src_tlsdated_LDADD = @SSL_LIBS@ $(RT_LIB) $(DBUS_LIBS) $(LIBEVENT_LIBS)
+src_tlsdated_SOURCES = src/conf.c
+
+if HAVE_ANDROID
+src_tlsdated_SOURCES+= src/common/android.c
+endif
+
+# This doesn't work on Mac OS X or FreeBSD
+if TARGET_LINUX
+src_tlsdated_SOURCES+= src/routeup.c
+endif
+
+if HAVE_DBUS
+src_tlsdated_SOURCES+= src/dbus.c
+endif
+if HAVE_CROS
+src_tlsdated_SOURCES+= src/platform-cros.c
+endif
+if HAVE_SECCOMP_FILTER
+src_tlsdated_SOURCES+= src/seccomp.c
+endif
+src_tlsdated_SOURCES+= src/tlsdate-monitor.c
+src_tlsdated_SOURCES+= src/tlsdate-setter.c
+src_tlsdated_SOURCES+= src/tlsdated.c
+src_tlsdated_SOURCES+= src/util.c
+src_tlsdated_SOURCES+= src/events/check_continuity.c
+src_tlsdated_SOURCES+= src/events/kickoff_time_sync.c
+src_tlsdated_SOURCES+= src/events/route_up.c
+src_tlsdated_SOURCES+= src/events/run_tlsdate.c
+src_tlsdated_SOURCES+= src/events/sigterm.c
+src_tlsdated_SOURCES+= src/events/sigchld.c
+src_tlsdated_SOURCES+= src/events/save.c
+src_tlsdated_SOURCES+= src/events/time_set.c
+src_tlsdated_SOURCES+= src/events/tlsdate_status.c
+
+src_tlsdated_unittest_CFLAGS = $(DBUS_CFLAGS) $(LIBEVENT_CFLAGS)
+src_tlsdated_unittest_CPPFLAGS = -DWITH_EVENTS
+if SECCOMP_FILTER_DEBUG
+src_tlsdated_unittest_CPPFLAGS += -DSECCOMP_FILTER_DEBUG=1
+endif
+src_tlsdated_unittest_LDADD = @SSL_LIBS@ $(RT_LIB) $(DBUS_LIBS) $(LIBEVENT_LIBS)
+src_tlsdated_unittest_SOURCES = src/tlsdated-unittest.c
+src_tlsdated_unittest_SOURCES+= $(src_tlsdated_SOURCES)
+
+check_PROGRAMS+= src/tlsdated_unittest
+noinst_PROGRAMS+= src/tlsdated_unittest
+endif
+
+# This doesn't work on Mac OS X
+if TARGET_LINUX
+if !POLARSSL
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+if HAVE_SECCOMP_FILTER
+src_proxy_bio_unittest_SOURCES+= src/seccomp.c
+endif
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+endif
+
+if TARGET_FREEBSD
+if !POLARSSL
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+if !HAVE_STRCHRNUL
+src_proxy_bio_unittest_SOURCES+= src/common/android.c
+endif
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+# XXX This conditional should apply for any system where we're building
+# conf_unittest, but I don't know how to tell that to automake.
+if !HAVE_FMEMOPEN
+if HAVE_FUNOPEN
+src_conf_unittest_SOURCES+= src/common/fmemopen-funopen.c
+endif
+endif
+endif
+
+if TARGET_NETBSD
+if !POLARSSL
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+src_proxy_bio_unittest_SOURCES+= src/common/android.c
+
+# XXX This conditional should apply for any system where we're building
+# proxy_bio_unittest, but I don't know how to tell that to automake.
+if !HAVE_STRNLEN
+src_proxy_bio_unittest_SOURCES+= src/common/strnlen.c
+endif
+
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+endif
+
+if TARGET_OPENBSD
+if !POLARSSL
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+src_proxy_bio_unittest_SOURCES+= src/common/android.c
+src_proxy_bio_unittest_SOURCES+= src/common/fmemopen.c
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+endif
+
+if TARGET_DRAGONFLYBSD
+if !POLARSSL
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+src_proxy_bio_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+endif
+
+if TARGET_BSD
+if !POLARSSL
+if !TARGET_FREEBSD
+if !TARGET_NETBSD
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+endif
+endif
+endif
+
+if TARGET_GNUHURD
+if !POLARSSL
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+src_proxy_bio_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+endif
+
+if TARGET_CYGWIN
+if !POLARSSL
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+src_proxy_bio_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+endif
+
+if TARGET_MINGW
+if !POLARSSL
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+src_proxy_bio_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+endif
+
+if TARGET_HAIKU
+if !POLARSSL
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+src_proxy_bio_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+endif
+endif
+
+# We're not shipping headers
+noinst_HEADERS+= src/routeup.h
+noinst_HEADERS+= src/test_harness.h
+noinst_HEADERS+= src/tlsdate-helper.h
+noinst_HEADERS+= src/seccomp.h
+noinst_HEADERS+= src/seccomp-compat.h
+noinst_HEADERS+= src/tlsdate.h
+noinst_HEADERS+= src/util.h
+noinst_HEADERS+= src/visibility.h
+noinst_HEADERS+= src/proxy-bio.h
+noinst_HEADERS+= src/proxy-polarssl.h
+noinst_HEADERS+= src/test-bio.h
+noinst_HEADERS+= src/conf.h
+noinst_HEADERS+= src/dbus.h
+noinst_HEADERS+= src/platform.h
+
+if HAVE_ANDROID
+noinst_HEADERS+= src/common/android.h
+endif
+
+# This is our explicit target list
+# We do not attempt to build with PolarSSL
+if !POLARSSL
+if !TARGET_LINUX
+if !TARGET_OSX
+if !TARGET_OPENBSD
+if !TARGET_NETBSD
+if !TARGET_FREEBSD
+if !TARGET_DRAGONFLYBSD
+if !TARGET_HAIKU
+if !TARGET_GNUHURD
+if !TARGET_CYGWIN
+if !TARGET_MINGW
+if !TARGET_BSD
+bin_PROGRAMS+= src/tlsdate
+bin_PROGRAMS+= src/tlsdate-helper
+
+src_conf_unittest_SOURCES = src/conf.c
+src_conf_unittest_SOURCES+= src/conf-unittest.c
+src_conf_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/conf_unittest
+noinst_PROGRAMS+= src/conf_unittest
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+
+if !POLARSSL
+if !TARGET_LINUX
+if !TARGET_OSX
+if !TARGET_OPENBSD
+if !TARGET_NETBSD
+if !TARGET_FREEBSD
+if !TARGET_GNUKFREEBSD
+if !TARGET_DRAGONFLYBSD
+if !TARGET_HAIKU
+if !TARGET_GNUHURD
+if !TARGET_CYGWIN
+if !TARGET_MINGW
+if !TARGET_BSD
+src_proxy_bio_unittest_LDADD = @SSL_LIBS@
+src_proxy_bio_unittest_SOURCES = src/proxy-bio.c
+src_proxy_bio_unittest_SOURCES+= src/proxy-bio-unittest.c
+src_proxy_bio_unittest_SOURCES+= src/test-bio.c
+src_proxy_bio_unittest_SOURCES+= src/util.c
+src_proxy_bio_unittest_SOURCES+= src/common/android.c
+check_PROGRAMS+= src/proxy-bio_unittest
+noinst_PROGRAMS+= src/proxy-bio_unittest
+
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+
+
+check_PROGRAMS+= src/test/proxy-override src/test/check-host-1 \
+ src/test/check-host-2 src/test/sleep-wrap \
+ src/test/return-argc src/test/emit
diff --git a/src/platform-cros.c b/src/platform-cros.c
new file mode 100644
index 0000000..5a9d7ab
--- /dev/null
+++ b/src/platform-cros.c
@@ -0,0 +1,613 @@
+/*
+ * platform-cros.c - CrOS platform DBus integration
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "config.h"
+
+#include <ctype.h>
+#include <dbus/dbus.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+
+#include <event2/event.h>
+
+#include "src/dbus.h"
+#include "src/platform.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+static const char kMatchFormatData[] = "interface='%s',member='%s',arg0='%s'";
+static const char *kMatchFormat = kMatchFormatData;
+static const char kMatchNoArgFormatData[] = "interface='%s',member='%s'";
+static const char *kMatchNoArgFormat = kMatchNoArgFormatData;
+
+static const char kLibCrosDestData[] = "org.chromium.LibCrosService";
+static const char *kLibCrosDest = kLibCrosDestData;
+static const char kLibCrosInterfaceData[] = "org.chromium.LibCrosServiceInterface";
+static const char *kLibCrosInterface = kLibCrosInterfaceData;
+static const char kLibCrosPathData[] = "/org/chromium/LibCrosService";
+static const char *kLibCrosPath = kLibCrosPathData;
+static const char kResolveNetworkProxyData[] = "ResolveNetworkProxy";
+static const char *kResolveNetworkProxy = kResolveNetworkProxyData;
+
+static const char kDBusInterfaceData[] = "org.freedesktop.DBus";
+static const char *kDBusInterface = kDBusInterfaceData;
+static const char kNameOwnerChangedData[] = "NameOwnerChanged";
+static const char *kNameOwnerChanged = kNameOwnerChangedData;
+static const char kNameAcquiredData[] = "NameAcquired";
+static const char *kNameAcquired = kNameAcquiredData;
+
+static const char kManagerInterfaceData[] = "org.chromium.flimflam.Manager";
+static const char *kManagerInterface = kManagerInterfaceData;
+
+static const char kServiceInterfaceData[] = "org.chromium.flimflam.Service";
+static const char *kServiceInterface = kServiceInterfaceData;
+static const char kMemberData[] = "PropertyChanged";
+static const char *kMember = kMemberData;
+
+static const char kProxyConfigData[] = "ProxyConfig";
+static const char *kProxyConfig = kProxyConfigData;
+static const char kDefaultServiceData[] = "DefaultService";
+static const char *kDefaultService = kDefaultServiceData;
+
+static const char kResolveInterfaceData[] = "org.torproject.tlsdate.Resolver";
+static const char *kResolveInterface = kResolveInterfaceData;
+static const char kResolveMemberData[] = "ProxyChange";
+static const char *kResolveMember = kResolveMemberData;
+
+/* TODO(wad) Integrate with cros_system_api/dbus/service_constants.h */
+static const char kPowerManagerInterfaceData[] = "org.chromium.PowerManager";
+static const char *kPowerManagerInterface = kPowerManagerInterfaceData;
+static const char kSuspendDoneData[] = "SuspendDone";
+static const char *kSuspendDone = kSuspendDoneData;
+
+static const char kErrorServiceUnknownData[] = "org.freedesktop.DBus.Error.ServiceUnknown";
+static const char *kErrorServiceUnknown = kErrorServiceUnknownData;
+
+struct platform_state
+{
+ struct event_base *base;
+ struct state *state;
+ DBusMessage **resolve_msg;
+ int resolve_msg_count;
+ uint32_t resolve_network_proxy_serial;
+};
+
+static
+bool
+get_valid_hostport (const char *hostport, char *out, size_t len)
+{
+ bool host = true;
+ const char *end = hostport + strlen (hostport);
+ const char *c;
+ *out = '\0';
+ /* Hosts begin with alphanumeric only. */
+ if (!isalnum (*hostport))
+ {
+ info ("Host does not start with alnum");
+ return false;
+ }
+ *out++ = *hostport;
+ for (c = hostport + 1; c < end && len > 0; ++c, ++out, --len)
+ {
+ *out = *c;
+ if (host)
+ {
+ if (isalnum (*c) || *c == '-' || *c == '.')
+ {
+ continue;
+ }
+ if (*c == ':')
+ {
+ host = false;
+ continue;
+ }
+ }
+ else
+ {
+ if (isdigit (*c))
+ continue;
+ }
+ *out = '\0';
+ return false;
+ }
+ *out = '\0';
+ return true;
+}
+
+/* Convert PAC return format to tlsdated url format */
+/* TODO(wad) support multiple proxies when Chromium does:
+ * PROXY x.x.x.x:yyyy; PROXY z.z.z.z:aaaaa
+ */
+static
+void
+canonicalize_pac (const char *pac_fmt, char *proxy_url, size_t len)
+{
+ size_t type_len;
+ size_t copied = 0;
+ const char *space;
+ /* host[255]:port[6]\0 */
+ char hostport[6 + 255 + 2];
+ proxy_url[0] = '\0';
+ if (len < 1)
+ return;
+ if (!strcmp (pac_fmt, "DIRECT"))
+ {
+ return;
+ }
+ /* Find type */
+ space = strchr (pac_fmt, ' ');
+ if (!space)
+ return;
+ type_len = space - pac_fmt;
+ if (!get_valid_hostport (space + 1, hostport, sizeof (hostport)))
+ {
+ error ("invalid host:port: %s", space + 1);
+ return;
+ }
+ proxy_url[0] = '\0';
+ if (!strncmp (pac_fmt, "PROXY", type_len))
+ {
+ copied = snprintf (proxy_url, len, "http://%s", hostport);
+ }
+ else if (!strncmp (pac_fmt, "SOCKS", type_len))
+ {
+ copied = snprintf (proxy_url, len, "socks4://%s", hostport);
+ }
+ else if (!strncmp (pac_fmt, "SOCKS5", type_len))
+ {
+ copied = snprintf (proxy_url, len, "socks5://%s", hostport);
+ }
+ else if (!strncmp (pac_fmt, "HTTPS", type_len))
+ {
+ copied = snprintf (proxy_url, len, "https://%s", hostport);
+ }
+ else
+ {
+ error ("pac_fmt unmatched: '%s' %zu", pac_fmt, type_len);
+ }
+ if (copied >= len)
+ {
+ error ("canonicalize_pac: truncation '%s'", proxy_url);
+ proxy_url[0] = '\0';
+ return;
+ }
+}
+
+static
+DBusHandlerResult
+handle_service_change (DBusConnection *connection,
+ DBusMessage *message,
+ struct platform_state *ctx)
+{
+ DBusMessageIter iter, subiter;
+ DBusError error;
+ const char *pname;
+ const char *pval;
+ const char *service;
+ dbus_error_init (&error);
+ verb_debug ("[event:cros:%s]: fired", __func__);
+ /* TODO(wad) Track the current DefaultService only fire when it changes */
+ service = dbus_message_get_path (message);
+ if (!service)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ /* Shill emits string:ProxyConfig variant string:"..." */
+ if (!dbus_message_iter_init (message, &iter))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_iter_get_basic (&iter, &pname);
+ /* Make sure we are only firing on a ProxyConfig property change. */
+ if (strcmp (pname, kProxyConfig))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ if (!dbus_message_iter_next (&iter))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_iter_recurse (&iter, &subiter);
+ if (dbus_message_iter_get_arg_type (&subiter) != DBUS_TYPE_STRING)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_iter_get_basic (&subiter, &pval);
+ /* Right now, nothing is done with the Shill proxy value because
+ * Chromium handles .pac resolution. This may be more useful for
+ * ignoring incomplete proxy values sent while a user is typing.
+ */
+ action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+handle_manager_change (DBusConnection *connection,
+ DBusMessage *message,
+ struct platform_state *ctx)
+{
+ DBusMessageIter iter, subiter;
+ DBusError error;
+ const char *pname;
+ const char *pval;
+ verb_debug ("[event:cros:%s]: fired", __func__);
+ dbus_error_init (&error);
+ if (!dbus_message_iter_init (message, &iter))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_iter_get_basic (&iter, &pname);
+ /* Make sure we caught the right property. */
+ if (strcmp (pname, kDefaultService))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ if (!dbus_message_iter_next (&iter))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_iter_recurse (&iter, &subiter);
+ if (dbus_message_iter_get_arg_type (&subiter) != DBUS_TYPE_OBJECT_PATH)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_iter_get_basic (&subiter, &pval);
+ /* TODO(wad) Filter on the currently active service in pval. */
+ verb_debug ("[event:cros:%s] service change on path %s",
+ __func__, pval);
+ action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+handle_suspend_done (DBusConnection *connection,
+ DBusMessage *message,
+ struct platform_state *ctx)
+{
+ DBusMessageIter iter;
+ DBusError error;
+ const char *pname;
+ verb_debug ("[event:cros:%s]: fired", __func__);
+ /* Coming back from resume, trigger a continuity and time
+ * check just in case none of the other events happen.
+ */
+ action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+handle_proxy_change (DBusConnection *connection,
+ DBusMessage *message,
+ struct platform_state *ctx)
+{
+ DBusMessageIter iter;
+ DBusError error;
+ const char *pname;
+ const char *pval;
+ char time_host[MAX_PROXY_URL];
+ int url_len = 0;
+ struct source *src = ctx->state->opts.sources;
+ verb_debug ("[event:cros:%s]: fired", __func__);
+ if (ctx->state->opts.cur_source && ctx->state->opts.cur_source->next)
+ src = ctx->state->opts.cur_source->next;
+ if (!ctx->state->resolving)
+ {
+ info ("[event:cros:%s] Unexpected ResolveNetworkProxy signal seen",
+ __func__);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ dbus_error_init (&error);
+ /* Shill emits string:ProxyConfig variant string:"..." */
+ if (!dbus_message_iter_init (message, &iter))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_iter_get_basic (&iter, &pname);
+ /* Make sure this was the resolution we asked for */
+ url_len = snprintf (time_host, sizeof (time_host), "https://%s:%s",
+ src->host, src->port);
+ if (url_len >= sizeof (time_host))
+ {
+ error ("[event:cros:%s]: current source url is too long",
+ __func__);
+ }
+ if (strcmp (pname, time_host))
+ {
+ error ("[event:cros:%s]: resolved host mismatch: %s v %s",
+ __func__, pname, time_host);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ if (!dbus_message_iter_next (&iter))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_iter_get_basic (&iter, &pval);
+ ctx->state->resolving = 0;
+ canonicalize_pac (pval, ctx->state->dynamic_proxy, sizeof (ctx->state->dynamic_proxy));
+ trigger_event (ctx->state, E_TLSDATE, 1);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+handle_dbus_change (DBusConnection *connection,
+ DBusMessage *message,
+ struct platform_state *ctx)
+{
+ DBusMessageIter iter;
+ DBusError error;
+ const char *pname;
+ verb_debug ("[event:cros:%s]: fired", __func__);
+ dbus_error_init (&error);
+ if (!dbus_message_iter_init (message, &iter))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_iter_get_basic (&iter, &pname);
+ /* Make sure we caught the right property. */
+ if (strcmp (pname, kLibCrosDest))
+ return DBUS_HANDLER_RESULT_HANDLED;
+ action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+void
+action_resolve_proxy (evutil_socket_t fd, short what, void *arg)
+{
+ struct platform_state *ctx = arg;
+ struct dbus_state *dbus_state = ctx->state->dbus;
+ DBusConnection *conn = dbus_state->conn;
+ struct source *src = ctx->state->opts.sources;
+ verb_debug ("[event:%s] fired", __func__);
+ /* Emulate tlsdate-monitor.c:build_argv and choose the next source */
+ if (ctx->state->opts.cur_source && ctx->state->opts.cur_source->next)
+ src = ctx->state->opts.cur_source->next;
+ if (ctx->state->resolving || ctx->resolve_network_proxy_serial)
+ {
+ /* Note, this is not the same as the response signal. It just avoids
+ * multiple requests in a single dispatch window.
+ */
+ info ("[event:%s] no resolve_proxy sent; pending method_reply",
+ __func__);
+ return;
+ }
+ ctx->state->dynamic_proxy[0] = '\0';
+ if (ctx->resolve_msg[src->id] == NULL)
+ {
+ info ("[event:%s] no dynamic proxy for %s:%s", __func__,
+ src->host, src->port);
+ trigger_event (ctx->state, E_TLSDATE, 1);
+ return;
+ }
+ info ("[event:%s] resolving proxy for %s:%s", __func__,
+ src->host, src->port);
+ ctx->state->resolving = 1;
+ if (!dbus_connection_send (conn,
+ ctx->resolve_msg[src->id],
+ &ctx->resolve_network_proxy_serial))
+ {
+ error ("[event:%s] cannot send ResolveNetworkProxy query!", __func__);
+ return;
+ }
+}
+
+static
+DBusHandlerResult
+dbus_filter (DBusConnection *connection, DBusMessage *message, void *data)
+{
+ struct platform_state *state = data;
+ /* Terminate gracefully if DBus goes away. */
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected"))
+ {
+ error ("[cros] DBus system bus has become inaccessible. Terminating.");
+ /* Trigger a graceful teardown. */
+ kill (getpid(), SIGINT);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ /* Hand it over to the service dispatcher. */
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ /* Handle explicitly defined signals only. */
+ if (dbus_message_is_signal (message, kDBusInterface, kNameAcquired))
+ {
+ info ("[cros] DBus name acquired successfully");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ if (dbus_message_is_signal (message, kServiceInterface, kMember))
+ return handle_service_change (connection, message, state);
+ if (dbus_message_is_signal (message, kManagerInterface, kMember))
+ return handle_manager_change (connection, message, state);
+ if (dbus_message_is_signal (message, kResolveInterface, kResolveMember))
+ return handle_proxy_change (connection, message, state);
+ if (dbus_message_is_signal (message, kDBusInterface, kNameOwnerChanged))
+ return handle_dbus_change (connection, message, state);
+ if (dbus_message_is_signal (message, kPowerManagerInterface, kSuspendDone))
+ return handle_suspend_done (connection, message, state);
+ if (dbus_message_is_error (message, kErrorServiceUnknown))
+ {
+ info ("[cros] org.chromium.LibCrosService.ResolveNetworkProxy is missing");
+ info ("[cros] skipping proxy resolution for now");
+ /* Fire off tlsdate rather than letting it fail silently. */
+ state->resolve_network_proxy_serial = 0;
+ state->state->resolving = 0;
+ trigger_event (state->state, E_TLSDATE, 1);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ /* Indicates a successful resolve request was issued. */
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ {
+ uint32_t serial = dbus_message_get_reply_serial (message);
+ if (serial == state->resolve_network_proxy_serial)
+ {
+ state->resolve_network_proxy_serial = 0;
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ info ("[cros] unknown DBus METHOD_RETURN seen: %u", serial);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ verb_debug ("[cros] unknown message received: "
+ "type=%s dest=%s interface=%s member=%s path=%s sig=%s error_name=%s",
+ dbus_message_type_to_string (dbus_message_get_type (message)),
+ dbus_message_get_destination (message),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message),
+ dbus_message_get_path (message),
+ dbus_message_get_signature (message),
+ dbus_message_get_error_name (message));
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int
+add_match (DBusConnection *conn, const char *interface, const char *member,
+ const char *arg0)
+{
+ char match[1024];
+ DBusError error;
+ int len;
+ dbus_error_init (&error);
+ if (arg0)
+ {
+ len = snprintf (match, sizeof (match), kMatchFormat,
+ interface, member, arg0);
+ }
+ else
+ {
+ len = snprintf (match, sizeof (match), kMatchNoArgFormat,
+ interface, member);
+ }
+ if (len >= sizeof (match) || len < 0)
+ {
+ error ("[dbus] match truncated for '%s,%s'", interface, member);
+ return 1;
+ }
+ dbus_bus_add_match (conn, match, &error);
+ if (dbus_error_is_set (&error))
+ {
+ error ("[dbus] failed to add_match for '%s,%s'; error: %s, %s",
+ interface, member, error.name, error.message);
+ dbus_error_free (&error);
+ return 1;
+ }
+ return 0;
+}
+
+DBusMessage *
+new_resolver_message(const struct source *src)
+{
+ char time_host[MAX_PROXY_URL];
+ void *time_host_ptr = &time_host;
+ int url_len;
+ DBusMessage *res;
+ DBusMessageIter args;
+ if (!src->proxy || strcmp (src->proxy, "dynamic"))
+ {
+ return NULL;
+ }
+ res = dbus_message_new_method_call (kLibCrosDest, kLibCrosPath,
+ kLibCrosInterface, kResolveNetworkProxy);
+ if (!res)
+ {
+ error ("[cros] could not setup dynamic proxy for source %d", src->id);
+ return NULL;
+ }
+ /* Build the time_host */
+ url_len = snprintf (time_host, sizeof (time_host), "https://%s:%s",
+ src->host, src->port);
+ if (url_len >= sizeof (time_host))
+ {
+ fatal ("[cros] source %d url is too long! (%d)", src->id, url_len);
+ }
+ /* Finish the message */
+ dbus_message_iter_init_append (res, &args);
+ if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &time_host_ptr) ||
+ !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &kResolveInterface) ||
+ !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &kResolveMember))
+ {
+ fatal ("[cros could not append arguments for resolver message");
+ }
+ return res;
+}
+
+int
+platform_init_cros (struct state *state)
+{
+ /* Watch for per-service ProxyConfig property changes */
+ struct event_base *base = state->base;
+ struct dbus_state *dbus_state = state->dbus;
+ struct source *src = NULL;
+ int sources = 0;
+ DBusConnection *conn = dbus_state->conn;
+ DBusError error;
+ struct platform_state *platform_state =
+ calloc (1, sizeof (struct platform_state));
+ if (!platform_state)
+ {
+ error ("[cros] could not allocate platform_state");
+ return -1;
+ }
+ /* TODO(wad) Follow up with dbus_error_free() where needed. */
+ dbus_error_init (&error);
+ /* Add watches for: proxy changes, default service changes, proxy resolution,
+ * LibCrosService ownership, and power state changes.
+ */
+ if (add_match (conn, kServiceInterface, kMember, kProxyConfig) ||
+ add_match (conn, kManagerInterface, kMember, kDefaultService) ||
+ add_match (conn, kResolveInterface, kResolveMember, NULL) ||
+ add_match (conn, kDBusInterface, kNameOwnerChanged, kLibCrosDest) ||
+ add_match (conn, kPowerManagerInterface, kSuspendDone, NULL))
+ return 1;
+
+ /* Allocate one per source */
+ for (src = state->opts.sources; src; src = src->next, ++sources);
+ platform_state->resolve_msg_count = sources;
+ platform_state->resolve_msg = calloc (sources, sizeof (DBusMessage *));
+ if (!platform_state->resolve_msg)
+ {
+ error ("[cros] cannot allocate resolver messages");
+ free (platform_state);
+ return -1;
+ }
+ for (src = state->opts.sources; src; src = src->next)
+ {
+ if (src->id >= sources)
+ fatal ("Source ID is greater than available sources!");
+ platform_state->resolve_msg[src->id] = new_resolver_message (src);
+ if (platform_state->resolve_msg[src->id])
+ src->proxy = state->dynamic_proxy;
+ }
+ state->dynamic_proxy[0] = '\0';
+ if (state->opts.proxy && !strcmp (state->opts.proxy, "dynamic"))
+ {
+ info ("[cros] default dynamic proxy support");
+ state->opts.proxy = state->dynamic_proxy;
+ }
+ platform_state->base = base;
+ platform_state->state = state;
+ /* Add the dynamic resolver if tlsdate doesn't already have one. */
+ if (!state->events[E_RESOLVER])
+ {
+ state->events[E_RESOLVER] = event_new (base, -1, EV_TIMEOUT,
+ action_resolve_proxy,
+ platform_state);
+ if (!state->events[E_RESOLVER])
+ /* Let's not clean up DBus. */
+ fatal ("Could not allocated resolver event");
+ /* Wake up as a NET event since it'll self-block until DBus has a chance
+ * to send it.
+ */
+ event_priority_set (state->events[E_RESOLVER], PRI_NET);
+ }
+ /* Each platform can attach their own filter, but the filter func needs to be
+ * willing to DBUS_HANDLER_RESULT_NOT_YET_HANDLED on unexpected events.
+ */
+ /* TODO(wad) add the clean up function as the callback. */
+ if (!dbus_connection_add_filter (conn,
+ dbus_filter, platform_state, NULL))
+ {
+ error ("Failed to register signal handler callback");
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/platform.h b/src/platform.h
new file mode 100644
index 0000000..f17efa2
--- /dev/null
+++ b/src/platform.h
@@ -0,0 +1,21 @@
+/*
+ * platform.h - platform handlers for event loops
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef PLATFORM_H_
+#define PLATFORM_H_
+#include "config.h"
+
+struct state;
+
+#ifdef HAVE_CROS
+int platform_init_cros (struct state *state);
+#else
+static inline int platform_init_cros (struct state *state)
+{
+ return 0;
+}
+#endif /* HAVE_CROS */
+#endif /* PLATFORM_H_ */
diff --git a/src/proxy-bio-plan9.c b/src/proxy-bio-plan9.c
new file mode 100644
index 0000000..98d3f97
--- /dev/null
+++ b/src/proxy-bio-plan9.c
@@ -0,0 +1,449 @@
+/*
+ * proxy-bio.c - BIO layer for SOCKS4a/5 proxy connections
+ *
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * This file implements a SOCKS4a/SOCKS5 "filter" BIO. In SSL terminology, a BIO
+ * is a stackable IO filter, kind of like sysv streams. These filters are
+ * inserted into a stream to cause it to run SOCKS over whatever transport is
+ * being used. Most commonly, this would be:
+ * SSL BIO (filter) -> SOCKS BIO (filter) -> connect BIO (source/sink)
+ * This configuration represents doing an SSL connection through a SOCKS proxy,
+ * which is itself connected to in plaintext. You might also do:
+ * SSL BIO -> SOCKS BIO -> SSL BIO -> connect BIO
+ * This is an SSL connection through a SOCKS proxy which is itself reached over
+ * SSL.
+ */
+
+#include <arpa/inet.h>
+#include <assert.h>
+#ifndef __USE_MISC
+#define __USE_MISC
+#endif
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+
+#ifndef UINT8_MAX
+#define UINT8_MAX (255)
+#endif
+
+#include <netdb.h>
+
+#include <inttypes.h>
+
+#include "src/proxy-bio-plan9.h"
+
+int socks4a_connect(BIO *b);
+int socks5_connect(BIO *b);
+int http_connect(BIO *b);
+
+int proxy_new(BIO *b)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) malloc(sizeof *ctx);
+ if (!ctx)
+ return 0;
+ ctx->connected = 0;
+ ctx->connect = NULL;
+ ctx->host = NULL;
+ ctx->port = 0;
+ b->init = 1;
+ b->flags = 0;
+ b->ptr = ctx;
+ return 1;
+}
+
+int proxy_free(BIO *b)
+{
+ struct proxy_ctx *c;
+ if (!b || !b->ptr)
+ return 1;
+ c = (struct proxy_ctx *) b->ptr;
+ if (c->host)
+ free(c->host);
+ c->host = NULL;
+ b->ptr = NULL;
+ free(c);
+ return 1;
+}
+
+int socks4a_connect(BIO *b)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ int r;
+ unsigned char buf[NI_MAXHOST + 16];
+ uint16_t port_n = htons(ctx->port);
+ size_t sz = 0;
+
+ verb("V: proxy4: connecting %s:%d", ctx->host, ctx->port);
+
+ /*
+ * Packet layout:
+ * 1b: Version (must be 0x04)
+ * 1b: command (0x01 is connect)
+ * 2b: port number, big-endian
+ * 4b: 0x00, 0x00, 0x00, 0x01 (bogus IPv4 addr)
+ * 1b: 0x00 (empty 'userid' field)
+ * nb: hostname, null-terminated
+ */
+ buf[0] = 0x04;
+ buf[1] = 0x01;
+ sz += 2;
+
+ memcpy(buf + 2, &port_n, sizeof(port_n));
+ sz += sizeof(port_n);
+
+ buf[4] = 0x00;
+ buf[5] = 0x00;
+ buf[6] = 0x00;
+ buf[7] = 0x01;
+ sz += 4;
+
+ buf[8] = 0x00;
+ sz += 1;
+
+ memcpy(buf + sz, ctx->host, strlen(ctx->host) + 1);
+ sz += strlen(ctx->host) + 1;
+
+ r = BIO_write(b->next_bio, buf, sz);
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != sz)
+ return 0;
+
+ /* server reply: 1 + 1 + 2 + 4 */
+ r = BIO_read(b->next_bio, buf, 8);
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != 8)
+ return 0;
+ if (buf[1] == 0x5a) {
+ verb("V: proxy4: connected");
+ ctx->connected = 1;
+ return 1;
+ }
+ return 0;
+}
+
+int socks5_connect(BIO *b)
+{
+ unsigned char buf[NI_MAXHOST + 16];
+ int r;
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ uint16_t port_n = htons(ctx->port);
+ size_t sz = 0;
+
+ /* the length for SOCKS addresses is only one byte. */
+ if (strlen(ctx->host) == UINT8_MAX + 1)
+ return 0;
+
+ verb("V: proxy5: connecting %s:%d", ctx->host, ctx->port);
+
+ /*
+ * Hello packet layout:
+ * 1b: Version
+ * 1b: auth methods
+ * nb: method types
+ *
+ * We support only one method (no auth, 0x00). Others listed in RFC
+ * 1928.
+ */
+ buf[0] = 0x05;
+ buf[1] = 0x01;
+ buf[2] = 0x00;
+
+ r = BIO_write(b->next_bio, buf, 3);
+ if (r != 3)
+ return 0;
+
+ r = BIO_read(b->next_bio, buf, 2);
+ if (r != 2)
+ return 0;
+
+ if (buf[0] != 0x05 || buf[1] != 0x00) {
+ verb("V: proxy5: auth error %02x %02x", buf[0], buf[1]);
+ return 0;
+ }
+
+ /*
+ * Connect packet layout:
+ * 1b: version
+ * 1b: command (0x01 is connect)
+ * 1b: reserved, 0x00
+ * 1b: addr type (0x03 is domain name)
+ * nb: addr len (1b) + addr bytes, no null termination
+ * 2b: port, network byte order
+ */
+ buf[0] = 0x05;
+ buf[1] = 0x01;
+ buf[2] = 0x00;
+ buf[3] = 0x03;
+ buf[4] = strlen(ctx->host);
+ sz += 5;
+ memcpy(buf + 5, ctx->host, strlen(ctx->host));
+ sz += strlen(ctx->host);
+ memcpy(buf + sz, &port_n, sizeof(port_n));
+ sz += sizeof(port_n);
+
+ r = BIO_write(b->next_bio, buf, sz);
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != sz)
+ return 0;
+
+ /*
+ * Server's response:
+ * 1b: version
+ * 1b: status (0x00 is okay)
+ * 1b: reserved, 0x00
+ * 1b: addr type (0x03 is domain name, 0x01 ipv4)
+ * nb: addr len (1b) + addr bytes, no null termination
+ * 2b: port, network byte order
+ */
+
+ /* grab up through the addr type */
+ r = BIO_read(b->next_bio, buf, 4);
+ if ( -1 == r )
+ return -1;
+ if (r != 4)
+ return 0;
+
+ if (buf[0] != 0x05 || buf[1] != 0x00) {
+ verb("V: proxy5: connect error %02x %02x", buf[0], buf[1]);
+ return 0;
+ }
+
+ if (buf[3] == 0x03) {
+ unsigned int len;
+ r = BIO_read(b->next_bio, buf + 4, 1);
+ if (r != 1)
+ return 0;
+ /* host (buf[4] bytes) + port (2 bytes) */
+ len = buf[4] + 2;
+ while (len) {
+ r = BIO_read(b->next_bio, buf + 5, min(len, sizeof(buf)));
+ if (r <= 0)
+ return 0;
+ len -= min(len, r);
+ }
+ } else if (buf[3] == 0x01) {
+ /* 4 bytes ipv4 addr, 2 bytes port */
+ r = BIO_read(b->next_bio, buf + 4, 6);
+ if (r != 6)
+ return 0;
+ }
+
+ verb("V: proxy5: connected");
+ ctx->connected = 1;
+ return 1;
+}
+
+/* SSL socket BIOs don't support BIO_gets, so... */
+int sock_gets(BIO *b, char *buf, size_t sz)
+{
+ char c;
+ while (BIO_read(b, &c, 1) > 0 && sz > 1) {
+ *buf++ = c;
+ sz--;
+ if (c == '\n') {
+ *buf = '\0';
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int http_connect(BIO *b)
+{
+ int r;
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ char buf[4096];
+ int retcode;
+
+ snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\n",
+ ctx->host, ctx->port);
+ r = BIO_write(b->next_bio, buf, strlen(buf));
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != strlen(buf))
+ return 0;
+ /* required by RFC 2616 14.23 */
+ snprintf(buf, sizeof(buf), "Host: %s:%d\r\n", ctx->host, ctx->port);
+ r = BIO_write(b->next_bio, buf, strlen(buf));
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != strlen(buf))
+ return 0;
+ strcpy(buf, "\r\n");
+ r = BIO_write(b->next_bio, buf, strlen(buf));
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != strlen(buf))
+ return 0;
+
+ r = sock_gets(b->next_bio, buf, sizeof(buf));
+ if (r)
+ return 0;
+ /* use %*s to ignore the version */
+ if (sscanf(buf, "HTTP/%*s %d", &retcode) != 1)
+ return 0;
+
+ if (retcode < 200 || retcode > 299)
+ return 0;
+ while (!(r = sock_gets(b->next_bio, buf, sizeof(buf)))) {
+ if (!strcmp(buf, "\r\n")) {
+ /* Done with the header */
+ ctx->connected = 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int proxy_write(BIO *b, const char *buf, int sz)
+{
+ int r;
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+
+ assert(buf);
+
+ if (sz <= 0)
+ return 0;
+
+ if (!b->next_bio)
+ return 0;
+
+ if (!ctx->connected) {
+ assert(ctx->connect);
+ if (!ctx->connect(b))
+ return 0;
+ }
+
+ r = BIO_write(b->next_bio, buf, sz);
+ BIO_clear_retry_flags(b);
+ BIO_copy_next_retry(b);
+ return r;
+}
+
+int proxy_read(BIO *b, char *buf, int sz)
+{
+ int r;
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+
+ assert(buf);
+
+ if (!b->next_bio)
+ return 0;
+
+ if (!ctx->connected) {
+ assert(ctx->connect);
+ if (!ctx->connect(b))
+ return 0;
+ }
+
+ r = BIO_read(b->next_bio, buf, sz);
+ BIO_clear_retry_flags(b);
+ BIO_copy_next_retry(b);
+ return r;
+}
+
+long proxy_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+ long ret;
+ struct proxy_ctx *ctx;
+ if (!b->next_bio)
+ return 0;
+ ctx = (struct proxy_ctx *) b->ptr;
+ assert(ctx);
+
+ switch (cmd) {
+ case BIO_C_DO_STATE_MACHINE:
+ BIO_clear_retry_flags(b);
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ BIO_copy_next_retry(b);
+ break;
+ case BIO_CTRL_DUP:
+ ret = 0;
+ break;
+ default:
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ }
+ return ret;
+}
+
+int proxy_gets(BIO *b, char *buf, int size)
+{
+ return BIO_gets(b->next_bio, buf, size);
+}
+
+int proxy_puts(BIO *b, const char *str)
+{
+ return BIO_puts(b->next_bio, str);
+}
+
+long proxy_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
+{
+ if (!b->next_bio)
+ return 0;
+ return BIO_callback_ctrl(b->next_bio, cmd, fp);
+}
+
+BIO_METHOD proxy_methods = {
+ BIO_TYPE_MEM,
+ "proxy",
+ proxy_write,
+ proxy_read,
+ proxy_puts,
+ proxy_gets,
+ proxy_ctrl,
+ proxy_new,
+ proxy_free,
+ proxy_callback_ctrl,
+};
+
+BIO_METHOD *BIO_f_proxy()
+{
+ return &proxy_methods;
+}
+
+/* API starts here */
+
+BIO API *BIO_new_proxy()
+{
+ return BIO_new(BIO_f_proxy());
+}
+
+int API BIO_proxy_set_type(BIO *b, const char *type)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ if (!strcmp(type, "socks5"))
+ ctx->connect = socks5_connect;
+ else if (!strcmp(type, "socks4a"))
+ ctx->connect = socks4a_connect;
+ else if (!strcmp(type, "http"))
+ ctx->connect = http_connect;
+ else
+ return 1;
+ return 0;
+}
+
+int API BIO_proxy_set_host(BIO *b, const char *host)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ if (strlen(host) == NI_MAXHOST)
+ return 1;
+ ctx->host = strdup(host);
+ return 0;
+}
+
+void API BIO_proxy_set_port(BIO *b, uint16_t port)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ ctx->port = port;
+}
diff --git a/src/proxy-bio-plan9.h b/src/proxy-bio-plan9.h
new file mode 100644
index 0000000..3e8e74b
--- /dev/null
+++ b/src/proxy-bio-plan9.h
@@ -0,0 +1,32 @@
+/*
+ * proxy-bio.h - BIO layer for transparent proxy connections
+ *
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef PROXY_BIO_H
+#define PROXY_BIO_H
+
+#include <inttypes.h>
+
+#include <openssl/bio.h>
+
+#include "util-plan9.h"
+
+struct proxy_ctx {
+ char *host;
+ uint16_t port;
+ int connected;
+ int (*connect)(BIO *b);
+};
+
+BIO *BIO_new_proxy();
+
+/* These do not take ownership of their string arguments. */
+int BIO_proxy_set_type(BIO *b, const char *type);
+int BIO_proxy_set_host(BIO *b, const char *host);
+void BIO_proxy_set_port(BIO *b, uint16_t port);
+
+#endif /* !PROXY_BIO_H */
diff --git a/src/proxy-bio-unittest.c b/src/proxy-bio-unittest.c
new file mode 100644
index 0000000..8b9ae8b
--- /dev/null
+++ b/src/proxy-bio-unittest.c
@@ -0,0 +1,292 @@
+/*
+ * proxy-bio-unittest.c - proxy-bio unit tests
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if defined(__linux__)
+#include <alloca.h>
+#endif
+
+#include "src/proxy-bio.h"
+#include "src/test-bio.h"
+#include "src/test_harness.h"
+#include "src/tlsdate.h"
+
+FIXTURE (test_bio)
+{
+ BIO *test;
+};
+
+FIXTURE_SETUP (test_bio)
+{
+ self->test = BIO_new_test();
+ ASSERT_NE (NULL, self->test);
+}
+
+FIXTURE_TEARDOWN (test_bio)
+{
+ BIO_free (self->test);
+}
+
+BIO *proxy_bio (BIO *test, const char *type)
+{
+ BIO *proxy = BIO_new_proxy();
+ BIO_proxy_set_type (proxy, type);
+ BIO_proxy_set_host (proxy, kTestHost);
+ BIO_proxy_set_port (proxy, TEST_PORT);
+ BIO_push (proxy, test);
+ return proxy;
+}
+
+int need_out_bytes (BIO *test, const unsigned char *out, size_t sz)
+{
+ unsigned char *buf = malloc (sz);
+ size_t i;
+ int result;
+ if (!buf)
+ return 1;
+ if (BIO_test_output_left (test) < sz)
+ {
+ fprintf (TH_LOG_STREAM, "not enough output: %d < %d\n",
+ (int) BIO_test_output_left (test), (int) sz);
+ free (buf);
+ return 2;
+ }
+ if (BIO_test_get_output (test, buf, sz) != sz)
+ {
+ free (buf);
+ return 3;
+ }
+ if (memcmp (buf, out, sz))
+ {
+ for (i = 0; i < sz; i++)
+ {
+ if (buf[i] != out[i])
+ fprintf (TH_LOG_STREAM,
+ "mismatch %d %02x %02x\n", (int) i,
+ buf[i], out[i]);
+ }
+ }
+ result = memcmp (buf, out, sz);
+ free (buf);
+ return result;
+}
+
+int need_out_byte (BIO *test, unsigned char out)
+{
+ unsigned char c;
+ if (BIO_test_output_left (test) < 1)
+ return 1;
+ if (BIO_test_get_output (test, &c, 1) != 1)
+ return 2;
+ return c != out;
+}
+
+int get_bytes (BIO *test, unsigned char *buf, size_t sz)
+{
+ return BIO_test_get_output (test, buf, sz);
+}
+
+void put_bytes (BIO *test, const unsigned char *buf, size_t sz)
+{
+ BIO_test_add_input (test, buf, sz);
+}
+
+void put_byte (BIO *test, char c)
+{
+ BIO_test_add_input (test, (unsigned char *) &c, 1);
+}
+
+unsigned const char kSocks4ARequest[] =
+{
+ 0x04, /* socks4 */
+ 0x01, /* tcp stream */
+ (TEST_PORT & 0xff00) >> 8,
+ TEST_PORT & 0xff,
+ 0x00, 0x00, 0x00, 0x01, /* bogus IP */
+ 0x00, /* userid */
+ TEST_HOST, 0x00 /* null-terminated host */
+};
+
+TEST_F (test_bio, socks4a_success)
+{
+ unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
+ unsigned const char kReply[] =
+ {
+ 0x00, /* null byte */
+ 0x5a, /* success */
+ (TEST_PORT & 0xff00) >> 8, /* port high */
+ TEST_PORT & 0xff, /* port low */
+ 0x00, 0x00, 0x00, 0x00 /* bogus IP */
+ };
+ BIO *proxy = proxy_bio (self->test, "socks4a");
+ put_bytes (self->test, kReply, sizeof (kReply));
+ EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kSocks4ARequest,
+ sizeof (kSocks4ARequest)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kTestInput,
+ sizeof (kTestInput)));
+ EXPECT_EQ (0, BIO_test_output_left (self->test));
+}
+
+TEST_F (test_bio, socks4a_fail)
+{
+ unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
+ unsigned const char kReply[] =
+ {
+ 0x00, /* null byte */
+ 0x5b, /* fail */
+ (TEST_PORT & 0xff00) >> 8, /* port high */
+ TEST_PORT & 0xff, /* port low */
+ 0x00, 0x00, 0x00, 0x00 /* bogus IP */
+ };
+ BIO *proxy = proxy_bio (self->test, "socks4a");
+ put_bytes (self->test, kReply, sizeof (kReply));
+ EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kSocks4ARequest,
+ sizeof (kSocks4ARequest)));
+ /* We shouldn't have written any payload */
+ EXPECT_EQ (0, BIO_test_output_left (self->test));
+}
+
+unsigned const char kSocks5AuthRequest[] =
+{
+ 0x05, /* socks5 */
+ 0x01, /* one auth method */
+ 0x00 /* no auth */
+};
+
+unsigned const char kSocks5AuthReply[] =
+{
+ 0x05, /* socks5 */
+ 0x00, /* no auth */
+};
+
+unsigned const char kSocks5ConnectRequest[] =
+{
+ 0x05, /* socks5 */
+ 0x01, /* tcp stream */
+ 0x00, /* reserved 0x00 */
+ 0x03, /* domain name */
+ TEST_HOST_SIZE, /* hostname with length prefix */
+ TEST_HOST,
+ (TEST_PORT & 0xff00) >> 8,
+ TEST_PORT & 0xff
+};
+
+unsigned const char kSocks5ConnectReply[] =
+{
+ 0x05, /* socks5 */
+ 0x00, /* success */
+ 0x00, /* reserved 0x00 */
+ 0x03, /* domain name */
+ TEST_HOST_SIZE, /* hostname with length prefix */
+ TEST_HOST,
+ (TEST_PORT & 0xff00) >> 8,
+ TEST_PORT & 0xff
+};
+
+TEST_F (test_bio, socks5_success)
+{
+ unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
+ BIO *proxy = proxy_bio (self->test, "socks5");
+ put_bytes (self->test, kSocks5AuthReply, sizeof (kSocks5AuthReply));
+ put_bytes (self->test, kSocks5ConnectReply, sizeof (kSocks5ConnectReply));
+ EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest,
+ sizeof (kSocks5AuthRequest)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kSocks5ConnectRequest,
+ sizeof (kSocks5ConnectRequest)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kTestInput,
+ sizeof (kTestInput)));
+ EXPECT_EQ (0, BIO_test_output_left (self->test));
+}
+
+TEST_F (test_bio, socks5_auth_fail)
+{
+ unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
+ unsigned const char kAuthFail[] =
+ {
+ 0x05,
+ 0xff,
+ };
+ BIO *proxy = proxy_bio (self->test, "socks5");
+ put_bytes (self->test, kAuthFail, sizeof (kAuthFail));
+ EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest,
+ sizeof (kSocks5AuthRequest)));
+ EXPECT_EQ (0, BIO_test_output_left (self->test));
+}
+
+TEST_F (test_bio, socks5_connect_fail)
+{
+ unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
+ unsigned const char kConnectFail[] =
+ {
+ 0x05,
+ 0x01,
+ 0x00,
+ 0x03,
+ TEST_HOST_SIZE,
+ TEST_HOST,
+ (TEST_PORT & 0xff00) >> 8,
+ TEST_PORT & 0xff
+ };
+ BIO *proxy = proxy_bio (self->test, "socks5");
+ put_bytes (self->test, kSocks5AuthReply, sizeof (kSocks5AuthReply));
+ put_bytes (self->test, kConnectFail, sizeof (kConnectFail));
+ EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest,
+ sizeof (kSocks5AuthRequest)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kSocks5ConnectRequest,
+ sizeof (kSocks5ConnectRequest)));
+ EXPECT_EQ (0, BIO_test_output_left (self->test));
+}
+
+TEST_F (test_bio, http_success)
+{
+ unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
+ BIO *proxy = proxy_bio (self->test, "http");
+ char kConnectRequest[1024];
+ char kConnectResponse[] = "HTTP/1.0 200 OK\r\n"
+ "Uninteresting-Header: foobar\r\n"
+ "Another-Header: lol\r\n"
+ "\r\n";
+ snprintf (kConnectRequest, sizeof (kConnectRequest),
+ "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
+ kTestHost, TEST_PORT, kTestHost, TEST_PORT);
+ put_bytes (self->test, (unsigned char *) kConnectResponse,
+ strlen (kConnectResponse));
+ EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+ EXPECT_EQ (0, need_out_bytes (self->test,
+ (unsigned char *) kConnectRequest,
+ strlen (kConnectRequest)));
+ EXPECT_EQ (0, need_out_bytes (self->test, kTestInput,
+ sizeof (kTestInput)));
+ EXPECT_EQ (0, BIO_test_output_left (self->test));
+}
+
+TEST_F (test_bio, http_error)
+{
+ unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
+ BIO *proxy = proxy_bio (self->test, "http");
+ char kConnectRequest[1024];
+ char kConnectResponse[] = "HTTP/1.0 403 NO U\r\n"
+ "Uninteresting-Header: foobar\r\n"
+ "Another-Header: lol\r\n"
+ "\r\n";
+ snprintf (kConnectRequest, sizeof (kConnectRequest),
+ "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
+ kTestHost, TEST_PORT, kTestHost, TEST_PORT);
+ put_bytes (self->test, (unsigned char *) kConnectResponse,
+ strlen (kConnectResponse));
+ EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+ EXPECT_EQ (0, need_out_bytes (self->test,
+ (unsigned char *) kConnectRequest,
+ strlen (kConnectRequest)));
+ EXPECT_EQ (0, BIO_test_output_left (self->test));
+}
+
+TEST_HARNESS_MAIN
diff --git a/src/proxy-bio.c b/src/proxy-bio.c
new file mode 100644
index 0000000..2576112
--- /dev/null
+++ b/src/proxy-bio.c
@@ -0,0 +1,430 @@
+/*
+ * proxy-bio.c - BIO layer for SOCKS4a/5 proxy connections
+ *
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * This file implements a SOCKS4a/SOCKS5 "filter" BIO. In SSL terminology, a BIO
+ * is a stackable IO filter, kind of like sysv streams. These filters are
+ * inserted into a stream to cause it to run SOCKS over whatever transport is
+ * being used. Most commonly, this would be:
+ * SSL BIO (filter) -> SOCKS BIO (filter) -> connect BIO (source/sink)
+ * This configuration represents doing an SSL connection through a SOCKS proxy,
+ * which is itself connected to in plaintext. You might also do:
+ * SSL BIO -> SOCKS BIO -> SSL BIO -> connect BIO
+ * This is an SSL connection through a SOCKS proxy which is itself reached over
+ * SSL.
+ */
+
+#include "config.h"
+
+#include <arpa/inet.h>
+#include <assert.h>
+#ifndef __USE_MISC
+#define __USE_MISC
+#endif
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#include <netdb.h>
+
+#include <stdint.h>
+
+#ifndef HAVE_STRNLEN
+#include "src/common/strnlen.h"
+#endif
+
+#include "src/proxy-bio.h"
+
+int socks4a_connect (BIO *b);
+int socks5_connect (BIO *b);
+int http_connect (BIO *b);
+
+int proxy_new (BIO *b)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) malloc (sizeof *ctx);
+ if (!ctx)
+ return 0;
+ ctx->connected = 0;
+ ctx->connect = NULL;
+ ctx->host = NULL;
+ ctx->port = 0;
+ b->init = 1;
+ b->flags = 0;
+ b->ptr = ctx;
+ return 1;
+}
+
+int proxy_free (BIO *b)
+{
+ struct proxy_ctx *c;
+ if (!b || !b->ptr)
+ return 1;
+ c = (struct proxy_ctx *) b->ptr;
+ if (c->host)
+ free (c->host);
+ c->host = NULL;
+ b->ptr = NULL;
+ free (c);
+ return 1;
+}
+
+int socks4a_connect (BIO *b)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ int r;
+ unsigned char buf[NI_MAXHOST + 16];
+ uint16_t port_n = htons (ctx->port);
+ size_t sz = 0;
+ verb ("V: proxy4: connecting %s:%d", ctx->host, ctx->port);
+ /*
+ * Packet layout:
+ * 1b: Version (must be 0x04)
+ * 1b: command (0x01 is connect)
+ * 2b: port number, big-endian
+ * 4b: 0x00, 0x00, 0x00, 0x01 (bogus IPv4 addr)
+ * 1b: 0x00 (empty 'userid' field)
+ * nb: hostname, null-terminated
+ */
+ buf[0] = 0x04;
+ buf[1] = 0x01;
+ sz += 2;
+ memcpy (buf + 2, &port_n, sizeof (port_n));
+ sz += sizeof (port_n);
+ buf[4] = 0x00;
+ buf[5] = 0x00;
+ buf[6] = 0x00;
+ buf[7] = 0x01;
+ sz += 4;
+ buf[8] = 0x00;
+ sz += 1;
+
+ memcpy (buf + sz, ctx->host, strlen (ctx->host) + 1);
+ sz += strlen (ctx->host) + 1;
+ r = BIO_write (b->next_bio, buf, sz);
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != sz)
+ return 0;
+ /* server reply: 1 + 1 + 2 + 4 */
+ r = BIO_read (b->next_bio, buf, 8);
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != 8)
+ return 0;
+ if (buf[1] == 0x5a)
+ {
+ verb ("V: proxy4: connected");
+ ctx->connected = 1;
+ return 1;
+ }
+ return 0;
+}
+
+int socks5_connect (BIO *b)
+{
+ unsigned char buf[NI_MAXHOST + 16];
+ int r;
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ uint16_t port_n = htons (ctx->port);
+ size_t sz = 0;
+ /* the length for SOCKS addresses is only one byte. */
+ if (strnlen (ctx->host, UINT8_MAX + 1) == UINT8_MAX + 1)
+ return 0;
+ verb ("V: proxy5: connecting %s:%d", ctx->host, ctx->port);
+ /*
+ * Hello packet layout:
+ * 1b: Version
+ * 1b: auth methods
+ * nb: method types
+ *
+ * We support only one method (no auth, 0x00). Others listed in RFC
+ * 1928.
+ */
+ buf[0] = 0x05;
+ buf[1] = 0x01;
+ buf[2] = 0x00;
+ r = BIO_write (b->next_bio, buf, 3);
+ if (r != 3)
+ return 0;
+ r = BIO_read (b->next_bio, buf, 2);
+ if (r != 2)
+ return 0;
+ if (buf[0] != 0x05 || buf[1] != 0x00)
+ {
+ verb ("V: proxy5: auth error %02x %02x", buf[0], buf[1]);
+ return 0;
+ }
+ /*
+ * Connect packet layout:
+ * 1b: version
+ * 1b: command (0x01 is connect)
+ * 1b: reserved, 0x00
+ * 1b: addr type (0x03 is domain name)
+ * nb: addr len (1b) + addr bytes, no null termination
+ * 2b: port, network byte order
+ */
+ buf[0] = 0x05;
+ buf[1] = 0x01;
+ buf[2] = 0x00;
+ buf[3] = 0x03;
+ buf[4] = strlen (ctx->host);
+ sz += 5;
+ memcpy (buf + 5, ctx->host, strlen (ctx->host));
+ sz += strlen (ctx->host);
+ memcpy (buf + sz, &port_n, sizeof (port_n));
+ sz += sizeof (port_n);
+ r = BIO_write (b->next_bio, buf, sz);
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != sz)
+ return 0;
+ /*
+ * Server's response:
+ * 1b: version
+ * 1b: status (0x00 is okay)
+ * 1b: reserved, 0x00
+ * 1b: addr type (0x03 is domain name, 0x01 ipv4)
+ * nb: addr len (1b) + addr bytes, no null termination
+ * 2b: port, network byte order
+ */
+ /* grab up through the addr type */
+ r = BIO_read (b->next_bio, buf, 4);
+ if ( -1 == r )
+ return -1;
+ if (r != 4)
+ return 0;
+ if (buf[0] != 0x05 || buf[1] != 0x00)
+ {
+ verb ("V: proxy5: connect error %02x %02x", buf[0], buf[1]);
+ return 0;
+ }
+ if (buf[3] == 0x03)
+ {
+ unsigned int len;
+ r = BIO_read (b->next_bio, buf + 4, 1);
+ if (r != 1)
+ return 0;
+ /* host (buf[4] bytes) + port (2 bytes) */
+ len = buf[4] + 2;
+ while (len)
+ {
+ r = BIO_read (b->next_bio, buf + 5, min (len, sizeof (buf)));
+ if (r <= 0)
+ return 0;
+ len -= min (len, r);
+ }
+ }
+ else if (buf[3] == 0x01)
+ {
+ /* 4 bytes ipv4 addr, 2 bytes port */
+ r = BIO_read (b->next_bio, buf + 4, 6);
+ if (r != 6)
+ return 0;
+ }
+ verb ("V: proxy5: connected");
+ ctx->connected = 1;
+ return 1;
+}
+
+/* SSL socket BIOs don't support BIO_gets, so... */
+int sock_gets (BIO *b, char *buf, size_t sz)
+{
+ char c;
+ while (BIO_read (b, &c, 1) > 0 && sz > 1)
+ {
+ *buf++ = c;
+ sz--;
+ if (c == '\n')
+ {
+ *buf = '\0';
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int http_connect (BIO *b)
+{
+ int r;
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ char buf[4096];
+ int retcode;
+ snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.1\r\n",
+ ctx->host, ctx->port);
+ r = BIO_write (b->next_bio, buf, strlen (buf));
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != strlen(buf))
+ return 0;
+ /* required by RFC 2616 14.23 */
+ snprintf (buf, sizeof (buf), "Host: %s:%d\r\n", ctx->host, ctx->port);
+ r = BIO_write (b->next_bio, buf, strlen (buf));
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != strlen(buf))
+ return 0;
+ strcpy (buf, "\r\n");
+ r = BIO_write (b->next_bio, buf, strlen (buf));
+ if ( -1 == r )
+ return -1;
+ if ( (size_t) r != strlen(buf))
+ return 0;
+ r = sock_gets (b->next_bio, buf, sizeof (buf));
+ if (r)
+ return 0;
+ /* use %*s to ignore the version */
+ if (sscanf (buf, "HTTP/%*s %d", &retcode) != 1)
+ return 0;
+ if (retcode < 200 || retcode > 299)
+ return 0;
+ while (! (r = sock_gets (b->next_bio, buf, sizeof (buf))))
+ {
+ if (!strcmp (buf, "\r\n"))
+ {
+ /* Done with the header */
+ ctx->connected = 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int proxy_write (BIO *b, const char *buf, int sz)
+{
+ int r;
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+
+ assert (buf);
+ if (sz <= 0)
+ return 0;
+ if (!b->next_bio)
+ return 0;
+ if (!ctx->connected)
+ {
+ assert (ctx->connect);
+ if (!ctx->connect (b))
+ return 0;
+ }
+ r = BIO_write (b->next_bio, buf, sz);
+ BIO_clear_retry_flags (b);
+ BIO_copy_next_retry (b);
+ return r;
+}
+
+int proxy_read (BIO *b, char *buf, int sz)
+{
+ int r;
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+
+ assert (buf);
+ if (!b->next_bio)
+ return 0;
+ if (!ctx->connected)
+ {
+ assert (ctx->connect);
+ if (!ctx->connect (b))
+ return 0;
+ }
+ r = BIO_read (b->next_bio, buf, sz);
+ BIO_clear_retry_flags (b);
+ BIO_copy_next_retry (b);
+ return r;
+}
+
+long proxy_ctrl (BIO *b, int cmd, long num, void *ptr)
+{
+ long ret;
+ struct proxy_ctx *ctx;
+ if (!b->next_bio)
+ return 0;
+ ctx = (struct proxy_ctx *) b->ptr;
+ assert (ctx);
+ switch (cmd)
+ {
+ case BIO_C_DO_STATE_MACHINE:
+ BIO_clear_retry_flags (b);
+ ret = BIO_ctrl (b->next_bio, cmd, num, ptr);
+ BIO_copy_next_retry (b);
+ break;
+ case BIO_CTRL_DUP:
+ ret = 0;
+ break;
+ default:
+ ret = BIO_ctrl (b->next_bio, cmd, num, ptr);
+ }
+ return ret;
+}
+
+int proxy_gets (BIO *b, char *buf, int size)
+{
+ return BIO_gets (b->next_bio, buf, size);
+}
+
+int proxy_puts (BIO *b, const char *str)
+{
+ return BIO_puts (b->next_bio, str);
+}
+
+long proxy_callback_ctrl (BIO *b, int cmd, bio_info_cb *fp)
+{
+ if (!b->next_bio)
+ return 0;
+ return BIO_callback_ctrl (b->next_bio, cmd, fp);
+}
+
+BIO_METHOD proxy_methods =
+{
+ BIO_TYPE_MEM,
+ "proxy",
+ proxy_write,
+ proxy_read,
+ proxy_puts,
+ proxy_gets,
+ proxy_ctrl,
+ proxy_new,
+ proxy_free,
+ proxy_callback_ctrl,
+};
+
+BIO_METHOD *BIO_f_proxy()
+{
+ return &proxy_methods;
+}
+
+/* API starts here */
+
+BIO API *BIO_new_proxy()
+{
+ return BIO_new (BIO_f_proxy());
+}
+
+int API BIO_proxy_set_type (BIO *b, const char *type)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ if (!strcmp (type, "socks5"))
+ ctx->connect = socks5_connect;
+ else if (!strcmp (type, "socks4a"))
+ ctx->connect = socks4a_connect;
+ else if (!strcmp (type, "http"))
+ ctx->connect = http_connect;
+ else
+ return 1;
+ return 0;
+}
+
+int API BIO_proxy_set_host (BIO *b, const char *host)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ if (strnlen (host, NI_MAXHOST) == NI_MAXHOST)
+ return 1;
+ ctx->host = strdup (host);
+ return 0;
+}
+
+void API BIO_proxy_set_port (BIO *b, uint16_t port)
+{
+ struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr;
+ ctx->port = port;
+}
diff --git a/src/proxy-bio.h b/src/proxy-bio.h
new file mode 100644
index 0000000..3a68153
--- /dev/null
+++ b/src/proxy-bio.h
@@ -0,0 +1,32 @@
+/*
+ * proxy-bio.h - BIO layer for transparent proxy connections
+ *
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef PROXY_BIO_H
+#define PROXY_BIO_H
+
+#include <stdint.h>
+
+#include <openssl/bio.h>
+
+#include "util.h"
+
+struct proxy_ctx {
+ char *host;
+ uint16_t port;
+ int connected;
+ int (*connect)(BIO *b);
+};
+
+BIO *BIO_new_proxy();
+
+/* These do not take ownership of their string arguments. */
+int BIO_proxy_set_type (BIO *b, const char *type);
+int BIO_proxy_set_host (BIO *b, const char *host);
+void BIO_proxy_set_port (BIO *b, uint16_t port);
+
+#endif /* !PROXY_BIO_H */
diff --git a/src/proxy-polarssl.c b/src/proxy-polarssl.c
new file mode 100644
index 0000000..04f7f6d
--- /dev/null
+++ b/src/proxy-polarssl.c
@@ -0,0 +1,360 @@
+/*
+ * proxy-polarssl.c - Net stack layer for SOCKS4a/5 proxy connections
+ *
+ * Based on proxy-bio.c - Original copyright (c) 2012 The Chromium OS Authors.
+ *
+ * This file was adapted by Paul Bakker <p.j.bakker@offspark.com>
+ * All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * This file implements a SOCKS4a/SOCKS5 net layer as used by PolarSSL.
+ */
+
+#include "config.h"
+
+#include <arpa/inet.h>
+#include <assert.h>
+#ifndef __USE_MISC
+#define __USE_MISC
+#endif
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#include <netdb.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#ifndef HAVE_STRNLEN
+#include "src/common/strnlen.h"
+#endif
+
+#include "src/proxy-polarssl.h"
+#include "src/util.h"
+
+int socks4a_connect(proxy_polarssl_ctx *ctx)
+{
+ int r;
+ unsigned char buf[NI_MAXHOST + 16];
+ uint16_t port_n;
+ size_t sz = 0;
+
+ if (!ctx)
+ return 0;
+
+ verb("V: proxy4: connecting %s:%d", ctx->host, ctx->port);
+
+ port_n = htons(ctx->port);
+
+ /*
+ * Packet layout:
+ * 1b: Version (must be 0x04)
+ * 1b: command (0x01 is connect)
+ * 2b: port number, big-endian
+ * 4b: 0x00, 0x00, 0x00, 0x01 (bogus IPv4 addr)
+ * 1b: 0x00 (empty 'userid' field)
+ * nb: hostname, null-terminated
+ */
+ buf[0] = 0x04;
+ buf[1] = 0x01;
+ sz += 2;
+
+ memcpy(buf + 2, &port_n, sizeof(port_n));
+ sz += sizeof(port_n);
+
+ buf[4] = 0x00;
+ buf[5] = 0x00;
+ buf[6] = 0x00;
+ buf[7] = 0x01;
+ sz += 4;
+
+ buf[8] = 0x00;
+ sz += 1;
+
+ memcpy(buf + sz, ctx->host, strlen(ctx->host) + 1);
+ sz += strlen(ctx->host) + 1;
+
+ r = ctx->f_send(ctx->p_send, buf, sz);
+ if (r != sz)
+ return 0;
+
+ /* server reply: 1 + 1 + 2 + 4 */
+ r = ctx->f_recv(ctx->p_recv, buf, 8);
+ if (r != 8)
+ return 0;
+
+ if (buf[1] == 0x5a) {
+ verb("V: proxy4: connected");
+ ctx->connected = 1;
+ return 1;
+ }
+ return 0;
+}
+
+int socks5_connect(proxy_polarssl_ctx *ctx)
+{
+ unsigned char buf[NI_MAXHOST + 16];
+ int r;
+ uint16_t port_n;
+ size_t sz = 0;
+
+ if (!ctx)
+ return 0;
+
+ /* the length for SOCKS addresses is only one byte. */
+ if (strnlen(ctx->host, UINT8_MAX + 1) == UINT8_MAX + 1)
+ return 0;
+
+ verb("V: proxy5: connecting %s:%d", ctx->host, ctx->port);
+
+ port_n = htons(ctx->port);
+
+ /*
+ * Hello packet layout:
+ * 1b: Version
+ * 1b: auth methods
+ * nb: method types
+ *
+ * We support only one method (no auth, 0x00). Others listed in RFC
+ * 1928.
+ */
+ buf[0] = 0x05;
+ buf[1] = 0x01;
+ buf[2] = 0x00;
+
+ r = ctx->f_send(ctx->p_send, buf, 3);
+ if (r != 3)
+ return 0;
+
+ r = ctx->f_recv(ctx->p_recv, buf, 2);
+ if (r != 2)
+ return 0;
+
+ if (buf[0] != 0x05 || buf[1] != 0x00) {
+ verb("V: proxy5: auth error %02x %02x", buf[0], buf[1]);
+ return 0;
+ }
+
+ /*
+ * Connect packet layout:
+ * 1b: version
+ * 1b: command (0x01 is connect)
+ * 1b: reserved, 0x00
+ * 1b: addr type (0x03 is domain name)
+ * nb: addr len (1b) + addr bytes, no null termination
+ * 2b: port, network byte order
+ */
+ buf[0] = 0x05;
+ buf[1] = 0x01;
+ buf[2] = 0x00;
+ buf[3] = 0x03;
+ buf[4] = strlen(ctx->host);
+ sz += 5;
+ memcpy(buf + 5, ctx->host, strlen(ctx->host));
+ sz += strlen(ctx->host);
+ memcpy(buf + sz, &port_n, sizeof(port_n));
+ sz += sizeof(port_n);
+
+ r = ctx->f_send(ctx->p_send, buf, sz);
+ if (r != sz)
+ return 0;
+
+ /*
+ * Server's response:
+ * 1b: version
+ * 1b: status (0x00 is okay)
+ * 1b: reserved, 0x00
+ * 1b: addr type (0x03 is domain name, 0x01 ipv4)
+ * nb: addr len (1b) + addr bytes, no null termination
+ * 2b: port, network byte order
+ */
+
+ /* grab up through the addr type */
+ r = ctx->f_recv(ctx->p_recv, buf, 4);
+ if (r != 4)
+ return 0;
+
+ if (buf[0] != 0x05 || buf[1] != 0x00) {
+ verb("V: proxy5: connect error %02x %02x", buf[0], buf[1]);
+ return 0;
+ }
+
+ if (buf[3] == 0x03) {
+ unsigned int len;
+ r = ctx->f_recv(ctx->p_recv, buf + 4, 1);
+ if (r != 1)
+ return 0;
+ /* host (buf[4] bytes) + port (2 bytes) */
+ len = buf[4] + 2;
+ while (len) {
+ r = ctx->f_recv(ctx->p_recv, buf + 5, min(len, sizeof(buf)));
+ if (r <= 0)
+ return 0;
+ len -= min(len, r);
+ }
+ } else if (buf[3] == 0x01) {
+ /* 4 bytes ipv4 addr, 2 bytes port */
+ r = ctx->f_recv(ctx->p_recv, buf + 4, 6);
+ if (r != 6)
+ return 0;
+ }
+
+ verb("V: proxy5: connected");
+ ctx->connected = 1;
+ return 1;
+}
+
+/* SSL socket BIOs don't support BIO_gets, so... */
+int sock_gets(proxy_polarssl_ctx *ctx, char *buf, size_t sz)
+{
+ unsigned char c;
+ while (ctx->f_recv(ctx->p_recv, &c, 1) > 0 && sz > 1) {
+ *buf++ = c;
+ sz--;
+ if (c == '\n') {
+ *buf = '\0';
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int http_connect(proxy_polarssl_ctx *ctx)
+{
+ int r;
+ char buf[4096];
+ int retcode;
+
+ snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\n",
+ ctx->host, ctx->port);
+ r = ctx->f_send(ctx->p_send, (unsigned char *) buf, strlen(buf));
+ if (r != strlen(buf))
+ return 0;
+ /* required by RFC 2616 14.23 */
+ snprintf(buf, sizeof(buf), "Host: %s:%d\r\n", ctx->host, ctx->port);
+ r = ctx->f_send(ctx->p_send, (unsigned char *) buf, strlen(buf));
+ if (r != strlen(buf))
+ return 0;
+ strcpy(buf, "\r\n");
+ r = ctx->f_send(ctx->p_send, (unsigned char *) buf, strlen(buf));
+ if (r != strlen(buf))
+ return 0;
+
+ r = sock_gets(ctx, buf, sizeof(buf));
+ if (r)
+ return 0;
+ /* use %*s to ignore the version */
+ if (sscanf(buf, "HTTP/%*s %d", &retcode) != 1)
+ return 0;
+
+ if (retcode < 200 || retcode > 299)
+ return 0;
+ while (!(r = sock_gets(ctx, buf, sizeof(buf)))) {
+ if (!strcmp(buf, "\r\n")) {
+ /* Done with the header */
+ ctx->connected = 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int API proxy_polarssl_init(proxy_polarssl_ctx *ctx)
+{
+ if (!ctx)
+ return 0;
+
+ memset(ctx, 0, sizeof(proxy_polarssl_ctx));
+ return 1;
+}
+
+void API proxy_polarssl_set_bio(proxy_polarssl_ctx *ctx,
+ int (*f_recv)(void *, unsigned char *, size_t), void *p_recv,
+ int (*f_send)(void *, const unsigned char *, size_t), void *p_send)
+{
+ if (!ctx)
+ return;
+
+ ctx->f_recv = f_recv;
+ ctx->p_recv = p_recv;
+ ctx->f_send = f_send;
+ ctx->p_send = p_send;
+}
+
+int API proxy_polarssl_free(proxy_polarssl_ctx *ctx)
+{
+ if (!ctx)
+ return 0;
+
+ if (ctx->host)
+ {
+ free(ctx->host);
+ ctx->host = NULL;
+ }
+
+ return 1;
+}
+
+int API proxy_polarssl_set_scheme(proxy_polarssl_ctx *ctx, const char *scheme)
+{
+ if (!strcmp(scheme, "socks5"))
+ ctx->f_connect = socks5_connect;
+ else if (!strcmp(scheme, "socks4"))
+ ctx->f_connect = socks4a_connect;
+ else if (!strcmp(scheme, "http"))
+ ctx->f_connect = http_connect;
+ else
+ return 1;
+ return 0;
+}
+
+int API proxy_polarssl_set_host(proxy_polarssl_ctx *ctx, const char *host)
+{
+ if (strnlen(host, NI_MAXHOST) == NI_MAXHOST)
+ return 1;
+ ctx->host = strdup(host);
+ return 0;
+}
+
+void API proxy_polarssl_set_port(proxy_polarssl_ctx *ctx, uint16_t port)
+{
+ ctx->port = port;
+}
+
+int API proxy_polarssl_recv(void *ctx, unsigned char *data, size_t len)
+{
+ proxy_polarssl_ctx *proxy = (proxy_polarssl_ctx *) ctx;
+ int r;
+
+ if (!ctx)
+ return -1;
+
+ if (!proxy->connected)
+ {
+ r = proxy->f_connect(ctx);
+ if (r)
+ return (r);
+ }
+
+ return proxy->f_recv(proxy->p_recv, data, len);
+}
+
+
+int API proxy_polarssl_send(void *ctx, const unsigned char *data, size_t len)
+{
+ proxy_polarssl_ctx *proxy = (proxy_polarssl_ctx *) ctx;
+ int r;
+
+ if (!ctx)
+ return -1;
+
+ if (!proxy->connected)
+ {
+ r = proxy->f_connect(ctx);
+ if (r)
+ return (r);
+ }
+
+ return proxy->f_send(proxy->p_send, data, len);
+}
diff --git a/src/proxy-polarssl.h b/src/proxy-polarssl.h
new file mode 100644
index 0000000..144ba20
--- /dev/null
+++ b/src/proxy-polarssl.h
@@ -0,0 +1,46 @@
+/*
+ * proxy-polarssl.h - PolarSSL layer for transparent proxy connections
+ *
+ * Based on proxy-bio.c - Original copyright (c) 2012 The Chromium OS Authors.
+ *
+ * This file was adapted by Paul Bakker <p.j.bakker@offspark.com>
+ * All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef PROXY_POLARSSL_H
+#define PROXY_POLARSSL_H
+
+#include <stdint.h>
+
+typedef struct _proxy_polarssl_ctx proxy_polarssl_ctx;
+
+struct _proxy_polarssl_ctx {
+ char *host;
+ uint16_t port;
+ int connected;
+
+ int (*f_recv)(void *, unsigned char *, size_t);
+ int (*f_send)(void *, const unsigned char *, size_t);
+ int (*f_connect)(proxy_polarssl_ctx *);
+
+ void *p_recv; /*!< context for reading operations */
+ void *p_send; /*!< context for writing operations */
+};
+
+int proxy_polarssl_init(proxy_polarssl_ctx *proxy);
+int proxy_polarssl_free(proxy_polarssl_ctx *ctx);
+
+void proxy_polarssl_set_bio(proxy_polarssl_ctx *ctx,
+ int (*f_recv)(void *, unsigned char *, size_t), void *p_recv,
+ int (*f_send)(void *, const unsigned char *, size_t), void *p_send);
+int proxy_polarssl_set_scheme(proxy_polarssl_ctx *ctx, const char *scheme);
+int proxy_polarssl_set_host(proxy_polarssl_ctx *ctx, const char *host);
+void proxy_polarssl_set_port(proxy_polarssl_ctx *ctx, uint16_t port);
+
+int proxy_polarssl_recv(void *ctx, unsigned char *data, size_t len);
+int proxy_polarssl_send(void *ctx, const unsigned char *data, size_t len);
+
+#endif /* !PROXY_POLARSSL_H */
diff --git a/src/routeup.c b/src/routeup.c
new file mode 100644
index 0000000..a5925d5
--- /dev/null
+++ b/src/routeup.c
@@ -0,0 +1,158 @@
+/*
+ * routeup.c - listens for routes coming up, tells stdout
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * We emit 'n' for a route coming up.
+ */
+
+#include "config.h"
+
+#ifdef linux
+#include <asm/types.h>
+#endif
+
+#include <sys/socket.h> /* needed for linux/if.h for struct sockaddr */
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/if.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/sockios.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include "src/util.h"
+#include "src/routeup.h"
+
+int verbose;
+int verbose_debug;
+
+/*
+ * Set up the supplied context by creating and binding its netlink socket.
+ * Returns 0 for success, 1 for failure.
+ */
+int API
+routeup_setup (struct routeup *rtc)
+{
+ struct sockaddr_nl sa;
+ memset (&sa, 0, sizeof (sa));
+ sa.nl_family = AF_NETLINK;
+ sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
+ rtc->netlinkfd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtc->netlinkfd < 0)
+ {
+ perror ("netlink socket() failed");
+ return 1;
+ }
+ if (bind (rtc->netlinkfd, (struct sockaddr *) &sa, sizeof (sa)) < 0)
+ {
+ perror ("netlink bind() failed");
+ close (rtc->netlinkfd);
+ return 1;
+ }
+ if (fcntl (rtc->netlinkfd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ perror ("netlink fcntl(O_NONBLOCK) failed");
+ close (rtc->netlinkfd);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Handle a single netlink message.
+ * Returns 0 if there was a route status change, 1 if there
+ * were no valid nlmsghdrs, and -1 if there was a read error.
+ */
+int API
+routeup_process (struct routeup *rtc)
+{
+ char buf[4096];
+ ssize_t sz;
+ struct nlmsghdr *nh;
+ if ( (sz = read (rtc->netlinkfd, buf, sizeof (buf))) < 0)
+ return -1;
+ for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, sz);
+ nh = NLMSG_NEXT (nh, sz))
+ {
+ /*
+ * Unpack the netlink message into a bunch of... well...
+ * netlink messages. The terminology is overloaded. Walk
+ * through the message until we find a header of type
+ * NLMSG_DONE.
+ */
+ if (nh->nlmsg_type == NLMSG_DONE)
+ break;
+ if (nh->nlmsg_type != RTM_NEWROUTE)
+ continue;
+ /*
+ * Clear out the socket so we don't keep old messages
+ * queued up and eventually overflow the receive buffer.
+ */
+ while (read (rtc->netlinkfd, buf, sizeof (buf)) > 0)
+ /* loop through receive queue */;
+ if (errno != EAGAIN) return -1;
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * Blocks until we get a route status change message then calls
+ * route_process(). Returns 0 if there was a route state change, 1 if there
+ * was a timeout, and -1 if there was a read error.
+ */
+int API
+routeup_once (struct routeup *rtc, unsigned int timeout)
+{
+ int ret;
+ struct timeval remaining;
+ struct timeval *rp = timeout ? &remaining : NULL;
+ fd_set fds;
+ remaining.tv_sec = timeout;
+ remaining.tv_usec = 0;
+ FD_ZERO (&fds);
+ FD_SET (rtc->netlinkfd, &fds);
+ while (select (rtc->netlinkfd + 1, &fds, NULL, NULL, rp) >= 0)
+ {
+ FD_ZERO (&fds);
+ FD_SET (rtc->netlinkfd, &fds);
+ if (timeout && !remaining.tv_sec && !remaining.tv_usec)
+ return 1;
+ ret = routeup_process (rtc);
+ if (ret == 1)
+ continue;
+ return ret;
+ }
+ return -1;
+}
+
+/* Tear down the supplied context by closing its netlink socket. */
+void API
+routeup_teardown (struct routeup *rtc)
+{
+ close (rtc->netlinkfd);
+}
+
+#ifdef ROUTEUP_MAIN
+int API
+main ()
+{
+ struct routeup rtc;
+ if (routeup_setup (&rtc))
+ return 1;
+ while (!routeup_once (&rtc, 0))
+ {
+ printf ("n\n");
+ fflush (stdout);
+ }
+ routeup_teardown (&rtc);
+ return 0;
+}
+#endif /* ROUTEUP_MAIN */
diff --git a/src/routeup.h b/src/routeup.h
new file mode 100644
index 0000000..29d87e2
--- /dev/null
+++ b/src/routeup.h
@@ -0,0 +1,44 @@
+/*
+ * routeup.h - routeup library interface
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Call routeup_setup() to initialize a routeup context, then call
+ * routeup_once() until it returns nonzero (indicating an error) or until
+ * you're no longer interested in route changes. Call routeup_teardown()
+ * when you're done with an routeup context.
+ */
+
+#ifndef ROUTEUP_H
+#define ROUTEUP_H
+
+struct routeup
+{
+ int netlinkfd; /* AF_NETLINK event socket */
+};
+
+#ifdef TARGET_OS_LINUX
+int routeup_setup (struct routeup *ifc);
+int routeup_once (struct routeup *ifc, unsigned int timeout);
+int routeup_process (struct routeup *rtc);
+void routeup_teardown (struct routeup *ifc);
+#else
+static inline int routeup_setup (struct routeup *ifc)
+{
+ return 1; /* Fail for platforms without support. */
+}
+static inline int routeup_once (struct routeup *ifc, unsigned int timeout)
+{
+ return -1;
+}
+static inline int routeup_process (struct routeup *rtc)
+{
+ return -1;
+}
+static inline void routeup_teardown (struct routeup *ifc)
+{
+}
+#endif
+
+#endif /* !ROUTEUP_H */
diff --git a/src/rtc.h b/src/rtc.h
new file mode 100644
index 0000000..2017e96
--- /dev/null
+++ b/src/rtc.h
@@ -0,0 +1,9 @@
+#ifndef RTC_H
+#define RTC_H
+
+struct rtc_handle
+{
+ int fd;
+};
+
+#endif /* RTC_H */
diff --git a/src/seccomp-compat.h b/src/seccomp-compat.h
new file mode 100644
index 0000000..9f1da87
--- /dev/null
+++ b/src/seccomp-compat.h
@@ -0,0 +1,32 @@
+/*
+ * seccomp-compat.h - seccomp defines for bad headers
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SECCOMP_COMPAT_H
+#define SECCOMP_COMPAT_H
+
+#include <stdint.h>
+
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+#endif
+
+#ifndef SECCOMP_MODE_FILTER
+#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */
+#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */
+#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */
+#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */
+#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */
+
+struct seccomp_data
+{
+ int nr;
+ uint32_t arch;
+ uint64_t instruction_pointer;
+ uint64_t args[6];
+};
+#endif /* !SECCOMP_MODE_FILTER */
+
+#endif
diff --git a/src/seccomp.c b/src/seccomp.c
new file mode 100644
index 0000000..fbc5a33
--- /dev/null
+++ b/src/seccomp.c
@@ -0,0 +1,117 @@
+/*
+ * seccomp.c - seccomp utility functions
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <asm/unistd.h>
+#include <elf.h>
+#include <errno.h>
+#include <sys/prctl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <linux/audit.h>
+#include <linux/filter.h>
+
+#include "src/seccomp.h"
+
+/* Linux seccomp_filter sandbox */
+#define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL
+
+/* Use a signal handler to emit violations when debugging */
+#ifdef SECCOMP_FILTER_DEBUG
+# undef SECCOMP_FILTER_FAIL
+# define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP
+#endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
+
+/* Simple helpers to avoid manual errors (but larger BPF programs). */
+#define SC_DENY(_nr, _errno) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \
+ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno))
+#define SC_ALLOW(_nr) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \
+ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
+
+#if defined(__i386__)
+# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386
+#elif defined(__x86_64__)
+# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64
+#elif defined(__arm__)
+# ifndef EM_ARM
+# define EM_ARM 40
+# endif
+# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM
+#else
+# error "Platform does not support seccomp filter yet"
+#endif
+
+/* Returns 0 if the the sandbox is enabled using
+ * the time setter policy.
+ */
+int
+enable_setter_seccomp (void)
+{
+ static const struct sock_filter insns[] =
+ {
+ /* Ensure the syscall arch convention is as expected. */
+ BPF_STMT (BPF_LD+BPF_W+BPF_ABS,
+ offsetof (struct seccomp_data, arch)),
+ BPF_JUMP (BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0),
+ BPF_STMT (BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
+ /* Load the syscall number for checking. */
+ BPF_STMT (BPF_LD+BPF_W+BPF_ABS,
+ offsetof (struct seccomp_data, nr)),
+
+ /* Process ALLOWs as quickly as possible */
+ SC_ALLOW (read),
+ SC_ALLOW (write),
+ SC_ALLOW (pwritev),
+
+ SC_ALLOW (settimeofday),
+ SC_ALLOW (ioctl), /* TODO(wad) filter for fd and RTC_SET_TIME */
+#ifdef __NR_time /* This is required for x86 systems */
+ SC_ALLOW (time),
+#endif
+
+ SC_ALLOW (lseek),
+ SC_ALLOW (close),
+ SC_ALLOW (munmap),
+
+ SC_ALLOW (exit_group),
+ SC_ALLOW (exit),
+
+ SC_DENY (open, EINVAL),
+ SC_DENY (fcntl, EINVAL),
+ SC_DENY (fstat, EINVAL),
+#ifdef __NR_mmap
+ SC_DENY (mmap, EINVAL),
+#endif
+#ifdef __NR_mmap2
+ SC_DENY (mmap2, EINVAL),
+#endif
+#ifdef __NR_sendto
+ SC_DENY (sendto, EINVAL),
+#endif
+#ifdef __NR_socket
+ SC_DENY (socket, EINVAL),
+#endif
+#ifdef __NR_socketcall
+ SC_DENY (socketcall, EINVAL),
+#endif
+ BPF_STMT (BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
+ };
+ static const struct sock_fprog prog =
+ {
+ .len = (unsigned short) (sizeof (insns) /sizeof (insns[0])),
+ .filter = (struct sock_filter *) insns,
+ };
+ return (prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) ||
+ prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog));
+}
diff --git a/src/seccomp.h b/src/seccomp.h
new file mode 100644
index 0000000..5f4a5f3
--- /dev/null
+++ b/src/seccomp.h
@@ -0,0 +1,24 @@
+/*
+ * seccomp.h - seccomp functions
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SECCOMP_H
+#define SECCOMP_H
+
+#include "config.h"
+
+#include "src/seccomp-compat.h"
+
+#ifdef HAVE_SECCOMP_FILTER
+int enable_setter_seccomp (void);
+#else /* HAVE_SECCOMP_FILTER */
+static
+inline int enable_setter_seccomp (void)
+{
+ return 0;
+}
+#endif /* !HAVE_SECCOMP_FILTER */
+
+#endif
diff --git a/src/test-bio.c b/src/test-bio.c
new file mode 100644
index 0000000..de8dd37
--- /dev/null
+++ b/src/test-bio.c
@@ -0,0 +1,156 @@
+/*
+ * test-bio.c - BIO layer for testing
+ *
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * This is a 'source/sink' BIO which supports synthetic inputs and outputs, and
+ * can be used to drive filter BIOs through a state machine. It buffers all
+ * output sent to it, which can be retrieved with BIO_test_get_output(), and
+ * input sent to it, which is handed back in response to BIO_read() by the
+ * filter BIO.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "src/test-bio.h"
+#include "src/util.h"
+
+int verbose;
+int verbose_debug;
+
+static const unsigned int kMagic = 0x5f8d3f15;
+
+struct test_ctx
+{
+ unsigned int magic;
+ unsigned char *out;
+ size_t outsz;
+ unsigned char *in;
+ size_t insz;
+};
+
+static struct test_ctx *bio_ctx (BIO *b)
+{
+ struct test_ctx *ctx = b->ptr;
+ assert (ctx->magic == kMagic);
+ return ctx;
+}
+
+static size_t buf_drain (unsigned char **buf, size_t *bufsz,
+ unsigned char *out, size_t outsz)
+{
+ if (*bufsz < outsz)
+ outsz = *bufsz;
+ memcpy (out, *buf, outsz);
+ if (*bufsz > outsz)
+ memmove (*buf, *buf + outsz, *bufsz - outsz);
+ *bufsz -= outsz;
+ *buf = realloc (*buf, *bufsz);
+ return outsz;
+}
+
+static void buf_fill (unsigned char **buf, size_t *bufsz,
+ const unsigned char *in, size_t insz)
+{
+ *buf = realloc (*buf, *bufsz + insz);
+ memcpy (*buf + *bufsz, in, insz);
+ *bufsz += insz;
+}
+
+int test_new (BIO *b)
+{
+ struct test_ctx *ctx = malloc (sizeof *ctx);
+ if (!ctx)
+ return 0;
+ ctx->magic = kMagic;
+ ctx->in = NULL;
+ ctx->insz = 0;
+ ctx->out = NULL;
+ ctx->outsz = 0;
+ b->init = 1;
+ b->flags = 0;
+ b->ptr = ctx;
+ return 1;
+}
+
+int test_free (BIO *b)
+{
+ struct test_ctx *ctx;
+ if (!b || !b->ptr)
+ return 1;
+ ctx = bio_ctx (b);
+ free (ctx->in);
+ free (ctx->out);
+ return 1;
+}
+
+int test_write (BIO *b, const char *buf, int sz)
+{
+ struct test_ctx *ctx = bio_ctx (b);
+ if (sz <= 0)
+ return 0;
+ buf_fill (&ctx->out, &ctx->outsz, (unsigned char *) buf, sz);
+ return sz;
+}
+
+int test_read (BIO *b, char *buf, int sz)
+{
+ struct test_ctx *ctx = bio_ctx (b);
+ if (sz <= 0)
+ return 0;
+ return buf_drain (&ctx->in, &ctx->insz, (unsigned char *) buf, sz);
+}
+
+long test_ctrl (BIO *b, int cmd, long num, void *ptr)
+{
+ return 0;
+}
+
+long test_callback_ctrl (BIO *b, int cmd, bio_info_cb *fp)
+{
+ return 0;
+}
+
+BIO_METHOD test_methods =
+{
+ BIO_TYPE_SOCKET,
+ "test",
+ test_write,
+ test_read,
+ NULL,
+ NULL,
+ test_ctrl,
+ test_new,
+ test_free,
+ test_callback_ctrl,
+};
+
+BIO_METHOD *BIO_s_test()
+{
+ return &test_methods;
+}
+
+BIO API *BIO_new_test()
+{
+ return BIO_new (BIO_s_test());
+}
+
+size_t API BIO_test_output_left (BIO *b)
+{
+ return bio_ctx (b)->outsz;
+}
+
+size_t API BIO_test_get_output (BIO *b, unsigned char *buf, size_t bufsz)
+{
+ struct test_ctx *c = bio_ctx (b);
+ return buf_drain (&c->out, &c->outsz, buf, bufsz);
+}
+
+void API BIO_test_add_input (BIO *b, const unsigned char *buf, size_t bufsz)
+{
+ struct test_ctx *c = bio_ctx (b);
+ return buf_fill (&c->in, &c->insz, buf, bufsz);
+}
diff --git a/src/test-bio.h b/src/test-bio.h
new file mode 100644
index 0000000..dcf1721
--- /dev/null
+++ b/src/test-bio.h
@@ -0,0 +1,20 @@
+/*
+ * test-bio.h - test BIO that stores reads/writes
+ *
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef TEST_BIO_H
+#define TEST_BIO_H
+
+#include <openssl/bio.h>
+
+BIO *BIO_new_test();
+
+size_t BIO_test_output_left (BIO *b);
+size_t BIO_test_get_output (BIO *b, unsigned char *buf, size_t bufsz);
+void BIO_test_add_input (BIO *b, const unsigned char *buf, size_t bufsz);
+
+#endif /* !TEST_BIO_H */
diff --git a/src/test/check-host-1.c b/src/test/check-host-1.c
new file mode 100644
index 0000000..33f745a
--- /dev/null
+++ b/src/test/check-host-1.c
@@ -0,0 +1,27 @@
+/* test returns a "sane" time if the host, port, and proxy
+ * are passed in properly on the commandline. The test
+ * is invoked by tlsdated instead of tlsdate.
+ * This expects host1, port1, proxy1.
+ *
+ * Paired with check-host-2.c, it allows for source rotation
+ * testing.
+ */
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int main (int argc, char *argv[])
+{
+ unsigned int t = RECENT_COMPILE_DATE + 1;
+ if (argc < 7)
+ return 3;
+ if (!strcmp (argv[2], "host1")
+ && !strcmp (argv[4], "port1")
+ && !strcmp (argv[6], "proxy1"))
+ {
+ fwrite (&t, sizeof (t), 1, stdout);
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/test/check-host-2.c b/src/test/check-host-2.c
new file mode 100644
index 0000000..869a865
--- /dev/null
+++ b/src/test/check-host-2.c
@@ -0,0 +1,26 @@
+/* test returns a "sane" time if the host, port, and proxy
+ * are passed in properly on the commandline. The test
+ * is invoked by tlsdated instead of tlsdate.
+ * This expects host2, port2, proxy2.
+ *
+ * Paired with check-host-2.c, it allows for source rotation
+ * testing.
+ */
+#include "config.h"
+#include <string.h>
+#include <stdio.h>
+
+int main (int argc, char *argv[])
+{
+ unsigned int t = RECENT_COMPILE_DATE + 1;
+ if (argc < 7)
+ return 3;
+ if (!strcmp (argv[2], "host2")
+ && !strcmp (argv[4], "port2")
+ && !strcmp (argv[6], "proxy2"))
+ {
+ fwrite (&t, sizeof (t), 1, stdout);
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/test/emit.c b/src/test/emit.c
new file mode 100644
index 0000000..2c9d8e7
--- /dev/null
+++ b/src/test/emit.c
@@ -0,0 +1,18 @@
+/* Integration test helper which will print out
+ * the given time in seconds as an unsigned int.
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main (int argc, char *argv[])
+{
+ /* Unsigned int to match what tlsdate -Vraw returns, not time_t */
+ unsigned int t = argc > 1 ? (unsigned int) atoi(argv[1]) :
+ RECENT_COMPILE_DATE + 1;
+ fwrite (&t, sizeof (t), 1, stdout);
+ fflush(stdout);
+ return 0;
+}
diff --git a/src/test/proxy-override.c b/src/test/proxy-override.c
new file mode 100644
index 0000000..39abdc6
--- /dev/null
+++ b/src/test/proxy-override.c
@@ -0,0 +1,32 @@
+/* This test is called in lieu of tlsdate by tlsdated
+ * and it returns a timestamp that matches the proxy
+ * ordering - global, dynamic, etc.
+ * For use, see tlsdated-unittests.c
+ */
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int main (int argc, char *argv[])
+{
+ /* Unsigned int to match what tlsdate -Vraw returns, not time_t */
+ /* TODO(wad) move tlsdated -Vraw to emitting time_t */
+ unsigned int t = RECENT_COMPILE_DATE + 1;
+ int saw_good_proxy = 0;
+ while (argc--)
+ {
+ if (!strcmp (argv[0], "socks5://good.proxy"))
+ saw_good_proxy = 1;
+ if (!strcmp (argv[0], "socks5://bad.proxy"))
+ {
+ t = RECENT_COMPILE_DATE + 3;
+ break;
+ }
+ argv++;
+ }
+ if (saw_good_proxy)
+ t = RECENT_COMPILE_DATE + 2;
+ fwrite (&t, sizeof (t), 1, stdout);
+ return 0;
+}
diff --git a/src/test/return-argc.c b/src/test/return-argc.c
new file mode 100644
index 0000000..3bcface
--- /dev/null
+++ b/src/test/return-argc.c
@@ -0,0 +1,3 @@
+/* return-argc.c - returns argc */
+
+int main(int argc, char *argv[]) { return argc; }
diff --git a/src/test/sleep-wrap.c b/src/test/sleep-wrap.c
new file mode 100644
index 0000000..d45d92f
--- /dev/null
+++ b/src/test/sleep-wrap.c
@@ -0,0 +1,20 @@
+/* Test invoked by tlsdated instead of tlsdate to
+ * show allow arbitrary delays before returning a
+ * "sane" time. This makes for easy timeout testing.
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main (int argc, char *argv[])
+{
+ /* Unsigned int to match what tlsdate -Vraw returns, not time_t */
+ unsigned int t = RECENT_COMPILE_DATE + 1;
+ if (argc < 2)
+ return 1;
+ sleep (atoi (argv[1]));
+ fwrite (&t, sizeof (t), 1, stdout);
+ return 0;
+}
diff --git a/src/test_harness.h b/src/test_harness.h
new file mode 100644
index 0000000..3fd118a
--- /dev/null
+++ b/src/test_harness.h
@@ -0,0 +1,451 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * test_harness.h: simple C unit test helper.
+ *
+ * Usage:
+ * #include "test_harness.h"
+ * TEST(standalone_test) {
+ * do_some_stuff;
+ * EXPECT_GT(10, stuff) {
+ * stuff_state_t state;
+ * enumerate_stuff_state(&state);
+ * TH_LOG("expectation failed with state: %s", state.msg);
+ * }
+ * more_stuff;
+ * ASSERT_NE(some_stuff, NULL) TH_LOG("how did it happen?!");
+ * last_stuff;
+ * EXPECT_EQ(0, last_stuff);
+ * }
+ *
+ * FIXTURE(my_fixture) {
+ * mytype_t *data;
+ * int awesomeness_level;
+ * };
+ * FIXTURE_SETUP(my_fixture) {
+ * self->data = mytype_new();
+ * ASSERT_NE(NULL, self->data);
+ * }
+ * FIXTURE_TEARDOWN(my_fixture) {
+ * mytype_free(self->data);
+ * }
+ * TEST_F(my_fixture, data_is_good) {
+ * EXPECT_EQ(1, is_my_data_good(self->data));
+ * }
+ *
+ * TEST_HARNESS_MAIN
+ *
+ * API inspired by code.google.com/p/googletest
+ */
+#ifndef TEST_HARNESS_H_
+#define TEST_HARNESS_H_
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/* All exported functionality should be declared through this macro. */
+#define TEST_API(x) _##x
+
+/*
+ * Exported APIs
+ */
+
+/* TEST(name) { implementation }
+ * Defines a test by name.
+ * Names must be unique and tests must not be run in parallel. The
+ * implementation containing block is a function and scoping should be treated
+ * as such. Returning early may be performed with a bare "return;" statement.
+ *
+ * EXPECT_* and ASSERT_* are valid in a TEST() { } context.
+ */
+#define TEST TEST_API(TEST)
+
+/* FIXTURE(datatype name) {
+ * type property1;
+ * ...
+ * };
+ * Defines the data provided to TEST_F()-defined tests as |self|. It should be
+ * populated and cleaned up using FIXTURE_SETUP and FIXTURE_TEARDOWN.
+ */
+#define FIXTURE TEST_API(FIXTURE)
+
+/* FIXTURE_DATA(datatype name)
+ * This call may be used when the type of the fixture data
+ * is needed. In general, this should not be needed unless
+ * the |self| is being passed to a helper directly.
+ */
+#define FIXTURE_DATA TEST_API(FIXTURE_DATA)
+
+/* FIXTURE_SETUP(fixture name) { implementation }
+ * Populates the required "setup" function for a fixture. An instance of the
+ * datatype defined with _FIXTURE_DATA will be exposed as |self| for the
+ * implementation.
+ *
+ * ASSERT_* are valid for use in this context and will prempt the execution
+ * of any dependent fixture tests.
+ *
+ * A bare "return;" statement may be used to return early.
+ */
+#define FIXTURE_SETUP TEST_API(FIXTURE_SETUP)
+
+/* FIXTURE_TEARDOWN(fixture name) { implementation }
+ * Populates the required "teardown" function for a fixture. An instance of the
+ * datatype defined with _FIXTURE_DATA will be exposed as |self| for the
+ * implementation to clean up.
+ *
+ * A bare "return;" statement may be used to return early.
+ */
+#define FIXTURE_TEARDOWN TEST_API(FIXTURE_TEARDOWN)
+
+/* TEST_F(fixture, name) { implementation }
+ * Defines a test that depends on a fixture (e.g., is part of a test case).
+ * Very similar to TEST() except that |self| is the setup instance of fixture's
+ * datatype exposed for use by the implementation.
+ */
+#define TEST_F TEST_API(TEST_F)
+
+/* Use once to append a main() to the test file. E.g.,
+ * TEST_HARNESS_MAIN
+ */
+#define TEST_HARNESS_MAIN TEST_API(TEST_HARNESS_MAIN)
+
+/*
+ * Operators for use in TEST and TEST_F.
+ * ASSERT_* calls will stop test execution immediately.
+ * EXPECT_* calls will emit a failure warning, note it, and continue.
+ */
+
+/* ASSERT_EQ(expected, measured): expected == measured */
+#define ASSERT_EQ TEST_API(ASSERT_EQ)
+/* ASSERT_NE(expected, measured): expected != measured */
+#define ASSERT_NE TEST_API(ASSERT_NE)
+/* ASSERT_LT(expected, measured): expected < measured */
+#define ASSERT_LT TEST_API(ASSERT_LT)
+/* ASSERT_LE(expected, measured): expected <= measured */
+#define ASSERT_LE TEST_API(ASSERT_LE)
+/* ASSERT_GT(expected, measured): expected > measured */
+#define ASSERT_GT TEST_API(ASSERT_GT)
+/* ASSERT_GE(expected, measured): expected >= measured */
+#define ASSERT_GE TEST_API(ASSERT_GE)
+/* ASSERT_NULL(measured): NULL == measured */
+#define ASSERT_NULL TEST_API(ASSERT_NULL)
+/* ASSERT_TRUE(measured): measured != 0 */
+#define ASSERT_TRUE TEST_API(ASSERT_TRUE)
+/* ASSERT_FALSE(measured): measured == 0 */
+#define ASSERT_FALSE TEST_API(ASSERT_FALSE)
+/* ASSERT_STREQ(expected, measured): !strcmp(expected, measured) */
+#define ASSERT_STREQ TEST_API(ASSERT_STREQ)
+/* ASSERT_STRNE(expected, measured): strcmp(expected, measured) */
+#define ASSERT_STRNE TEST_API(ASSERT_STRNE)
+/* EXPECT_EQ(expected, measured): expected == measured */
+#define EXPECT_EQ TEST_API(EXPECT_EQ)
+/* EXPECT_NE(expected, measured): expected != measured */
+#define EXPECT_NE TEST_API(EXPECT_NE)
+/* EXPECT_LT(expected, measured): expected < measured */
+#define EXPECT_LT TEST_API(EXPECT_LT)
+/* EXPECT_LE(expected, measured): expected <= measured */
+#define EXPECT_LE TEST_API(EXPECT_LE)
+/* EXPECT_GT(expected, measured): expected > measured */
+#define EXPECT_GT TEST_API(EXPECT_GT)
+/* EXPECT_GE(expected, measured): expected >= measured */
+#define EXPECT_GE TEST_API(EXPECT_GE)
+/* EXPECT_NULL(measured): NULL == measured */
+#define EXPECT_NULL TEST_API(EXPECT_NULL)
+/* EXPECT_TRUE(measured): 0 != measured */
+#define EXPECT_TRUE TEST_API(EXPECT_TRUE)
+/* EXPECT_FALSE(measured): 0 == measured */
+#define EXPECT_FALSE TEST_API(EXPECT_FALSE)
+/* EXPECT_STREQ(expected, measured): !strcmp(expected, measured) */
+#define EXPECT_STREQ TEST_API(EXPECT_STREQ)
+/* EXPECT_STRNE(expected, measured): strcmp(expected, measured) */
+#define EXPECT_STRNE TEST_API(EXPECT_STRNE)
+
+/* TH_LOG(format, ...)
+ * Optional debug logging function available for use in tests.
+ * Logging may be enabled or disabled by defining TH_LOG_ENABLED.
+ * E.g., #define TH_LOG_ENABLED 1
+ * If no definition is provided, logging is enabled by default.
+ */
+#define TH_LOG TEST_API(TH_LOG)
+
+/*
+ * Internal implementation.
+ *
+ */
+
+/* Utilities exposed to the test definitions */
+#ifndef TH_LOG_STREAM
+# define TH_LOG_STREAM stderr
+#endif
+
+#ifndef TH_LOG_ENABLED
+# define TH_LOG_ENABLED 1
+#endif
+
+#define _TH_LOG(fmt, ...) do { \
+ if (TH_LOG_ENABLED) \
+ __TH_LOG(fmt, ##__VA_ARGS__); \
+} while (0)
+
+/* Unconditional logger for internal use. */
+#define __TH_LOG(fmt, ...) \
+ fprintf(TH_LOG_STREAM, "%s:%d:%s:" fmt "\n", \
+ __FILE__, __LINE__, _metadata->name, ##__VA_ARGS__)
+
+/* Defines the test function and creates the registration stub. */
+#define _TEST(test_name) \
+ static void test_name(struct __test_metadata *_metadata); \
+ static struct __test_metadata _##test_name##_object = \
+ { name: "global." #test_name, fn: &test_name }; \
+ static void __attribute__((constructor)) _register_##test_name(void) { \
+ __register_test(&_##test_name##_object); \
+ } \
+ static void test_name( \
+ struct __test_metadata __attribute__((unused)) *_metadata)
+
+/* Wraps the struct name so we have one less argument to pass around. */
+#define _FIXTURE_DATA(fixture_name) struct _test_data_##fixture_name
+
+/* Called once per fixture to setup the data and register. */
+#define _FIXTURE(fixture_name) \
+ static void __attribute__((constructor)) \
+ _register_##fixture_name##_data(void) { \
+ __fixture_count++; \
+ } \
+ _FIXTURE_DATA(fixture_name)
+
+/* Prepares the setup function for the fixture. |_metadata| is included
+ * so that ASSERT_* work as a convenience.
+ */
+#define _FIXTURE_SETUP(fixture_name) \
+ void fixture_name##_setup( \
+ struct __test_metadata __attribute__((unused)) *_metadata, \
+ _FIXTURE_DATA(fixture_name) __attribute__((unused)) *self)
+#define _FIXTURE_TEARDOWN(fixture_name) \
+ void fixture_name##_teardown( \
+ struct __test_metadata __attribute__((unused)) *_metadata, \
+ _FIXTURE_DATA(fixture_name) __attribute__((unused)) *self)
+
+/* Emits test registration and helpers for fixture-based test
+ * cases.
+ * TODO(wad) register fixtures on dedicated test lists.
+ */
+#define _TEST_F(fixture_name, test_name) \
+ static void fixture_name##_##test_name( \
+ struct __test_metadata *_metadata, \
+ _FIXTURE_DATA(fixture_name) *self); \
+ static inline void wrapper_##fixture_name##_##test_name( \
+ struct __test_metadata *_metadata) { \
+ /* fixture data is allocated, setup, and torn down per call. */ \
+ _FIXTURE_DATA(fixture_name) self; \
+ memset(&self, 0, sizeof(_FIXTURE_DATA(fixture_name))); \
+ fixture_name##_setup(_metadata, &self); \
+ /* Let setup failure terminate early. */ \
+ if (!_metadata->passed) return; \
+ fixture_name##_##test_name(_metadata, &self); \
+ fixture_name##_teardown(_metadata, &self); \
+ } \
+ static struct __test_metadata _##fixture_name##_##test_name##_object = { \
+ name: #fixture_name "." #test_name, \
+ fn: &wrapper_##fixture_name##_##test_name, \
+ }; \
+ static void __attribute__((constructor)) \
+ _register_##fixture_name##_##test_name(void) { \
+ __register_test(&_##fixture_name##_##test_name##_object); \
+ } \
+ static void fixture_name##_##test_name( \
+ struct __test_metadata __attribute__((unused)) *_metadata, \
+ _FIXTURE_DATA(fixture_name) __attribute__((unused)) *self)
+
+/* Exports a simple wrapper to run the test harness. */
+#define _TEST_HARNESS_MAIN \
+ int main(int argc, char **argv) { return test_harness_run(argc, argv); }
+
+#define _ASSERT_EQ(_expected, _seen) \
+ __EXPECT(_expected, _seen, ==, 1)
+#define _ASSERT_NE(_expected, _seen) \
+ __EXPECT(_expected, _seen, !=, 1)
+#define _ASSERT_LT(_expected, _seen) \
+ __EXPECT(_expected, _seen, <, 1)
+#define _ASSERT_LE(_expected, _seen) \
+ __EXPECT(_expected, _seen, <=, 1)
+#define _ASSERT_GT(_expected, _seen) \
+ __EXPECT(_expected, _seen, >, 1)
+#define _ASSERT_GE(_expected, _seen) \
+ __EXPECT(_expected, _seen, >=, 1)
+#define _ASSERT_NULL(_seen) \
+ __EXPECT(NULL, _seen, ==, 1)
+
+#define _ASSERT_TRUE(_seen) \
+ _ASSERT_NE(0, _seen)
+#define _ASSERT_FALSE(_seen) \
+ _ASSERT_EQ(0, _seen)
+#define _ASSERT_STREQ(_expected, _seen) \
+ __EXPECT_STR(_expected, _seen, ==, 1)
+#define _ASSERT_STRNE(_expected, _seen) \
+ __EXPECT_STR(_expected, _seen, !=, 1)
+
+#define _EXPECT_EQ(_expected, _seen) \
+ __EXPECT(_expected, _seen, ==, 0)
+#define _EXPECT_NE(_expected, _seen) \
+ __EXPECT(_expected, _seen, !=, 0)
+#define _EXPECT_LT(_expected, _seen) \
+ __EXPECT(_expected, _seen, <, 0)
+#define _EXPECT_LE(_expected, _seen) \
+ __EXPECT(_expected, _seen, <=, 0)
+#define _EXPECT_GT(_expected, _seen) \
+ __EXPECT(_expected, _seen, >, 0)
+#define _EXPECT_GE(_expected, _seen) \
+ __EXPECT(_expected, _seen, >=, 0)
+
+#define _EXPECT_NULL(_seen) \
+ __EXPECT(NULL, _seen, ==, 0)
+#define _EXPECT_TRUE(_seen) \
+ _EXPECT_NE(0, _seen)
+#define _EXPECT_FALSE(_seen) \
+ _EXPECT_EQ(0, _seen)
+
+#define _EXPECT_STREQ(_expected, _seen) \
+ __EXPECT_STR(_expected, _seen, ==, 0)
+#define _EXPECT_STRNE(_expected, _seen) \
+ __EXPECT_STR(_expected, _seen, !=, 0)
+
+/* Support an optional handler after and ASSERT_* or EXPECT_*. The approach is
+ * not thread-safe, but it should be fine in most sane test scenarios.
+ *
+ * Using __bail(), which optionally abort()s, is the easiest way to early
+ * return while still providing an optional block to the API consumer.
+ */
+#define OPTIONAL_HANDLER(_assert) \
+ for (; _metadata->trigger; _metadata->trigger = __bail(_assert))
+
+#define __EXPECT(_expected, _seen, _t, _assert) do { \
+ /* Avoid multiple evaluation of the cases */ \
+ __typeof__(_expected) __exp = (_expected); \
+ __typeof__(_seen) __seen = (_seen); \
+ if (!(__exp _t __seen)) { \
+ unsigned long long __exp_print = 0; \
+ unsigned long long __seen_print = 0; \
+ /* Avoid casting complaints the scariest way we can. */ \
+ memcpy(&__exp_print, &__exp, sizeof(__exp)); \
+ memcpy(&__seen_print, &__seen, sizeof(__seen)); \
+ __TH_LOG("Expected %s (%llu) %s %s (%llu)", \
+ #_expected, __exp_print, #_t, \
+ #_seen, __seen_print); \
+ _metadata->passed = 0; \
+ /* Ensure the optional handler is triggered */ \
+ _metadata->trigger = 1; \
+ } \
+} while (0); OPTIONAL_HANDLER(_assert)
+
+#define __EXPECT_STR(_expected, _seen, _t, _assert) do { \
+ const char *__exp = (_expected); \
+ const char *__seen = (_seen); \
+ if (!(strcmp(__exp, __seen) _t 0)) { \
+ __TH_LOG("Expected '%s' %s '%s'.", __exp, #_t, __seen); \
+ _metadata->passed = 0; \
+ _metadata->trigger = 1; \
+ } \
+} while (0); OPTIONAL_HANDLER(_assert)
+
+/* Contains all the information for test execution and status checking. */
+struct __test_metadata
+{
+ const char *name;
+ void (*fn) (struct __test_metadata *);
+ int passed;
+ int trigger; /* extra handler after the evaluation */
+ struct __test_metadata *prev, *next;
+};
+
+/* Storage for the (global) tests to be run. */
+static struct __test_metadata *__test_list = NULL;
+static unsigned int __test_count = 0;
+static unsigned int __fixture_count = 0;
+
+static inline void __register_test (struct __test_metadata *t)
+{
+ __test_count++;
+ /* Circular linked list where only prev is circular. */
+ if (__test_list == NULL)
+ {
+ __test_list = t;
+ t->next = NULL;
+ t->prev = t;
+ return;
+ }
+ t->next = NULL;
+ t->prev = __test_list->prev;
+ t->prev->next = t;
+ __test_list->prev = t;
+}
+
+static inline int __bail (int for_realz)
+{
+ if (for_realz)
+ abort();
+ return 0;
+}
+
+static int test_harness_run (int __attribute__ ( (unused)) argc,
+ char __attribute__ ( (unused)) **argv)
+{
+ struct __test_metadata *t;
+ int ret = 0;
+ unsigned int count = 0;
+ /* TODO(wad) add optional arguments similar to gtest. */
+ printf ("[==========] Running %u tests from %u test cases.\n",
+ __test_count, __fixture_count + 1);
+ for (t = __test_list; t; t = t->next)
+ {
+ pid_t child_pid;
+ int status;
+ count++;
+ t->passed = 1;
+ t->trigger = 0;
+ printf ("[ RUN ] %s\n", t->name);
+ child_pid = fork();
+ if (child_pid < 0)
+ {
+ printf ("ERROR SPAWNING TEST CHILD\n");
+ t->passed = 0;
+ }
+ else if (child_pid == 0)
+ {
+ t->fn (t);
+ _exit (t->passed);
+ }
+ else
+ {
+ /* TODO(wad) add timeout support. */
+ waitpid (child_pid, &status, 0);
+ if (WIFEXITED (status))
+ t->passed = WEXITSTATUS (status);
+ if (WIFSIGNALED (status))
+ {
+ t->passed = 0;
+ fprintf (TH_LOG_STREAM,
+ "%s: Test terminated unexpectedly by signal %d\n",
+ t->name,
+ WTERMSIG (status));
+ }
+ }
+ printf ("[ %4s ] %s\n", (t->passed ? "OK" : "FAIL"), t->name);
+ if (!t->passed)
+ ret = 1;
+ }
+ /* TODO(wad) organize by fixtures since ordering is not guaranteed now. */
+ printf ("[==========] %u tests ran.\n", count);
+ printf ("[ %s ]\n", (ret ? "FAILED" : "PASSED"));
+ return ret;
+}
+
+#endif /* TEST_HARNESS_H_ */
diff --git a/src/tlsdate-helper-plan9.c b/src/tlsdate-helper-plan9.c
new file mode 100644
index 0000000..3c532aa
--- /dev/null
+++ b/src/tlsdate-helper-plan9.c
@@ -0,0 +1,1250 @@
+/* Copyright (c) 2012, Jacob Appelbaum.
+ * Copyright (c) 2012, The Tor Project, Inc.
+ * Copyright (c) 2012, Christian Grothoff. */
+/* See LICENSE for licensing information */
+/*
+ This file contains the license for tlsdate,
+ a free software project to set your system clock securely.
+
+ It also lists the licenses for other components used by tlsdate.
+
+ For more information about tlsdate, see https://github.com/ioerror/tlsdate
+
+ If you got this file as a part of a larger bundle,
+ there may be other license terms that you should be aware of.
+
+===============================================================================
+tlsdate is distributed under this license:
+
+Copyright (c) 2011-2012, Jacob Appelbaum <jacob@appelbaum.net>
+Copyright (c) 2011-2012, The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+If you got tlsdate as a static binary with OpenSSL included, then you should
+know:
+
+ "This product includes software developed by the OpenSSL Project for use in
+ the OpenSSL Toolkit (http://www.openssl.org/)"
+
+===============================================================================
+*/
+
+/**
+ * \file tlsdate-helper.c
+ * \brief Helper program that does the actual work of setting the system clock.
+ **/
+
+/*
+ * tlsdate is a tool for setting the system clock by hand or by communication
+ * with the network. It does not set the RTC. It is designed to be as secure as
+ * TLS (RFC 2246) but of course the security of TLS is often reduced to
+ * whichever CA racket you believe is trustworthy. By default, tlsdate trusts
+ * your local CA root store - so any of these companies could assist in a MITM
+ * attack against you and you'd be screwed.
+
+ * This tool is designed to be run by hand or as a system daemon. It must be
+ * run as root or otherwise have the proper caps; it will not be able to set
+ * the system time without running as root or another privileged user.
+ */
+
+#include "config.h"
+#include "src/tlsdate-helper-plan9.h"
+
+#ifndef USE_POLARSSL
+#include "src/proxy-bio-plan9.h"
+#else
+#include "src/proxy-polarssl.h"
+#endif
+
+#include "src/compat/clock-plan9.h"
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#ifdef USE_POLARSSL
+#include "polarssl/entropy.h"
+#include "polarssl/ctr_drbg.h"
+#include "polarssl/ssl.h"
+#endif
+
+static void
+validate_proxy_scheme(const char *scheme)
+{
+ if (!strcmp(scheme, "http"))
+ return;
+ if (!strcmp(scheme, "socks4"))
+ return;
+ if (!strcmp(scheme, "socks5"))
+ return;
+ die("invalid proxy scheme\n");
+}
+
+static void
+validate_proxy_host(const char *host)
+{
+ const char *kValid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ ".-";
+ if (strspn(host, kValid) != strlen(host))
+ die("invalid char in host\n");
+}
+
+static void
+validate_proxy_port(const char *port)
+{
+ while (*port)
+ if (!isdigit(*port++))
+ die("invalid char in port\n");
+}
+
+static void
+parse_proxy_uri(char *proxy, char **scheme, char **host, char **port)
+{
+ /* Expecting a URI, so: <scheme> '://' <host> ':' <port> */
+ *scheme = proxy;
+ proxy = strstr(proxy, "://");
+ if (!proxy)
+ die("malformed proxy URI\n");
+ *proxy = '\0'; /* terminate scheme string */
+ proxy += strlen("://");
+
+ *host = proxy;
+ proxy = strchr(proxy, ':');
+ if (!proxy)
+ die("malformed proxy URI\n");
+ *proxy++ = '\0';
+
+ *port = proxy;
+
+ validate_proxy_scheme(*scheme);
+ validate_proxy_host(*host);
+ validate_proxy_port(*port);
+}
+
+#ifndef USE_POLARSSL
+static void
+setup_proxy(BIO *ssl)
+{
+ BIO *bio;
+ char *scheme;
+ char *proxy_host;
+ char *proxy_port;
+
+ if (!proxy)
+ return;
+ /*
+ * grab the proxy's host and port out of the URI we have for it. We want the
+ * underlying connect BIO to connect to this, not the target host and port, so
+ * we squirrel away the target host and port in the proxy BIO (as the proxy
+ * target) and swap out the connect BIO's target host and port so it'll
+ * connect to the proxy instead.
+ */
+ parse_proxy_uri(proxy, &scheme, &proxy_host, &proxy_port);
+ bio = BIO_new_proxy();
+ BIO_proxy_set_type(bio, scheme);
+ BIO_proxy_set_host(bio, host);
+ BIO_proxy_set_port(bio, atoi(port));
+ host = proxy_host;
+ port = proxy_port;
+ BIO_push(ssl, bio);
+}
+
+static BIO *
+make_ssl_bio(SSL_CTX *ctx)
+{
+ BIO *con = NULL;
+ BIO *ssl = NULL;
+
+ if (!(con = BIO_new(BIO_s_connect())))
+ die("BIO_s_connect failed\n");
+ if (!(ssl = BIO_new_ssl(ctx, 1)))
+ die("BIO_new_ssl failed\n");
+ setup_proxy(ssl);
+ BIO_push(ssl, con);
+ return ssl;
+}
+
+/** helper function for 'malloc' */
+static void *
+xmalloc (size_t size)
+{
+ void *ptr;
+
+ if (0 == size)
+ die("xmalloc: zero size\n");
+
+ ptr = malloc(size);
+ if (NULL == ptr)
+ die("xmalloc: out of memory (allocating %zu bytes)\n", size);
+
+ return ptr;
+}
+
+
+/** helper function for 'free' */
+static void
+xfree (void *ptr)
+{
+ if (NULL == ptr)
+ die("xfree: NULL pointer given as argument\n");
+
+ free(ptr);
+}
+
+void
+openssl_time_callback (const SSL* ssl, int where, int ret)
+{
+ if (where == SSL_CB_CONNECT_LOOP &&
+ (ssl->state == SSL3_ST_CR_SRVR_HELLO_A || ssl->state == SSL3_ST_CR_SRVR_HELLO_B))
+ {
+ /*
+ // XXX TODO: If we want to trust the remote system for time,
+ // can we just read that time out of the remote system and if the
+ // cert verifies, decide that the time is reasonable?
+ // Such a process seems to indicate that a once valid cert would be
+ // forever valid - we stopgap that by ensuring it isn't less than
+ // the latest compiled_time and isn't above max_reasonable_time...
+ // XXX TODO: Solve eternal question about the Chicken and the Egg...
+ */
+ uint32_t compiled_time = RECENT_COMPILE_DATE;
+ uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
+ uint32_t server_time;
+ verb("V: freezing time for x509 verification\n");
+ memcpy(&server_time, ssl->s3->server_random, sizeof(uint32_t));
+ if (compiled_time < ntohl(server_time)
+ &&
+ ntohl(server_time) < max_reasonable_time)
+ {
+ verb("V: remote peer provided: %d, preferred over compile time: %d\n",
+ ntohl(server_time), compiled_time);
+ verb("V: freezing time with X509_VERIFY_PARAM_set_time\n");
+ X509_VERIFY_PARAM_set_time(ssl->ctx->cert_store->param,
+ (time_t) ntohl(server_time) + 86400);
+ } else {
+ die("V: the remote server is a false ticker! server: %d compile: %d\n",
+ ntohl(server_time), compiled_time);
+ }
+ }
+}
+
+uint32_t
+get_certificate_keybits (EVP_PKEY *public_key)
+{
+ /*
+ In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
+ */
+ uint32_t key_bits;
+ switch (public_key->type)
+ {
+ case EVP_PKEY_RSA:
+ verb("V: key type: EVP_PKEY_RSA\n");
+ key_bits = BN_num_bits(public_key->pkey.rsa->n);
+ break;
+ case EVP_PKEY_RSA2:
+ verb("V: key type: EVP_PKEY_RSA2\n");
+ key_bits = BN_num_bits(public_key->pkey.rsa->n);
+ break;
+ case EVP_PKEY_DSA:
+ verb("V: key type: EVP_PKEY_DSA\n");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DSA1:
+ verb("V: key type: EVP_PKEY_DSA1\n");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DSA2:
+ verb("V: key type: EVP_PKEY_DSA2\n");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DSA3:
+ verb("V: key type: EVP_PKEY_DSA3\n");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DSA4:
+ verb("V: key type: EVP_PKEY_DSA4\n");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DH:
+ verb("V: key type: EVP_PKEY_DH\n");
+ key_bits = BN_num_bits(public_key->pkey.dh->pub_key);
+ break;
+ case EVP_PKEY_EC:
+ verb("V: key type: EVP_PKEY_EC\n");
+ key_bits = EVP_PKEY_bits(public_key);
+ break;
+ // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
+ default:
+ key_bits = 0;
+ die ("unknown public key type\n");
+ break;
+ }
+ verb ("V: keybits: %d\n", key_bits);
+ return key_bits;
+}
+
+uint32_t
+dns_label_count(char *label, char *delim)
+{
+ char *label_tmp;
+ char *saveptr;
+ char *saveptr_tmp;
+ uint32_t label_count;
+
+ label_tmp = strdup(label);
+ label_count = 0;
+ saveptr = NULL;
+ saveptr_tmp = NULL;
+ saveptr = strtok_r(label_tmp, delim, &saveptr);
+ if (NULL != saveptr)
+ {
+ // Did we find our first label?
+ if (saveptr[0] != delim[0])
+ {
+ label_count++;
+ verb ("V: label found; total label count: %d\n", label_count);
+ }
+ do
+ {
+ // Find all subsequent labels
+ label_count++;
+ saveptr_tmp = strtok_r(NULL, delim, &saveptr);
+ verb ("V: label found; total label count: %d\n", label_count);
+ } while (NULL != saveptr_tmp);
+ }
+ free(label_tmp);
+ return label_count;
+}
+
+// first we split strings on '.'
+// then we call each split string a 'label'
+// Do not allow '*' for the top level domain label; eg never allow *.*.com
+// Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
+// Do allow *.example.com
+uint32_t
+check_wildcard_match_rfc2595 (const char *orig_hostname,
+ const char *orig_cert_wild_card)
+{
+ char *hostname;
+ char *hostname_to_free;
+ char *cert_wild_card;
+ char *cert_wild_card_to_free;
+ char *expected_label;
+ char *wildcard_label;
+ char *delim;
+ char *wildchar;
+ uint32_t ok;
+ uint32_t wildcard_encountered;
+ uint32_t label_count;
+
+ // First we copy the original strings
+ hostname = strdup(orig_hostname);
+ cert_wild_card = strdup(orig_cert_wild_card);
+ hostname_to_free = hostname;
+ cert_wild_card_to_free = cert_wild_card;
+ delim = strdup(".");
+ wildchar = strdup("*");
+
+ verb ("V: Inspecting '%s' for possible wildcard match against '%s'\n",
+ hostname, cert_wild_card);
+
+ // By default we have not processed any labels
+ label_count = dns_label_count(cert_wild_card, delim);
+
+ // By default we have no match
+ ok = 0;
+ wildcard_encountered = 0;
+ // First - do we have labels? If not, we refuse to even try to match
+ if ((NULL != strpbrk(cert_wild_card, delim)) &&
+ (NULL != strpbrk(hostname, delim)) &&
+ (label_count <= ((uint32_t)RFC2595_MIN_LABEL_COUNT)))
+ {
+ if (wildchar[0] == cert_wild_card[0])
+ {
+ verb ("V: Found wildcard in at start of provided certificate name\n");
+ do
+ {
+ // Skip over the bytes between the first char and until the next label
+ wildcard_label = strtok(cert_wild_card, delim);
+ expected_label = strtok(hostname, delim);
+ if (NULL != wildcard_label &&
+ NULL != expected_label &&
+ NULL != hostname &&
+ NULL != cert_wild_card)
+ {
+ // Now we only consider this wildcard valid if the rest of the
+ // hostnames match verbatim
+ verb ("V: Attempting match of '%s' against '%s'\n",
+ expected_label, wildcard_label);
+ // This is the case where we have a label that begins with wildcard
+ // Furthermore, we only allow this for the first label
+ if (wildcard_label[0] == wildchar[0] &&
+ 0 == wildcard_encountered && 0 == ok)
+ {
+ verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
+ wildcard_encountered = 1;
+ } else {
+ verb ("V: Attempting match of '%s' against '%s'\n",
+ hostname, cert_wild_card);
+ if (0 == strcasecmp (expected_label, wildcard_label) &&
+ label_count >= ((uint32_t)RFC2595_MIN_LABEL_COUNT))
+ {
+ ok = 1;
+ verb ("V: remaining labels match!\n");
+ break;
+ } else {
+ ok = 0;
+ verb ("V: remaining labels do not match!\n");
+ break;
+ }
+ }
+ } else {
+ // We hit this case when we have a mismatched number of labels
+ verb("V: NULL label; no wildcard here\n");
+ break;
+ }
+ } while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
+ } else {
+ verb ("V: Not a RFC 2595 wildcard\n");
+ }
+ } else {
+ verb ("V: Not a valid wildcard certificate\n");
+ ok = 0;
+ }
+ // Free our copies
+ free(wildchar);
+ free(delim);
+ free(hostname_to_free);
+ free(cert_wild_card_to_free);
+ if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
+ {
+ verb ("V: wildcard match of %s against %s\n",
+ orig_hostname, orig_cert_wild_card);
+ return (wildcard_encountered & ok);
+ } else {
+ verb ("V: wildcard match failure of %s against %s\n",
+ orig_hostname, orig_cert_wild_card);
+ return 0;
+ }
+}
+#endif
+
+#ifndef USE_POLARSSL
+/**
+ This extracts the first commonName and checks it against hostname.
+*/
+uint32_t
+check_cn (SSL *ssl, const char *hostname)
+{
+ int ok = 0;
+ int ret;
+ char *cn_buf;
+ X509 *certificate;
+ X509_NAME *xname;
+
+ // We cast this to cast away g++ complaining about the following:
+ // error: invalid conversion from ‘void*’ to ‘char*’
+ cn_buf = (char *) xmalloc(TLSDATE_HOST_NAME_MAX + 1);
+
+ certificate = SSL_get_peer_certificate(ssl);
+ if (NULL == certificate)
+ {
+ die ("Unable to extract certificate\n");
+ }
+
+ memset(cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
+ xname = X509_get_subject_name(certificate);
+ ret = X509_NAME_get_text_by_NID(xname, NID_commonName,
+ cn_buf, TLSDATE_HOST_NAME_MAX);
+
+ if (-1 == ret || ret != (int) strlen(cn_buf))
+ {
+ die ("Unable to extract commonName\n");
+ }
+ if (strcasecmp(cn_buf, hostname))
+ {
+ verb ("V: commonName mismatch! Expected: %s - received: %s\n",
+ hostname, cn_buf);
+ } else {
+ verb ("V: commonName matched: %s\n", cn_buf);
+ ok = 1;
+ }
+
+ X509_NAME_free(xname);
+ X509_free(certificate);
+ xfree(cn_buf);
+
+ return ok;
+}
+
+/**
+ Search for a hostname match in the SubjectAlternativeNames.
+*/
+uint32_t
+check_san (SSL *ssl, const char *hostname)
+{
+ X509 *cert;
+ int extcount, ok = 0;
+ /* What an OpenSSL mess ... */
+ if (NULL == (cert = SSL_get_peer_certificate(ssl)))
+ {
+ die ("Getting certificate failed\n");
+ }
+
+ if ((extcount = X509_get_ext_count(cert)) > 0)
+ {
+ int i;
+ for (i = 0; i < extcount; ++i)
+ {
+ const char *extstr;
+ X509_EXTENSION *ext;
+ ext = X509_get_ext(cert, i);
+ extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
+
+ if (!strcmp(extstr, "subjectAltName"))
+ {
+
+ int j;
+ void *extvalstr;
+ const unsigned char *tmp;
+
+ STACK_OF(CONF_VALUE) *val;
+ CONF_VALUE *nval;
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ const
+#endif
+ X509V3_EXT_METHOD *method;
+
+ if (!(method = X509V3_EXT_get(ext)))
+ {
+ break;
+ }
+
+ tmp = ext->value->data;
+ if (method->it)
+ {
+ extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length,
+ ASN1_ITEM_ptr(method->it));
+ } else {
+ extvalstr = method->d2i(NULL, &tmp, ext->value->length);
+ }
+
+ if (!extvalstr)
+ {
+ break;
+ }
+
+ if (method->i2v)
+ {
+ val = method->i2v(method, extvalstr, NULL);
+ for (j = 0; j < sk_CONF_VALUE_num(val); ++j)
+ {
+ nval = sk_CONF_VALUE_value(val, j);
+ if ((!strcasecmp(nval->name, "DNS") &&
+ !strcasecmp(nval->value, hostname) ) ||
+ (!strcasecmp(nval->name, "iPAddress") &&
+ !strcasecmp(nval->value, hostname)))
+ {
+ verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); /* We matched this; so it's safe to print */
+ ok = 1;
+ break;
+ }
+ // Attempt to match subjectAltName DNS names
+ if (!strcasecmp(nval->name, "DNS"))
+ {
+ ok = check_wildcard_match_rfc2595(hostname, nval->value);
+ if (ok)
+ {
+ break;
+ }
+ }
+ verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
+ }
+ }
+ } else {
+ verb ("V: found non subjectAltName extension\n");
+ }
+ if (ok)
+ {
+ break;
+ }
+ }
+ } else {
+ verb ("V: no X509_EXTENSION field(s) found\n");
+ }
+ X509_free(cert);
+ return ok;
+}
+
+uint32_t
+check_name (SSL *ssl, const char *hostname)
+{
+ uint32_t ret;
+ ret = check_cn(ssl, hostname);
+ ret += check_san(ssl, hostname);
+ if (0 != ret && 0 < ret)
+ {
+ verb ("V: hostname verification passed\n");
+ } else {
+ die ("hostname verification failed for host %s!\n", host);
+ }
+ return ret;
+}
+#endif
+
+#ifdef USE_POLARSSL
+uint32_t
+verify_signature (ssl_context *ssl, const char *hostname)
+{
+ int ssl_verify_result;
+
+ ssl_verify_result = ssl_get_verify_result (ssl);
+ if (ssl_verify_result & BADCERT_EXPIRED)
+ {
+ die ("certificate has expired\n");
+ }
+ if (ssl_verify_result & BADCERT_REVOKED)
+ {
+ die ("certificate has been revoked\n");
+ }
+ if (ssl_verify_result & BADCERT_CN_MISMATCH)
+ {
+ die ("CN and subject AltName mismatch for certificate\n");
+ }
+ if (ssl_verify_result & BADCERT_NOT_TRUSTED)
+ {
+ die ("certificate is self-signed or not signed by a trusted CA\n");
+ }
+
+ if (0 == ssl_verify_result)
+ {
+ verb ("V: verify success\n");
+ }
+ else
+ {
+ die ("certificate verification error: -0x%04x\n", -ssl_verify_result);
+ }
+ return 0;
+}
+#else
+uint32_t
+verify_signature (SSL *ssl, const char *hostname)
+{
+ long ssl_verify_result;
+ X509 *certificate;
+
+ certificate = SSL_get_peer_certificate(ssl);
+ if (NULL == certificate)
+ {
+ die ("Getting certificate failed\n");
+ }
+ // In theory, we verify that the cert is valid
+ ssl_verify_result = SSL_get_verify_result(ssl);
+ switch (ssl_verify_result)
+ {
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ die ("certificate is self signed\n");
+ case X509_V_OK:
+ verb ("V: certificate verification passed\n");
+ break;
+ default:
+ die ("certification verification error: %ld\n",
+ ssl_verify_result);
+ }
+ return 0;
+}
+#endif
+
+#ifdef USE_POLARSSL
+void
+check_key_length (ssl_context *ssl)
+{
+ uint32_t key_bits;
+ const x509_cert *certificate;
+ const rsa_context *public_key;
+ char buf[1024];
+
+ certificate = ssl_get_peer_cert (ssl);
+ if (NULL == certificate)
+ {
+ die ("Getting certificate failed\n");
+ }
+
+ x509parse_dn_gets(buf, 1024, &certificate->subject);
+ verb ("V: Certificate for subject '%s'\n", buf);
+
+ public_key = &certificate->rsa;
+ if (NULL == public_key)
+ {
+ die ("public key extraction failure\n");
+ } else {
+ verb ("V: public key is ready for inspection\n");
+ }
+ key_bits = mpi_msb (&public_key->N);
+ if (MIN_PUB_KEY_LEN >= key_bits)
+ {
+ die ("Unsafe public key size: %d bits\n", key_bits);
+ } else {
+ verb ("V: key length appears safe\n");
+ }
+}
+#else
+void
+check_key_length (SSL *ssl)
+{
+ uint32_t key_bits;
+ X509 *certificate;
+ EVP_PKEY *public_key;
+ certificate = SSL_get_peer_certificate (ssl);
+ if (NULL == certificate)
+ {
+ die ("Getting certificate failed\n");
+ }
+ public_key = X509_get_pubkey (certificate);
+ if (NULL == public_key)
+ {
+ die ("public key extraction failure\n");
+ } else {
+ verb ("V: public key is ready for inspection\n");
+ }
+
+ key_bits = get_certificate_keybits (public_key);
+ if (MIN_PUB_KEY_LEN >= key_bits && public_key->type != EVP_PKEY_EC)
+ {
+ die ("Unsafe public key size: %d bits\n", key_bits);
+ } else {
+ if (public_key->type == EVP_PKEY_EC)
+ if(key_bits >= MIN_ECC_PUB_KEY_LEN
+ && key_bits <= MAX_ECC_PUB_KEY_LEN)
+ {
+ verb ("V: ECC key length appears safe\n");
+ } else {
+ die ("Unsafe ECC key size: %d bits\n", key_bits);
+ } else {
+ verb ("V: key length appears safe\n");
+ }
+ }
+ EVP_PKEY_free (public_key);
+}
+#endif
+
+#ifdef USE_POLARSSL
+void
+inspect_key (ssl_context *ssl, const char *hostname)
+{
+ verify_signature (ssl, hostname);
+
+ // ssl_get_verify_result() already checks for CN / subjectAltName match
+ // and reports the mismatch as error. So check_name() is not called
+}
+#else
+void
+inspect_key (SSL *ssl, const char *hostname)
+{
+
+ verify_signature (ssl, hostname);
+ check_name (ssl, hostname);
+}
+#endif
+
+#ifdef USE_POLARSSL
+void
+check_timestamp (uint32_t server_time)
+{
+ uint32_t compiled_time = RECENT_COMPILE_DATE;
+ uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
+ if (compiled_time < server_time
+ &&
+ server_time < max_reasonable_time)
+ {
+ verb("V: remote peer provided: %d, preferred over compile time: %d\n",
+ server_time, compiled_time);
+ } else {
+ die("V: the remote server is a false ticker! server: %d compile: %d\n",
+ server_time, compiled_time);
+ }
+}
+
+static int ssl_do_handshake_part(ssl_context *ssl)
+{
+ int ret = 0;
+
+ /* Only do steps till ServerHello is received */
+ while (ssl->state != SSL_SERVER_HELLO)
+ {
+ ret = ssl_handshake_step (ssl);
+ if (0 != ret)
+ {
+ die("SSL handshake failed\n");
+ }
+ }
+ /* Do ServerHello so we can skim the timestamp */
+ ret = ssl_handshake_step (ssl);
+ if (0 != ret)
+ {
+ die("SSL handshake failed\n");
+ }
+
+ return 0;
+}
+
+/**
+ * Run SSL handshake and store the resulting time value in the
+ * 'time_map'.
+ *
+ * @param time_map where to store the current time
+ */
+static void
+run_ssl (uint32_t *time_map, int time_is_an_illusion)
+{
+ entropy_context entropy;
+ ctr_drbg_context ctr_drbg;
+ ssl_context ssl;
+ proxy_polarssl_ctx proxy_ctx;
+ x509_cert cacert;
+ struct stat statbuf;
+ int ret = 0, server_fd = 0;
+ char *pers = "tlsdate-helper";
+
+ memset (&ssl, 0, sizeof(ssl_context));
+ memset (&cacert, 0, sizeof(x509_cert));
+
+ verb("V: Using PolarSSL for SSL\n");
+ if (ca_racket)
+ {
+ if (-1 == stat (ca_cert_container, &statbuf))
+ {
+ die("Unable to stat CA certficate container %s\n", ca_cert_container);
+ }
+ else
+ {
+ switch (statbuf.st_mode & S_IFMT)
+ {
+ case S_IFREG:
+ if (0 > x509parse_crtfile(&cacert, ca_cert_container))
+ fprintf(stderr, "x509parse_crtfile failed\n");
+ break;
+ case S_IFDIR:
+ if (0 > x509parse_crtpath(&cacert, ca_cert_container))
+ fprintf(stderr, "x509parse_crtpath failed\n");
+ break;
+ default:
+ die("Unable to load CA certficate container %s\n", ca_cert_container);
+ }
+ }
+ }
+
+ entropy_init (&entropy);
+ if (0 != ctr_drbg_init (&ctr_drbg, entropy_func, &entropy,
+ (unsigned char *) pers, strlen(pers)))
+ {
+ die("Failed to initialize CTR_DRBG\n");
+ }
+
+ if (0 != ssl_init (&ssl))
+ {
+ die("SSL initialization failed\n");
+ }
+ ssl_set_endpoint (&ssl, SSL_IS_CLIENT);
+ ssl_set_rng (&ssl, ctr_drbg_random, &ctr_drbg);
+ ssl_set_ca_chain (&ssl, &cacert, NULL, hostname_to_verify);
+ if (ca_racket)
+ {
+ // You can do SSL_VERIFY_REQUIRED here, but then the check in
+ // inspect_key() never happens as the ssl_handshake() will fail.
+ ssl_set_authmode (&ssl, SSL_VERIFY_OPTIONAL);
+ }
+
+ if (proxy)
+ {
+ char *scheme;
+ char *proxy_host;
+ char *proxy_port;
+
+ parse_proxy_uri (proxy, &scheme, &proxy_host, &proxy_port);
+
+ verb("V: opening socket to proxy %s:%s\n", proxy_host, proxy_port);
+ if (0 != net_connect (&server_fd, proxy_host, atoi(proxy_port)))
+ {
+ die ("SSL connection failed\n");
+ }
+
+ proxy_polarssl_init (&proxy_ctx);
+ proxy_polarssl_set_bio (&proxy_ctx, net_recv, &server_fd, net_send, &server_fd);
+ proxy_polarssl_set_host (&proxy_ctx, host);
+ proxy_polarssl_set_port (&proxy_ctx, atoi(port));
+ proxy_polarssl_set_scheme (&proxy_ctx, scheme);
+
+ ssl_set_bio (&ssl, proxy_polarssl_recv, &proxy_ctx, proxy_polarssl_send, &proxy_ctx);
+
+ verb("V: Handle proxy connection\n");
+ if (0 == proxy_ctx.f_connect (&proxy_ctx))
+ die("Proxy connection failed\n");
+ }
+ else
+ {
+ verb("V: opening socket to %s:%s\n", host, port);
+ if (0 != net_connect (&server_fd, host, atoi(port)))
+ {
+ die ("SSL connection failed\n");
+ }
+
+ ssl_set_bio (&ssl, net_recv, &server_fd, net_send, &server_fd);
+ }
+
+ verb("V: starting handshake\n");
+ if (0 != ssl_do_handshake_part (&ssl))
+ die("SSL handshake first part failed\n");
+
+ uint32_t timestamp = ( (uint32_t) ssl.in_msg[6] << 24 )
+ | ( (uint32_t) ssl.in_msg[7] << 16 )
+ | ( (uint32_t) ssl.in_msg[8] << 8 )
+ | ( (uint32_t) ssl.in_msg[9] );
+ check_timestamp (timestamp);
+
+ verb("V: continuing handshake\n");
+ /* Continue with handshake */
+ while (0 != (ret = ssl_handshake (&ssl)))
+ {
+ if (POLARSSL_ERR_NET_WANT_READ != ret &&
+ POLARSSL_ERR_NET_WANT_WRITE != ret)
+ {
+ die("SSL handshake failed\n");
+ }
+ }
+
+ // Verify the peer certificate against the CA certs on the local system
+ if (ca_racket) {
+ inspect_key (&ssl, hostname_to_verify);
+ } else {
+ verb ("V: Certificate verification skipped!\n");
+ }
+ check_key_length (&ssl);
+
+ memcpy (time_map, &timestamp, sizeof(uint32_t));
+ proxy_polarssl_free (&proxy_ctx);
+ ssl_free (&ssl);
+ x509_free (&cacert);
+}
+#else /* USE_POLARSSL */
+/**
+ * Run SSL handshake and store the resulting time value in the
+ * 'time_map'.
+ *
+ * @param time_map where to store the current time
+ */
+static void
+run_ssl (uint32_t *time_map, int time_is_an_illusion)
+{
+ BIO *s_bio;
+ SSL_CTX *ctx;
+ SSL *ssl;
+ struct stat statbuf;
+
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ ctx = NULL;
+ if (0 == strcmp("sslv23", protocol))
+ {
+ verb ("V: using SSLv23_client_method()\n");
+ ctx = SSL_CTX_new(SSLv23_client_method());
+ } else if (0 == strcmp("sslv3", protocol))
+ {
+ verb ("V: using SSLv3_client_method()\n");
+ ctx = SSL_CTX_new(SSLv3_client_method());
+ } else if (0 == strcmp("tlsv1", protocol))
+ {
+ verb ("V: using TLSv1_client_method()\n");
+ ctx = SSL_CTX_new(TLSv1_client_method());
+ } else
+ die("Unsupported protocol `%s'\n", protocol);
+
+ if (ctx == NULL)
+ die("OpenSSL failed to support protocol `%s'\n", protocol);
+
+ verb("V: Using OpenSSL for SSL\n");
+ if (ca_racket)
+ {
+ if (-1 == stat(ca_cert_container, &statbuf))
+ {
+ die("Unable to stat CA certficate container %s\n", ca_cert_container);
+ } else
+ {
+ switch (statbuf.st_mode & S_IFMT)
+ {
+ case S_IFREG:
+ if (1 != SSL_CTX_load_verify_locations(ctx, ca_cert_container, NULL))
+ fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
+ break;
+ case S_IFDIR:
+ if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
+ fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
+ break;
+ default:
+ if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
+ {
+ fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
+ die("Unable to load CA certficate container %s\n", ca_cert_container);
+ }
+ }
+ }
+ }
+
+ if (NULL == (s_bio = make_ssl_bio(ctx)))
+ die ("SSL BIO setup failed\n");
+ BIO_get_ssl(s_bio, &ssl);
+ if (NULL == ssl)
+ die ("SSL setup failed\n");
+
+ if (time_is_an_illusion)
+ {
+ SSL_set_info_callback(ssl, openssl_time_callback);
+ }
+
+ SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+ verb("V: opening socket to %s:%s\n", host, port);
+ if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
+ (1 != BIO_set_conn_port(s_bio, port)) )
+ die ("Failed to initialize connection to `%s:%s'\n", host, port);
+
+ if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
+ die ("BIO_new_fp returned error, possibly: %s", strerror(errno));
+
+ // This should run in seccomp
+ // eg: prctl(PR_SET_SECCOMP, 1);
+ if (1 != BIO_do_connect(s_bio)) /* XXX TODO: BIO_should_retry() later? */
+ die ("SSL connection failed\n");
+ if (1 != BIO_do_handshake(s_bio))
+ die ("SSL handshake failed\n");
+
+ // Verify the peer certificate against the CA certs on the local system
+ if (ca_racket) {
+ inspect_key (ssl, hostname_to_verify);
+ } else {
+ verb ("V: Certificate verification skipped!\n");
+ }
+ check_key_length(ssl);
+ // from /usr/include/openssl/ssl3.h
+ // ssl->s3->server_random is an unsigned char of 32 bits
+ memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
+ SSL_free(ssl);
+ SSL_CTX_free(ctx);
+}
+#endif /* USE_POLARSSL */
+/** drop root rights and become 'nobody' */
+
+int
+main(int argc, char **argv)
+{
+ uint32_t *time_map;
+ struct tlsdate_time start_time, end_time, warp_time;
+ int status;
+ pid_t ssl_child;
+ long long rt_time_ms;
+ uint32_t server_time_s;
+ int setclock;
+ int showtime;
+ int timewarp;
+ int leap;
+
+ if (argc != 12)
+ return 1;
+ host = argv[1];
+ hostname_to_verify = argv[1];
+ port = argv[2];
+ protocol = argv[3];
+ ca_cert_container = argv[6];
+ ca_racket = (0 != strcmp ("unchecked", argv[4]));
+ verbose = (0 != strcmp ("quiet", argv[5]));
+ setclock = (0 == strcmp ("setclock", argv[7]));
+ showtime = (0 == strcmp ("showtime", argv[8]));
+ timewarp = (0 == strcmp ("timewarp", argv[9]));
+ leap = (0 == strcmp ("leapaway", argv[10]));
+ proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
+
+ if (timewarp)
+ {
+
+ verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
+ (unsigned long) CLOCK_SEC(&warp_time),
+ (unsigned long) CLOCK_USEC(&warp_time));
+
+ if (1 == setclock) {
+ clock_init_time(&warp_time, RECENT_COMPILE_DATE, 0);
+ } else {
+ verb ("V: we'll do the time warp another time - we're not setting clock\n");
+ }
+ }
+
+ /* We are not going to set the clock, thus no need to stay root */
+ if (0 == setclock && 0 == timewarp)
+ {
+ drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
+ }
+/*
+ XXX: KILL ME
+ // We cast the mmap value to remove this error when compiling with g++:
+ // src/tlsdate-helper.c: In function ‘int main(int, char**)’:
+ // src/tlsdate-helper.c:822:41: error: invalid conversion from ‘void*’ to ‘uint32_t
+ time_map = (uint32_t *) mmap (NULL, sizeof (uint32_t),
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (MAP_FAILED == time_map)
+ {
+ fprintf (stderr, "mmap failed: %s\n",
+ strerror (errno));
+ return 1;
+ }
+*/
+ /* Get the current time from the system clock. */
+ if (0 != clock_get_real_time(&start_time))
+ {
+ die ("Failed to read current time of day: %s\n", strerror (errno));
+ }
+
+ verb ("V: time is currently %lu.%06lu\n",
+ (unsigned long) CLOCK_SEC(&start_time),
+ (unsigned long) CLOCK_NSEC(&start_time));
+
+ if (((unsigned long) CLOCK_SEC(&start_time)) < ((unsigned long) CLOCK_SEC(&warp_time)))
+ {
+ verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
+ if (timewarp)
+ {
+ verb ("V: Attempting to warp local clock into the future\n");
+ if (0 != clock_set_real_time(&warp_time))
+ {
+ die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
+ strerror (errno),
+ (unsigned long) CLOCK_SEC(&warp_time),
+ (unsigned long) CLOCK_SEC(&warp_time));
+ }
+ if (0 != clock_get_real_time(&start_time))
+ {
+ die ("Failed to read current time of day: %s\n", strerror (errno));
+ }
+ verb ("V: time is currently %lu.%06lu\n",
+ (unsigned long) CLOCK_SEC(&start_time),
+ (unsigned long) CLOCK_NSEC(&start_time));
+ verb ("V: It's just a step to the left...\n");
+ }
+ } else {
+ verb ("V: time is greater than RECENT_COMPILE_DATE\n");
+ }
+
+ /* initialize to bogus value, just to be on the safe side */
+ *time_map = 0;
+
+ /* Run SSL interaction in separate process (and not as 'root') */
+ ssl_child = fork ();
+ if (-1 == ssl_child)
+ die ("fork failed: %s\n", strerror (errno));
+ if (0 == ssl_child)
+ {
+ drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
+ run_ssl (time_map, leap);
+ /*
+ XXX: should be a pipe close
+ (void) munmap (time_map, sizeof (uint32_t));
+ */
+ _exit (0);
+ }
+ if (ssl_child != waitpid (ssl_child, &status, 0))
+ die ("waitpid failed: %s\n", strerror (errno));
+ if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
+ die ("child process failed in SSL handshake\n");
+
+ if (0 != clock_get_real_time(&end_time))
+ die ("Failed to read current time of day: %s\n", strerror (errno));
+
+ /* calculate RTT */
+ rt_time_ms = (CLOCK_SEC(&end_time) - CLOCK_SEC(&start_time)) * 1000 + (CLOCK_USEC(&end_time) - CLOCK_USEC(&start_time)) / 1000;
+ if (rt_time_ms < 0)
+ rt_time_ms = 0; /* non-linear time... */
+#ifdef USE_POLARSSL
+ server_time_s = *time_map;
+#else
+ server_time_s = ntohl (*time_map);
+#endif
+ /*
+ XXX: should be a pipe close
+ munmap (time_map, sizeof (uint32_t));
+ */
+ verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
+ (unsigned int) server_time_s,
+ CLOCK_SEC(&start_time) - server_time_s,
+ rt_time_ms);
+
+ /* warning if the handshake took too long */
+ if (rt_time_ms > TLS_RTT_THRESHOLD) {
+ verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
+ "server or run it again\n", TLS_RTT_THRESHOLD);
+ }
+
+ if (showtime)
+ {
+ struct tm ltm;
+ time_t tim = server_time_s;
+ char buf[256];
+
+ localtime_r(&tim, &ltm);
+ if (0 == strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
+ {
+ die ("strftime returned 0\n");
+ }
+ fprintf(stdout, "%s\n", buf);
+ }
+
+ /* finally, actually set the time */
+ if (setclock)
+ {
+ struct tlsdate_time server_time;
+
+ clock_init_time(&server_time, server_time_s + (rt_time_ms / 2 / 1000),
+ (rt_time_ms / 2) % 1000);
+
+ // We should never receive a time that is before the time we were last
+ // compiled; we subscribe to the linear theory of time for this program
+ // and this program alone!
+ if (CLOCK_SEC(&server_time) >= MAX_REASONABLE_TIME)
+ die("remote server is a false ticker from the future!\n");
+ if (CLOCK_SEC(&server_time) <= RECENT_COMPILE_DATE)
+ die ("remote server is a false ticker!\n");
+ if (0 != clock_set_real_time(&server_time))
+ die ("setting time failed: %s (Difference from server is about %d s)\n",
+ strerror (errno),
+ CLOCK_SEC(&start_time) - server_time_s);
+ verb ("V: setting time succeeded\n");
+ }
+ return 0;
+}
diff --git a/src/tlsdate-helper-plan9.h b/src/tlsdate-helper-plan9.h
new file mode 100644
index 0000000..4838ed6
--- /dev/null
+++ b/src/tlsdate-helper-plan9.h
@@ -0,0 +1,118 @@
+/* Copyright (c) 2012, Jacob Appelbaum
+ * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tlsdate-helper.h
+ * \brief The secondary header for our clock helper.
+ **/
+
+#ifndef TLSDATEHELPER_H
+#define TLSDATEHELPER_H
+
+#include <stdarg.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <pwd.h>
+#include <grp.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#ifndef USE_POLARSSL
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#endif
+
+int verbose;
+
+#include "src/util.h"
+
+/** Name of user that we feel safe to run SSL handshake with. */
+#ifndef UNPRIV_USER
+#define UNPRIV_USER "nobody"
+#endif
+#ifndef UNPRIV_GROUP
+#define UNPRIV_GROUP "nogroup"
+#endif
+
+// We should never accept a time before we were compiled
+// We measure in seconds since the epoch - eg: echo `date '+%s'`
+// We set this manually to ensure others can reproduce a build;
+// automation of this will make every build different!
+#ifndef RECENT_COMPILE_DATE
+#define RECENT_COMPILE_DATE (uint32_t) 1342323666
+#endif
+
+#ifndef MAX_REASONABLE_TIME
+#define MAX_REASONABLE_TIME (uint32_t) 1999991337
+#endif
+
+#ifndef MIN_PUB_KEY_LEN
+#define MIN_PUB_KEY_LEN (uint32_t) 1023
+#endif
+
+#ifndef MIN_ECC_PUB_KEY_LEN
+#define MIN_ECC_PUB_KEY_LEN (uint32_t) 160
+#endif
+
+#ifndef MAX_ECC_PUB_KEY_LEN
+#define MAX_ECC_PUB_KEY_LEN (uint32_t) 521
+#endif
+// After the duration of the TLS handshake exceeds this threshold
+// (in msec), a warning is printed.
+#define TLS_RTT_THRESHOLD 2000
+
+// RFC 5280 says...
+// ub-common-name-length INTEGER ::= 64
+#define MAX_CN_NAME_LENGTH 64
+
+// RFC 1034 and posix say...
+#define TLSDATE_HOST_NAME_MAX 255
+
+// To support our RFC 2595 wildcard verification
+#define RFC2595_MIN_LABEL_COUNT 3
+
+static int ca_racket;
+
+static const char *host;
+
+static const char *hostname_to_verify;
+
+static const char *port;
+
+static const char *protocol;
+
+static char *proxy;
+
+static const char *ca_cert_container;
+#ifndef USE_POLARSSL
+void openssl_time_callback (const SSL* ssl, int where, int ret);
+uint32_t get_certificate_keybits (EVP_PKEY *public_key);
+uint32_t check_cn (SSL *ssl, const char *hostname);
+uint32_t check_san (SSL *ssl, const char *hostname);
+long openssl_check_against_host_and_verify (SSL *ssl);
+uint32_t check_name (SSL *ssl, const char *hostname);
+uint32_t verify_signature (SSL *ssl, const char *hostname);
+void check_key_length (SSL *ssl);
+void inspect_key (SSL *ssl, const char *hostname);
+void check_key_length (SSL *ssl);
+void inspect_key (SSL *ssl, const char *hostname);
+#endif
+uint32_t dns_label_count (char *label, char *delim);
+uint32_t check_wildcard_match_rfc2595 (const char *orig_hostname,
+ const char *orig_cert_wild_card);
+static void run_ssl (uint32_t *time_map, int time_is_an_illusion);
+
+#endif
diff --git a/src/tlsdate-helper.c b/src/tlsdate-helper.c
new file mode 100644
index 0000000..877c67e
--- /dev/null
+++ b/src/tlsdate-helper.c
@@ -0,0 +1,1439 @@
+/* Copyright (c) 2012, Jacob Appelbaum.
+ * Copyright (c) 2012, The Tor Project, Inc.
+ * Copyright (c) 2012, Christian Grothoff. */
+/* See LICENSE for licensing information */
+/*
+ This file contains the license for tlsdate,
+ a free software project to set your system clock securely.
+
+ It also lists the licenses for other components used by tlsdate.
+
+ For more information about tlsdate, see https://github.com/ioerror/tlsdate
+
+ If you got this file as a part of a larger bundle,
+ there may be other license terms that you should be aware of.
+
+===============================================================================
+tlsdate is distributed under this license:
+
+Copyright (c) 2011-2012, Jacob Appelbaum <jacob@appelbaum.net>
+Copyright (c) 2011-2012, The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+If you got tlsdate as a static binary with OpenSSL included, then you should
+know:
+
+ "This product includes software developed by the OpenSSL Project for use in
+ the OpenSSL Toolkit (http://www.openssl.org/)"
+
+===============================================================================
+*/
+
+/**
+ * \file tlsdate-helper.c
+ * \brief Helper program that does the actual work of setting the system clock.
+ **/
+
+/*
+ * tlsdate is a tool for setting the system clock by hand or by communication
+ * with the network. It does not set the RTC. It is designed to be as secure as
+ * TLS (RFC 2246) but of course the security of TLS is often reduced to
+ * whichever CA racket you believe is trustworthy. By default, tlsdate trusts
+ * your local CA root store - so any of these companies could assist in a MITM
+ * attack against you and you'd be screwed.
+
+ * This tool is designed to be run by hand or as a system daemon. It must be
+ * run as root or otherwise have the proper caps; it will not be able to set
+ * the system time without running as root or another privileged user.
+ */
+
+#include "config.h"
+#include "src/tlsdate-helper.h"
+#include "src/util.h"
+
+#ifndef USE_POLARSSL
+#include "src/proxy-bio.h"
+#else
+#include "src/proxy-polarssl.h"
+#endif
+
+#include "src/compat/clock.h"
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#ifdef USE_POLARSSL
+#include "polarssl/entropy.h"
+#include "polarssl/ctr_drbg.h"
+#include "polarssl/ssl.h"
+#endif
+
+static void
+validate_proxy_scheme(const char *scheme)
+{
+ if (!strcmp(scheme, "http"))
+ return;
+ if (!strcmp(scheme, "socks4"))
+ return;
+ if (!strcmp(scheme, "socks5"))
+ return;
+ die("invalid proxy scheme");
+}
+
+static void
+validate_proxy_host(const char *host)
+{
+ const char *kValid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ ".-";
+ if (strspn(host, kValid) != strlen(host))
+ die("invalid char in host");
+}
+
+static void
+validate_proxy_port(const char *port)
+{
+ while (*port)
+ if (!isdigit((int)(unsigned char)*port++))
+ die("invalid char in port");
+}
+
+static void
+parse_proxy_uri(char *proxy, char **scheme, char **host, char **port)
+{
+ /* Expecting a URI, so: <scheme> '://' <host> ':' <port> */
+ *scheme = proxy;
+ proxy = strstr(proxy, "://");
+ if (!proxy)
+ die("malformed proxy URI");
+ *proxy = '\0'; /* terminate scheme string */
+ proxy += strlen("://");
+
+ *host = proxy;
+ proxy = strchr(proxy, ':');
+ if (!proxy)
+ die("malformed proxy URI");
+ *proxy++ = '\0';
+
+ *port = proxy;
+
+ validate_proxy_scheme(*scheme);
+ validate_proxy_host(*host);
+ validate_proxy_port(*port);
+}
+
+#ifndef USE_POLARSSL
+static void
+setup_proxy(BIO *ssl)
+{
+ BIO *bio;
+ char *scheme;
+ char *proxy_host;
+ char *proxy_port;
+
+ if (!proxy)
+ return;
+ /*
+ * grab the proxy's host and port out of the URI we have for it. We want the
+ * underlying connect BIO to connect to this, not the target host and port, so
+ * we squirrel away the target host and port in the proxy BIO (as the proxy
+ * target) and swap out the connect BIO's target host and port so it'll
+ * connect to the proxy instead.
+ */
+ parse_proxy_uri(proxy, &scheme, &proxy_host, &proxy_port);
+ bio = BIO_new_proxy();
+ BIO_proxy_set_type(bio, scheme);
+ BIO_proxy_set_host(bio, host);
+ BIO_proxy_set_port(bio, atoi(port));
+ host = proxy_host;
+ port = proxy_port;
+ BIO_push(ssl, bio);
+}
+
+static BIO *
+make_ssl_bio(SSL_CTX *ctx)
+{
+ BIO *con = NULL;
+ BIO *ssl = NULL;
+
+ if (!(con = BIO_new(BIO_s_connect())))
+ die("BIO_s_connect failed");
+ if (!(ssl = BIO_new_ssl(ctx, 1)))
+ die("BIO_new_ssl failed");
+ setup_proxy(ssl);
+ BIO_push(ssl, con);
+ return ssl;
+}
+
+
+static int
+write_all_to_bio(BIO *bio, const char *string)
+{
+ int n = (int) strlen(string);
+ int r;
+
+ while (n) {
+ r = BIO_write(bio, string, n);
+ if (r > 0) {
+ if (r > n)
+ return -1;
+ n -= r;
+ string += r;
+ } else {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* If the string is all nice clean ascii that it's safe to log, return
+ * it. Otherwise return a placeholder "This is junk" string. */
+static const char *
+sanitize_string(const char *s)
+{
+ const unsigned char *cp;
+ for (cp = (const unsigned char *)s; *cp; cp++) {
+ if (*cp < 32 || *cp >= 127)
+ return "string with invalid characters";
+ }
+ return s;
+}
+
+static int
+handle_date_line(const char *dateline, uint32_t *result)
+{
+ int year,mon,day,hour,min,sec;
+ char month[4];
+ struct tm tm;
+ int i;
+ time_t t;
+ /* We recognize the three formats in RFC2616, section 3.3.1. Month
+ names are always in English. The formats are:
+
+ Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+ Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
+
+ Note that the first is preferred.
+ */
+
+ static const char *MONTHS[] =
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
+
+ if (strncmp("\r\nDate: ", dateline, 8))
+ return 0;
+
+ dateline += 8;
+ if (strlen(dateline) > MAX_DATE_LINE_LEN) {
+ verb("V: The date line was impossibly long.");
+ return -1;
+ }
+ verb("V: The alleged date is <%s>", sanitize_string(dateline));
+
+ while (*dateline == ' ')
+ ++dateline;
+ while (*dateline && *dateline != ' ')
+ ++dateline;
+ while (*dateline == ' ')
+ ++dateline;
+ /* We just skipped over the day of the week. Now we have:*/
+ if (sscanf(dateline, "%d %3s %d %d:%d:%d",
+ &day, month, &year, &hour, &min, &sec) == 6 ||
+ sscanf(dateline, "%d-%3s-%d %d:%d:%d",
+ &day, month, &year, &hour, &min, &sec) == 6 ||
+ sscanf(dateline, "%3s %d %d:%d:%d %d",
+ month, &day, &hour, &min, &sec, &year) == 6) {
+
+ /* Two digit dates are defined to be relative to 1900; all other dates
+ * are supposed to be represented as four digits. */
+ if (year < 100)
+ year += 1900;
+
+ verb("V: Parsed the date: %04d-%s-%02d %02d:%02d:%02d",
+ year, month, day, hour, min, sec);
+ } else {
+ verb("V: Couldn't parse date.");
+ return -1;
+ }
+
+ for (i = 0; ; ++i) {
+ if (!MONTHS[i])
+ return -2;
+ if (!strcmp(month, MONTHS[i])) {
+ mon = i;
+ break;
+ }
+ }
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = mon;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ t = timegm(&tm);
+ if (t > 0xffffffff || t < 0)
+ return -1;
+
+ *result = (uint32_t) t;
+
+ return 1;
+}
+
+static int
+read_http_date_from_bio(BIO *bio, uint32_t *result)
+{
+ int n;
+ char buf[MAX_HTTP_HEADERS_SIZE];
+ int buf_len=0;
+ char *dateline, *endofline;
+
+ while (buf_len < sizeof(buf)-1) {
+ n = BIO_read(bio, buf+buf_len, sizeof(buf)-buf_len-1);
+ if (n <= 0)
+ return 0;
+ buf_len += n;
+ buf[buf_len] = 0;
+ verb_debug ("V: read %d bytes.", n, buf);
+
+ dateline = memmem(buf, buf_len, "\r\nDate: ", 8);
+ if (NULL == dateline)
+ continue;
+
+ endofline = memmem(dateline+2, buf_len - (dateline-buf+2), "\r\n", 2);
+ if (NULL == endofline)
+ continue;
+
+ *endofline = 0;
+ return handle_date_line(dateline, result);
+ }
+ return -2;
+}
+
+/** helper function for 'malloc' */
+static void *
+xmalloc (size_t size)
+{
+ void *ptr;
+
+ if (0 == size)
+ die("xmalloc: zero size");
+
+ ptr = malloc(size);
+ if (NULL == ptr)
+ die("xmalloc: out of memory (allocating %zu bytes)", size);
+
+ return ptr;
+}
+
+
+/** helper function for 'free' */
+static void
+xfree (void *ptr)
+{
+ if (NULL == ptr)
+ die("xfree: NULL pointer given as argument");
+
+ free(ptr);
+}
+
+void
+openssl_time_callback (const SSL* ssl, int where, int ret)
+{
+ if (where == SSL_CB_CONNECT_LOOP &&
+ (ssl->state == SSL3_ST_CR_SRVR_HELLO_A || ssl->state == SSL3_ST_CR_SRVR_HELLO_B))
+ {
+ // XXX TODO: If we want to trust the remote system for time,
+ // can we just read that time out of the remote system and if the
+ // cert verifies, decide that the time is reasonable?
+ // Such a process seems to indicate that a once valid cert would be
+ // forever valid - we stopgap that by ensuring it isn't less than
+ // the latest compiled_time and isn't above max_reasonable_time...
+ // XXX TODO: Solve eternal question about the Chicken and the Egg...
+ uint32_t compiled_time = RECENT_COMPILE_DATE;
+ uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
+ uint32_t server_time;
+ verb("V: freezing time for x509 verification");
+ memcpy(&server_time, ssl->s3->server_random, sizeof(uint32_t));
+ if (compiled_time < ntohl(server_time)
+ &&
+ ntohl(server_time) < max_reasonable_time)
+ {
+ verb("V: remote peer provided: %d, preferred over compile time: %d",
+ ntohl(server_time), compiled_time);
+ verb("V: freezing time with X509_VERIFY_PARAM_set_time");
+ X509_VERIFY_PARAM_set_time(ssl->ctx->cert_store->param,
+ (time_t) ntohl(server_time) + 86400);
+ } else {
+ die("V: the remote server is a false ticker! server: %d compile: %d",
+ ntohl(server_time), compiled_time);
+ }
+ }
+}
+
+uint32_t
+get_certificate_keybits (EVP_PKEY *public_key)
+{
+ /*
+ In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
+ */
+ uint32_t key_bits;
+ switch (public_key->type)
+ {
+ case EVP_PKEY_RSA:
+ verb("V: key type: EVP_PKEY_RSA");
+ key_bits = BN_num_bits(public_key->pkey.rsa->n);
+ break;
+ case EVP_PKEY_RSA2:
+ verb("V: key type: EVP_PKEY_RSA2");
+ key_bits = BN_num_bits(public_key->pkey.rsa->n);
+ break;
+ case EVP_PKEY_DSA:
+ verb("V: key type: EVP_PKEY_DSA");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DSA1:
+ verb("V: key type: EVP_PKEY_DSA1");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DSA2:
+ verb("V: key type: EVP_PKEY_DSA2");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DSA3:
+ verb("V: key type: EVP_PKEY_DSA3");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DSA4:
+ verb("V: key type: EVP_PKEY_DSA4");
+ key_bits = BN_num_bits(public_key->pkey.dsa->p);
+ break;
+ case EVP_PKEY_DH:
+ verb("V: key type: EVP_PKEY_DH");
+ key_bits = BN_num_bits(public_key->pkey.dh->pub_key);
+ break;
+ case EVP_PKEY_EC:
+ verb("V: key type: EVP_PKEY_EC");
+ key_bits = EVP_PKEY_bits(public_key);
+ break;
+ // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
+ default:
+ key_bits = 0;
+ die ("unknown public key type");
+ break;
+ }
+ verb ("V: keybits: %d", key_bits);
+ return key_bits;
+}
+
+uint32_t
+dns_label_count(char *label, char *delim)
+{
+ char *label_tmp;
+ char *saveptr;
+ char *saveptr_tmp;
+ uint32_t label_count;
+
+ label_tmp = strdup(label);
+ label_count = 0;
+ saveptr = NULL;
+ saveptr_tmp = NULL;
+ saveptr = strtok_r(label_tmp, delim, &saveptr);
+ if (NULL != saveptr)
+ {
+ // Did we find our first label?
+ if (saveptr[0] != delim[0])
+ {
+ label_count++;
+ }
+ do
+ {
+ // Find all subsequent labels
+ label_count++;
+ saveptr_tmp = strtok_r(NULL, delim, &saveptr);
+ } while (NULL != saveptr_tmp);
+ }
+ verb_debug ("V: label found; total label count: %d", label_count);
+ free(label_tmp);
+ return label_count;
+}
+
+// first we split strings on '.'
+// then we call each split string a 'label'
+// Do not allow '*' for the top level domain label; eg never allow *.*.com
+// Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
+// Do allow *.example.com
+uint32_t
+check_wildcard_match_rfc2595 (const char *orig_hostname,
+ const char *orig_cert_wild_card)
+{
+ char *hostname;
+ char *hostname_to_free;
+ char *cert_wild_card;
+ char *cert_wild_card_to_free;
+ char *expected_label;
+ char *wildcard_label;
+ char *delim;
+ char *wildchar;
+ uint32_t ok;
+ uint32_t wildcard_encountered;
+ uint32_t label_count;
+
+ // First we copy the original strings
+ hostname = strndup(orig_hostname, strlen(orig_hostname));
+ cert_wild_card = strndup(orig_cert_wild_card, strlen(orig_cert_wild_card));
+ hostname_to_free = hostname;
+ cert_wild_card_to_free = cert_wild_card;
+ delim = strdup(".");
+ wildchar = strdup("*");
+
+ verb_debug ("V: Inspecting '%s' for possible wildcard match against '%s'",
+ hostname, cert_wild_card);
+
+ // By default we have not processed any labels
+ label_count = dns_label_count(cert_wild_card, delim);
+
+ // By default we have no match
+ ok = 0;
+ wildcard_encountered = 0;
+ // First - do we have labels? If not, we refuse to even try to match
+ if ((NULL != strpbrk(cert_wild_card, delim)) &&
+ (NULL != strpbrk(hostname, delim)) &&
+ (label_count <= ((uint32_t)RFC2595_MIN_LABEL_COUNT)))
+ {
+ if (wildchar[0] == cert_wild_card[0])
+ {
+ verb_debug ("V: Found wildcard in at start of provided certificate name");
+ do
+ {
+ // Skip over the bytes between the first char and until the next label
+ wildcard_label = strsep(&cert_wild_card, delim);
+ expected_label = strsep(&hostname, delim);
+ if (NULL != wildcard_label &&
+ NULL != expected_label &&
+ NULL != hostname &&
+ NULL != cert_wild_card)
+ {
+ // Now we only consider this wildcard valid if the rest of the
+ // hostnames match verbatim
+ verb_debug ("V: Attempting match of '%s' against '%s'",
+ expected_label, wildcard_label);
+ // This is the case where we have a label that begins with wildcard
+ // Furthermore, we only allow this for the first label
+ if (wildcard_label[0] == wildchar[0] &&
+ 0 == wildcard_encountered && 0 == ok)
+ {
+ verb ("V: Forced match of '%s' against '%s'", expected_label, wildcard_label);
+ wildcard_encountered = 1;
+ } else {
+ verb_debug ("V: Attempting match of '%s' against '%s'",
+ hostname, cert_wild_card);
+ if (0 == strcasecmp (expected_label, wildcard_label) &&
+ label_count >= ((uint32_t)RFC2595_MIN_LABEL_COUNT))
+ {
+ ok = 1;
+ verb_debug ("V: remaining labels match!");
+ break;
+ } else {
+ ok = 0;
+ verb_debug ("V: remaining labels do not match!");
+ break;
+ }
+ }
+ } else {
+ // We hit this case when we have a mismatched number of labels
+ verb_debug ("V: NULL label; no wildcard here");
+ break;
+ }
+ } while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
+ } else {
+ verb_debug ("V: Not a RFC 2595 wildcard");
+ }
+ } else {
+ verb_debug ("V: Not a valid wildcard certificate");
+ ok = 0;
+ }
+ // Free our copies
+ free(wildchar);
+ free(delim);
+ free(hostname_to_free);
+ free(cert_wild_card_to_free);
+ if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
+ {
+ verb_debug ("V: wildcard match of %s against %s",
+ orig_hostname, orig_cert_wild_card);
+ return (wildcard_encountered & ok);
+ } else {
+ verb_debug ("V: wildcard match failure of %s against %s",
+ orig_hostname, orig_cert_wild_card);
+ return 0;
+ }
+}
+#endif
+
+#ifndef USE_POLARSSL
+/**
+ This extracts the first commonName and checks it against hostname.
+*/
+uint32_t
+check_cn (SSL *ssl, const char *hostname)
+{
+ int ok = 0;
+ int ret;
+ char *cn_buf;
+ X509 *certificate;
+ X509_NAME *xname;
+
+ // We cast this to cast away g++ complaining about the following:
+ // error: invalid conversion from ‘void*’ to ‘char*’
+ cn_buf = (char *) xmalloc(TLSDATE_HOST_NAME_MAX + 1);
+
+ certificate = SSL_get_peer_certificate(ssl);
+ if (NULL == certificate)
+ {
+ die ("Unable to extract certificate");
+ }
+
+ memset(cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
+ xname = X509_get_subject_name(certificate);
+ ret = X509_NAME_get_text_by_NID(xname, NID_commonName,
+ cn_buf, TLSDATE_HOST_NAME_MAX);
+
+ if (-1 == ret || ret != (int) strlen(cn_buf))
+ {
+ die ("Unable to extract commonName");
+ }
+ if (strcasecmp(cn_buf, hostname))
+ {
+ verb ("V: commonName mismatch! Expected: %s - received: %s",
+ hostname, cn_buf);
+ } else {
+ verb ("V: commonName matched: %s", cn_buf);
+ ok = 1;
+ }
+
+ X509_NAME_free(xname);
+ X509_free(certificate);
+ xfree(cn_buf);
+
+ return ok;
+}
+
+/**
+ Search for a hostname match in the SubjectAlternativeNames.
+*/
+uint32_t
+check_san (SSL *ssl, const char *hostname)
+{
+ X509 *cert;
+ int extcount, ok = 0;
+ /* What an OpenSSL mess ... */
+ if (NULL == (cert = SSL_get_peer_certificate(ssl)))
+ {
+ die ("Getting certificate failed");
+ }
+
+ if ((extcount = X509_get_ext_count(cert)) > 0)
+ {
+ int i;
+ for (i = 0; i < extcount; ++i)
+ {
+ const char *extstr;
+ X509_EXTENSION *ext;
+ ext = X509_get_ext(cert, i);
+ extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
+
+ if (!strcmp(extstr, "subjectAltName"))
+ {
+
+ int j;
+ void *extvalstr;
+ const unsigned char *tmp;
+
+ STACK_OF(CONF_VALUE) *val;
+ CONF_VALUE *nval;
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ const
+#endif
+ X509V3_EXT_METHOD *method;
+
+ if (!(method = X509V3_EXT_get(ext)))
+ {
+ break;
+ }
+
+ tmp = ext->value->data;
+ if (method->it)
+ {
+ extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length,
+ ASN1_ITEM_ptr(method->it));
+ } else {
+ extvalstr = method->d2i(NULL, &tmp, ext->value->length);
+ }
+
+ if (!extvalstr)
+ {
+ break;
+ }
+
+ if (method->i2v)
+ {
+ val = method->i2v(method, extvalstr, NULL);
+ for (j = 0; j < sk_CONF_VALUE_num(val); ++j)
+ {
+ nval = sk_CONF_VALUE_value(val, j);
+ if ((!strcasecmp(nval->name, "DNS") &&
+ !strcasecmp(nval->value, hostname) ) ||
+ (!strcasecmp(nval->name, "iPAddress") &&
+ !strcasecmp(nval->value, hostname)))
+ {
+ verb ("V: subjectAltName matched: %s, type: %s", nval->value, nval->name); // We matched this; so it's safe to print
+ ok = 1;
+ break;
+ }
+ // Attempt to match subjectAltName DNS names
+ if (!strcasecmp(nval->name, "DNS"))
+ {
+ ok = check_wildcard_match_rfc2595(hostname, nval->value);
+ if (ok)
+ {
+ break;
+ }
+ }
+ verb_debug ("V: subjectAltName found but not matched: %s, type: %s",
+ nval->value, sanitize_string(nval->name));
+ }
+ }
+ } else {
+ verb_debug ("V: found non subjectAltName extension");
+ }
+ if (ok)
+ {
+ break;
+ }
+ }
+ } else {
+ verb_debug ("V: no X509_EXTENSION field(s) found");
+ }
+ X509_free(cert);
+ return ok;
+}
+
+uint32_t
+check_name (SSL *ssl, const char *hostname)
+{
+ uint32_t ret;
+ ret = check_cn(ssl, hostname);
+ ret += check_san(ssl, hostname);
+ if (0 != ret && 0 < ret)
+ {
+ verb ("V: hostname verification passed");
+ } else {
+ die ("hostname verification failed for host %s!", host);
+ }
+ return ret;
+}
+#endif
+
+#ifdef USE_POLARSSL
+uint32_t
+verify_signature (ssl_context *ssl, const char *hostname)
+{
+ int ssl_verify_result;
+
+ ssl_verify_result = ssl_get_verify_result (ssl);
+ if (ssl_verify_result & BADCERT_EXPIRED)
+ {
+ die ("certificate has expired");
+ }
+ if (ssl_verify_result & BADCERT_REVOKED)
+ {
+ die ("certificate has been revoked");
+ }
+ if (ssl_verify_result & BADCERT_CN_MISMATCH)
+ {
+ die ("CN and subject AltName mismatch for certificate");
+ }
+ if (ssl_verify_result & BADCERT_NOT_TRUSTED)
+ {
+ die ("certificate is self-signed or not signed by a trusted CA");
+ }
+
+ if (0 == ssl_verify_result)
+ {
+ verb ("V: verify success");
+ }
+ else
+ {
+ die ("certificate verification error: -0x%04x", -ssl_verify_result);
+ }
+ return 0;
+}
+#else
+uint32_t
+verify_signature (SSL *ssl, const char *hostname)
+{
+ long ssl_verify_result;
+ X509 *certificate;
+
+ certificate = SSL_get_peer_certificate(ssl);
+ if (NULL == certificate)
+ {
+ die ("Getting certificate failed");
+ }
+ // In theory, we verify that the cert is valid
+ ssl_verify_result = SSL_get_verify_result(ssl);
+ switch (ssl_verify_result)
+ {
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ die ("certificate is self signed");
+ case X509_V_OK:
+ verb ("V: certificate verification passed");
+ break;
+ default:
+ die ("certification verification error: %ld",
+ ssl_verify_result);
+ }
+ return 0;
+}
+#endif
+
+#ifdef USE_POLARSSL
+void
+check_key_length (ssl_context *ssl)
+{
+ uint32_t key_bits;
+ const x509_cert *certificate;
+ const rsa_context *public_key;
+ char buf[1024];
+
+ certificate = ssl_get_peer_cert (ssl);
+ if (NULL == certificate)
+ {
+ die ("Getting certificate failed");
+ }
+
+ x509parse_dn_gets(buf, 1024, &certificate->subject);
+ verb_debug ("V: Certificate for subject '%s'", buf);
+
+ public_key = &certificate->rsa;
+ if (NULL == public_key)
+ {
+ die ("public key extraction failure");
+ } else {
+ verb_debug ("V: public key is ready for inspection");
+ }
+ key_bits = mpi_msb (&public_key->N);
+ if (MIN_PUB_KEY_LEN >= key_bits)
+ {
+ die ("Unsafe public key size: %d bits", key_bits);
+ } else {
+ verb_debug ("V: key length appears safe");
+ }
+}
+#else
+void
+check_key_length (SSL *ssl)
+{
+ uint32_t key_bits;
+ X509 *certificate;
+ EVP_PKEY *public_key;
+ certificate = SSL_get_peer_certificate (ssl);
+ if (NULL == certificate)
+ {
+ die ("Getting certificate failed");
+ }
+ public_key = X509_get_pubkey (certificate);
+ if (NULL == public_key)
+ {
+ die ("public key extraction failure");
+ } else {
+ verb_debug ("V: public key is ready for inspection");
+ }
+
+ key_bits = get_certificate_keybits (public_key);
+ if (MIN_PUB_KEY_LEN >= key_bits && public_key->type != EVP_PKEY_EC)
+ {
+ die ("Unsafe public key size: %d bits", key_bits);
+ } else {
+ if (public_key->type == EVP_PKEY_EC)
+ if(key_bits >= MIN_ECC_PUB_KEY_LEN
+ && key_bits <= MAX_ECC_PUB_KEY_LEN)
+ {
+ verb_debug ("V: ECC key length appears safe");
+ } else {
+ die ("Unsafe ECC key size: %d bits", key_bits);
+ } else {
+ verb_debug ("V: key length appears safe");
+ }
+ }
+ EVP_PKEY_free (public_key);
+}
+#endif
+
+#ifdef USE_POLARSSL
+void
+inspect_key (ssl_context *ssl, const char *hostname)
+{
+ verify_signature (ssl, hostname);
+
+ // ssl_get_verify_result() already checks for CN / subjectAltName match
+ // and reports the mismatch as error. So check_name() is not called
+}
+#else
+void
+inspect_key (SSL *ssl, const char *hostname)
+{
+
+ verify_signature (ssl, hostname);
+ check_name (ssl, hostname);
+}
+#endif
+
+#ifdef USE_POLARSSL
+void
+check_timestamp (uint32_t server_time)
+{
+ uint32_t compiled_time = RECENT_COMPILE_DATE;
+ uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
+ if (compiled_time < server_time
+ &&
+ server_time < max_reasonable_time)
+ {
+ verb("V: remote peer provided: %d, preferred over compile time: %d",
+ server_time, compiled_time);
+ } else {
+ die("V: the remote server is a false ticker! server: %d compile: %d",
+ server_time, compiled_time);
+ }
+}
+
+static int ssl_do_handshake_part(ssl_context *ssl)
+{
+ int ret = 0;
+
+ /* Only do steps till ServerHello is received */
+ while (ssl->state != SSL_SERVER_HELLO)
+ {
+ ret = ssl_handshake_step (ssl);
+ if (0 != ret)
+ {
+ die("SSL handshake failed");
+ }
+ }
+ /* Do ServerHello so we can skim the timestamp */
+ ret = ssl_handshake_step (ssl);
+ if (0 != ret)
+ {
+ die("SSL handshake failed");
+ }
+
+ return 0;
+}
+
+/**
+ * Run SSL handshake and store the resulting time value in the
+ * 'time_map'.
+ *
+ * @param time_map where to store the current time
+ * @param time_is_an_illusion
+ * @param http whether to do an http request and take the date from that
+ * instead.
+ */
+static void
+run_ssl (uint32_t *time_map, int time_is_an_illusion, int http)
+{
+ entropy_context entropy;
+ ctr_drbg_context ctr_drbg;
+ ssl_context ssl;
+ proxy_polarssl_ctx proxy_ctx;
+ x509_cert cacert;
+ struct stat statbuf;
+ int ret = 0, server_fd = 0;
+ char *pers = "tlsdate-helper";
+
+ memset (&ssl, 0, sizeof(ssl_context));
+ memset (&cacert, 0, sizeof(x509_cert));
+
+ verb("V: Using PolarSSL for SSL");
+ if (ca_racket)
+ {
+ if (-1 == stat (ca_cert_container, &statbuf))
+ {
+ die("Unable to stat CA certficate container %s", ca_cert_container);
+ }
+ else
+ {
+ switch (statbuf.st_mode & S_IFMT)
+ {
+ case S_IFREG:
+ if (0 > x509parse_crtfile(&cacert, ca_cert_container))
+ fprintf(stderr, "x509parse_crtfile failed");
+ break;
+ case S_IFDIR:
+ if (0 > x509parse_crtpath(&cacert, ca_cert_container))
+ fprintf(stderr, "x509parse_crtpath failed");
+ break;
+ default:
+ die("Unable to load CA certficate container %s", ca_cert_container);
+ }
+ }
+ }
+
+ entropy_init (&entropy);
+ if (0 != ctr_drbg_init (&ctr_drbg, entropy_func, &entropy,
+ (unsigned char *) pers, strlen(pers)))
+ {
+ die("Failed to initialize CTR_DRBG");
+ }
+
+ if (0 != ssl_init (&ssl))
+ {
+ die("SSL initialization failed");
+ }
+ ssl_set_endpoint (&ssl, SSL_IS_CLIENT);
+ ssl_set_rng (&ssl, ctr_drbg_random, &ctr_drbg);
+ ssl_set_ca_chain (&ssl, &cacert, NULL, hostname_to_verify);
+ if (ca_racket)
+ {
+ // You can do SSL_VERIFY_REQUIRED here, but then the check in
+ // inspect_key() never happens as the ssl_handshake() will fail.
+ ssl_set_authmode (&ssl, SSL_VERIFY_OPTIONAL);
+ }
+
+ if (proxy)
+ {
+ char *scheme;
+ char *proxy_host;
+ char *proxy_port;
+
+ parse_proxy_uri (proxy, &scheme, &proxy_host, &proxy_port);
+
+ verb("V: opening socket to proxy %s:%s", proxy_host, proxy_port);
+ if (0 != net_connect (&server_fd, proxy_host, atoi(proxy_port)))
+ {
+ die ("SSL connection failed");
+ }
+
+ proxy_polarssl_init (&proxy_ctx);
+ proxy_polarssl_set_bio (&proxy_ctx, net_recv, &server_fd, net_send, &server_fd);
+ proxy_polarssl_set_host (&proxy_ctx, host);
+ proxy_polarssl_set_port (&proxy_ctx, atoi(port));
+ proxy_polarssl_set_scheme (&proxy_ctx, scheme);
+
+ ssl_set_bio (&ssl, proxy_polarssl_recv, &proxy_ctx, proxy_polarssl_send, &proxy_ctx);
+
+ verb("V: Handle proxy connection");
+ if (0 == proxy_ctx.f_connect (&proxy_ctx))
+ die("Proxy connection failed");
+ }
+ else
+ {
+ verb("V: opening socket to %s:%s", host, port);
+ if (0 != net_connect (&server_fd, host, atoi(port)))
+ {
+ die ("SSL connection failed");
+ }
+
+ ssl_set_bio (&ssl, net_recv, &server_fd, net_send, &server_fd);
+ }
+
+ verb("V: starting handshake");
+ if (0 != ssl_do_handshake_part (&ssl))
+ die("SSL handshake first part failed");
+
+ uint32_t timestamp = ( (uint32_t) ssl.in_msg[6] << 24 )
+ | ( (uint32_t) ssl.in_msg[7] << 16 )
+ | ( (uint32_t) ssl.in_msg[8] << 8 )
+ | ( (uint32_t) ssl.in_msg[9] );
+ check_timestamp (timestamp);
+
+ verb("V: continuing handshake");
+ /* Continue with handshake */
+ while (0 != (ret = ssl_handshake (&ssl)))
+ {
+ if (POLARSSL_ERR_NET_WANT_READ != ret &&
+ POLARSSL_ERR_NET_WANT_WRITE != ret)
+ {
+ die("SSL handshake failed");
+ }
+ }
+
+ // Verify the peer certificate against the CA certs on the local system
+ if (ca_racket) {
+ inspect_key (&ssl, hostname_to_verify);
+ } else {
+ verb ("V: Certificate verification skipped!");
+ }
+ check_key_length (&ssl);
+
+ memcpy (time_map, &timestamp, sizeof(uint32_t));
+ proxy_polarssl_free (&proxy_ctx);
+ ssl_free (&ssl);
+ x509_free (&cacert);
+}
+#else /* USE_POLARSSL */
+/**
+ * Run SSL handshake and store the resulting time value in the
+ * 'time_map'.
+ *
+ * @param time_map where to store the current time
+ * @param time_is_an_illusion
+ * @param http whether to do an http request and take the date from that
+ * instead.
+ */
+static void
+run_ssl (uint32_t *time_map, int time_is_an_illusion, int http)
+{
+ BIO *s_bio;
+ SSL_CTX *ctx;
+ SSL *ssl;
+ struct stat statbuf;
+ uint32_t result_time;
+
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ ctx = NULL;
+ if (0 == strcmp("sslv23", protocol))
+ {
+ verb ("V: using SSLv23_client_method()");
+ ctx = SSL_CTX_new(SSLv23_client_method());
+ } else if (0 == strcmp("sslv3", protocol))
+ {
+ verb ("V: using SSLv3_client_method()");
+ ctx = SSL_CTX_new(SSLv3_client_method());
+ } else if (0 == strcmp("tlsv1", protocol))
+ {
+ verb ("V: using TLSv1_client_method()");
+ ctx = SSL_CTX_new(TLSv1_client_method());
+ } else
+ die("Unsupported protocol `%s'", protocol);
+
+ if (ctx == NULL)
+ die("OpenSSL failed to support protocol `%s'", protocol);
+
+ verb("V: Using OpenSSL for SSL");
+ if (ca_racket)
+ {
+ if (-1 == stat(ca_cert_container, &statbuf))
+ {
+ die("Unable to stat CA certficate container %s", ca_cert_container);
+ } else
+ {
+ switch (statbuf.st_mode & S_IFMT)
+ {
+ case S_IFREG:
+ if (1 != SSL_CTX_load_verify_locations(ctx, ca_cert_container, NULL))
+ fprintf(stderr, "SSL_CTX_load_verify_locations failed");
+ break;
+ case S_IFDIR:
+ if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
+ fprintf(stderr, "SSL_CTX_load_verify_locations failed");
+ break;
+ default:
+ if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
+ {
+ fprintf(stderr, "SSL_CTX_load_verify_locations failed");
+ die("Unable to load CA certficate container %s", ca_cert_container);
+ }
+ }
+ }
+ }
+
+ if (NULL == (s_bio = make_ssl_bio(ctx)))
+ die ("SSL BIO setup failed");
+ BIO_get_ssl(s_bio, &ssl);
+ if (NULL == ssl)
+ die ("SSL setup failed");
+
+ if (time_is_an_illusion)
+ {
+ SSL_set_info_callback(ssl, openssl_time_callback);
+ }
+
+ SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+ verb("V: opening socket to %s:%s", host, port);
+ if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
+ (1 != BIO_set_conn_port(s_bio, port)) )
+ die ("Failed to initialize connection to `%s:%s'", host, port);
+
+ if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
+ die ("BIO_new_fp returned error, possibly: %s", strerror(errno));
+
+ // This should run in seccomp
+ // eg: prctl(PR_SET_SECCOMP, 1);
+ if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later?
+ die ("SSL connection failed");
+ if (1 != BIO_do_handshake(s_bio))
+ die ("SSL handshake failed");
+
+ // from /usr/include/openssl/ssl3.h
+ // ssl->s3->server_random is an unsigned char of 32 bits
+ memcpy(&result_time, ssl->s3->server_random, sizeof (uint32_t));
+ verb("V: In TLS response, T=%lu", (unsigned long)ntohl(result_time));
+
+ if (http) {
+ char buf[1024];
+ verb_debug ("V: Starting HTTP");
+ if (snprintf(buf, sizeof(buf),
+ HTTP_REQUEST, HTTPS_USER_AGENT, hostname_to_verify) >= 1024)
+ die("hostname too long");
+ buf[1023]='\0'; /* Unneeded. */
+ verb_debug ("V: Writing HTTP request");
+ if (1 != write_all_to_bio(s_bio, buf))
+ die ("write all to bio failed.");
+ verb_debug ("V: Reading HTTP response");
+ if (1 != read_http_date_from_bio(s_bio, &result_time))
+ die ("read all from bio failed.");
+ verb ("V: Received HTTP response. T=%lu", (unsigned long)result_time);
+
+ result_time = htonl(result_time);
+ }
+
+ // Verify the peer certificate against the CA certs on the local system
+ if (ca_racket) {
+ inspect_key (ssl, hostname_to_verify);
+ } else {
+ verb ("V: Certificate verification skipped!");
+ }
+ check_key_length(ssl);
+
+ memcpy(time_map, &result_time, sizeof (uint32_t));
+
+ SSL_free(ssl);
+ SSL_CTX_free(ctx);
+}
+#endif /* USE_POLARSSL */
+/** drop root rights and become 'nobody' */
+
+int
+main(int argc, char **argv)
+{
+ uint32_t *time_map;
+ struct tlsdate_time start_time, end_time, warp_time;
+ int status;
+ pid_t ssl_child;
+ long long rt_time_ms;
+ uint32_t server_time_s;
+ int setclock;
+ int showtime;
+ int showtime_raw;
+ int timewarp;
+ int leap;
+ int http;
+
+ if (argc != 13)
+ return 1;
+ host = argv[1];
+ hostname_to_verify = argv[1];
+ port = argv[2];
+ protocol = argv[3];
+ ca_cert_container = argv[6];
+ ca_racket = (0 != strcmp ("unchecked", argv[4]));
+ verbose = (0 != strcmp ("quiet", argv[5]));
+ verbose_debug = (0 != strcmp ("verbose", argv[5]));
+ setclock = (0 == strcmp ("setclock", argv[7]));
+ showtime = (0 == strcmp ("showtime", argv[8]));
+ showtime_raw = (0 == strcmp ("showtime=raw", argv[8]));
+ timewarp = (0 == strcmp ("timewarp", argv[9]));
+ leap = (0 == strcmp ("leapaway", argv[10]));
+ proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
+ http = (0 == (strcmp("http", argv[12])));
+
+ /* Initalize warp_time with RECENT_COMPILE_DATE */
+ clock_init_time(&warp_time, RECENT_COMPILE_DATE, 0);
+
+ verb ("V: RECENT_COMPILE_DATE is %lu.%06lu",
+ (unsigned long) CLOCK_SEC(&warp_time),
+ (unsigned long) CLOCK_USEC(&warp_time));
+
+ if (1 != timewarp)
+ {
+ verb ("V: we'll do the time warp another time - we're not setting clock");
+ }
+
+ /* We are not going to set the clock, thus no need to stay root */
+ if (0 == setclock && 0 == timewarp)
+ {
+ verb ("V: attemping to drop administrator privileges");
+ drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
+ }
+
+ // We cast the mmap value to remove this error when compiling with g++:
+ // src/tlsdate-helper.c: In function ‘int main(int, char**)’:
+ // src/tlsdate-helper.c:822:41: error: invalid conversion from ‘void*’ to ‘uint32_t
+ time_map = (uint32_t *) mmap (NULL, sizeof (uint32_t),
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (MAP_FAILED == time_map)
+ {
+ fprintf (stderr, "mmap failed: %s",
+ strerror (errno));
+ return 1;
+ }
+
+ /* Get the current time from the system clock. */
+ if (0 != clock_get_real_time(&start_time))
+ {
+ die ("Failed to read current time of day: %s", strerror (errno));
+ }
+
+ verb ("V: time is currently %lu.%06lu",
+ (unsigned long) CLOCK_SEC(&start_time),
+ (unsigned long) CLOCK_NSEC(&start_time));
+
+ if (((unsigned long) CLOCK_SEC(&start_time)) < ((unsigned long) CLOCK_SEC(&warp_time)))
+ {
+ verb ("V: local clock time is less than RECENT_COMPILE_DATE");
+ if (timewarp)
+ {
+ verb ("V: Attempting to warp local clock into the future");
+ if (0 != clock_set_real_time(&warp_time))
+ {
+ die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)",
+ strerror (errno),
+ (unsigned long) CLOCK_SEC(&warp_time),
+ (unsigned long) CLOCK_SEC(&warp_time));
+ }
+ if (0 != clock_get_real_time(&start_time))
+ {
+ die ("Failed to read current time of day: %s", strerror (errno));
+ }
+ verb ("V: time is currently %lu.%06lu",
+ (unsigned long) CLOCK_SEC(&start_time),
+ (unsigned long) CLOCK_NSEC(&start_time));
+ verb ("V: It's just a step to the left...");
+ }
+ } else {
+ verb ("V: time is greater than RECENT_COMPILE_DATE");
+ }
+
+ /* initialize to bogus value, just to be on the safe side */
+ *time_map = 0;
+
+ /* Run SSL interaction in separate process (and not as 'root') */
+ ssl_child = fork ();
+ if (-1 == ssl_child)
+ die ("fork failed: %s", strerror (errno));
+ if (0 == ssl_child)
+ {
+ drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
+ run_ssl (time_map, leap, http);
+ (void) munmap (time_map, sizeof (uint32_t));
+ _exit (0);
+ }
+ if (ssl_child != platform->process_wait (ssl_child, &status, 1))
+ die ("waitpid failed: %s", strerror (errno));
+ if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
+ die ("child process failed in SSL handshake");
+
+ if (0 != clock_get_real_time(&end_time))
+ die ("Failed to read current time of day: %s", strerror (errno));
+
+ /* calculate RTT */
+ rt_time_ms = (CLOCK_SEC(&end_time) - CLOCK_SEC(&start_time)) * 1000 + (CLOCK_USEC(&end_time) - CLOCK_USEC(&start_time)) / 1000;
+ if (rt_time_ms < 0)
+ rt_time_ms = 0; /* non-linear time... */
+#ifdef USE_POLARSSL
+ server_time_s = *time_map;
+#else
+ server_time_s = ntohl (*time_map);
+#endif
+ // We should never have a time_map of zero here;
+ // It either stayed zero or we have a false ticker.
+ if ( 0 == server_time_s )
+ die ("child process failed to update time map; weird platform issues?");
+ munmap (time_map, sizeof (uint32_t));
+
+ verb ("V: server time %u (difference is about %d s) was fetched in %lld ms",
+ (unsigned int) server_time_s,
+ CLOCK_SEC(&start_time) - server_time_s,
+ rt_time_ms);
+
+ /* warning if the handshake took too long */
+ if (rt_time_ms > TLS_RTT_UNREASONABLE) {
+ die ("the TLS handshake took more than %d msecs - consider using a different " \
+ "server or run it again", TLS_RTT_UNREASONABLE);
+ }
+ if (rt_time_ms > TLS_RTT_THRESHOLD) {
+ verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
+ "server or run it again", TLS_RTT_THRESHOLD);
+ }
+
+ if (showtime_raw)
+ {
+ fwrite(&server_time_s, sizeof(server_time_s), 1, stdout);
+ }
+
+ if (showtime)
+ {
+ struct tm ltm;
+ time_t tim = server_time_s;
+ char buf[256];
+
+ localtime_r(&tim, &ltm);
+ if (0 == strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
+ {
+ die ("strftime returned 0");
+ }
+ fprintf(stdout, "%s\n", buf);
+ }
+
+ /* finally, actually set the time */
+ if (setclock)
+ {
+ struct tlsdate_time server_time;
+
+ clock_init_time(&server_time, server_time_s + (rt_time_ms / 2 / 1000),
+ (rt_time_ms / 2) % 1000);
+
+ // We should never receive a time that is before the time we were last
+ // compiled; we subscribe to the linear theory of time for this program
+ // and this program alone!
+ if (CLOCK_SEC(&server_time) >= MAX_REASONABLE_TIME)
+ die("remote server is a false ticker from the future!");
+ if (CLOCK_SEC(&server_time) <= RECENT_COMPILE_DATE)
+ die ("remote server is a false ticker!");
+ if (0 != clock_set_real_time(&server_time))
+ die ("setting time failed: %s (Difference from server is about %d s)",
+ strerror (errno),
+ CLOCK_SEC(&start_time) - server_time_s);
+ verb ("V: setting time succeeded");
+ }
+ return 0;
+}
diff --git a/src/tlsdate-helper.h b/src/tlsdate-helper.h
new file mode 100644
index 0000000..64e4092
--- /dev/null
+++ b/src/tlsdate-helper.h
@@ -0,0 +1,144 @@
+/* Copyright (c) 2012, Jacob Appelbaum
+ * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tlsdate-helper.h
+ * \brief The secondary header for our clock helper.
+ **/
+
+#ifndef TLSDATEHELPER_H
+#define TLSDATEHELPER_H
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef TARGET_OS_HAIKU
+#include <posix/string.h>
+#include <bsd/string.h>
+#endif
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <pwd.h>
+#include <grp.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#ifdef HAVE_PRCTL
+#include <sys/prctl.h>
+#endif
+
+#ifndef USE_POLARSSL
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#endif
+
+int verbose;
+int verbose_debug;
+
+#include "src/util.h"
+
+/** Name of user that we feel safe to run SSL handshake with. */
+#ifndef UNPRIV_USER
+#define UNPRIV_USER "nobody"
+#endif
+#ifndef UNPRIV_GROUP
+#define UNPRIV_GROUP "nogroup"
+#endif
+
+// We should never accept a time before we were compiled
+// We measure in seconds since the epoch - eg: echo `date '+%s'`
+// We set this manually to ensure others can reproduce a build;
+// automation of this will make every build different!
+#ifndef RECENT_COMPILE_DATE
+#define RECENT_COMPILE_DATE 1342323666L
+#endif
+
+#ifndef MAX_REASONABLE_TIME
+#define MAX_REASONABLE_TIME 1999991337L
+#endif
+
+#ifndef MIN_PUB_KEY_LEN
+#define MIN_PUB_KEY_LEN (uint32_t) 1023
+#endif
+
+#ifndef MIN_ECC_PUB_KEY_LEN
+#define MIN_ECC_PUB_KEY_LEN (uint32_t) 160
+#endif
+
+#ifndef MAX_ECC_PUB_KEY_LEN
+#define MAX_ECC_PUB_KEY_LEN (uint32_t) 521
+#endif
+// After the duration of the TLS handshake exceeds this threshold
+// (in msec), a warning is printed.
+#define TLS_RTT_THRESHOLD 2000
+
+// After the duration of the TLS handshake exceeds this threshold
+// (in msec), we consider the operation to have failed.
+#define TLS_RTT_UNREASONABLE 30000
+
+// RFC 5280 says...
+// ub-common-name-length INTEGER ::= 64
+#define MAX_CN_NAME_LENGTH 64
+
+// RFC 1034 and posix say...
+#define TLSDATE_HOST_NAME_MAX 255
+
+// To support our RFC 2595 wildcard verification
+#define RFC2595_MIN_LABEL_COUNT 3
+
+// Define a max length for the HTTP Date: header
+#define MAX_DATE_LINE_LEN 32
+
+// Define a max length for HTTP headers
+#define MAX_HTTP_HEADERS_SIZE 8192
+
+// Define our basic HTTP request
+#define HTTP_REQUEST \
+ "HEAD / HTTP/1.1\r\n" \
+ "User-Agent: %s\r\n" \
+ "Host: %s\r\n" \
+ "\r\n"
+
+static int ca_racket;
+
+static const char *host;
+
+static const char *hostname_to_verify;
+
+static const char *port;
+
+static const char *protocol;
+
+static char *proxy;
+
+static const char *ca_cert_container;
+#ifndef USE_POLARSSL
+void openssl_time_callback (const SSL* ssl, int where, int ret);
+uint32_t get_certificate_keybits (EVP_PKEY *public_key);
+uint32_t check_cn (SSL *ssl, const char *hostname);
+uint32_t check_san (SSL *ssl, const char *hostname);
+long openssl_check_against_host_and_verify (SSL *ssl);
+uint32_t check_name (SSL *ssl, const char *hostname);
+uint32_t verify_signature (SSL *ssl, const char *hostname);
+void check_key_length (SSL *ssl);
+void inspect_key (SSL *ssl, const char *hostname);
+void check_key_length (SSL *ssl);
+void inspect_key (SSL *ssl, const char *hostname);
+#endif
+uint32_t dns_label_count (char *label, char *delim);
+uint32_t check_wildcard_match_rfc2595 (const char *orig_hostname,
+ const char *orig_cert_wild_card);
+static void run_ssl (uint32_t *time_map, int time_is_an_illusion, int http);
+
+#endif
diff --git a/src/tlsdate-monitor.c b/src/tlsdate-monitor.c
new file mode 100644
index 0000000..5169a09
--- /dev/null
+++ b/src/tlsdate-monitor.c
@@ -0,0 +1,99 @@
+/*
+ * tlsdate-monitor.c - tlsdated monitor for tlsdate.
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+static
+char **
+build_argv (struct opts *opts)
+{
+ int argc;
+ char **new_argv;
+ assert (opts->sources);
+ /* choose the next source in the list; if we're at the end, start over. */
+ if (!opts->cur_source || !opts->cur_source->next)
+ opts->cur_source = opts->sources;
+ else
+ opts->cur_source = opts->cur_source->next;
+ for (argc = 0; opts->base_argv[argc]; argc++)
+ ;
+ /* Put an arbitrary limit on the number of args. */
+ if (argc > 1024)
+ return NULL;
+ argc++; /* uncounted null terminator */
+ argc += 9; /* -H host -p port -x proxy -Vraw -n -l */
+ new_argv = malloc (argc * sizeof (char *));
+ if (!new_argv)
+ return NULL;
+ for (argc = 0; opts->base_argv[argc]; argc++)
+ new_argv[argc] = opts->base_argv[argc];
+ new_argv[argc++] = "-H";
+ new_argv[argc++] = opts->cur_source->host;
+ new_argv[argc++] = "-p";
+ new_argv[argc++] = opts->cur_source->port;
+ if (opts->cur_source->proxy || opts->proxy)
+ {
+ char *proxy = opts->proxy ? opts->proxy : opts->cur_source->proxy;
+ if (strcmp (proxy, ""))
+ {
+ new_argv[argc++] = (char *) "-x";
+ new_argv[argc++] = proxy;
+ }
+ }
+ new_argv[argc++] = "-Vraw";
+ new_argv[argc++] = "-n";
+ if (opts->leap)
+ new_argv[argc++] = "-l";
+ new_argv[argc++] = NULL;
+ return new_argv;
+}
+
+/* Run tlsdate and redirects stdout to the monitor_fd */
+int
+tlsdate (struct state *state)
+{
+ char **new_argv;
+ pid_t pid;
+ switch ((pid = fork()))
+ {
+ case 0: /* child! */
+ break;
+ case -1:
+ perror ("fork() failed!");
+ return -1;
+ default:
+ verb_debug ("[tlsdate-monitor] spawned tlsdate: %d", pid);
+ state->tlsdate_pid = pid;
+ return 0;
+ }
+ if (!(new_argv = build_argv (&state->opts)))
+ fatal ("out of memory building argv");
+ /* Replace stdout with the pipe back to tlsdated */
+ if (dup2 (state->tlsdate_monitor_fd, STDOUT_FILENO) < 0)
+ {
+ perror ("dup2 failed");
+ _exit (2);
+ }
+ execve (new_argv[0], new_argv, state->envp);
+ perror ("[tlsdate-monitor] execve() failed");
+ _exit (1);
+}
diff --git a/src/tlsdate-setter.c b/src/tlsdate-setter.c
new file mode 100644
index 0000000..a40f67e
--- /dev/null
+++ b/src/tlsdate-setter.c
@@ -0,0 +1,178 @@
+/*
+ * tlsdate-setter.c - privileged time setter for tlsdated
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/dbus.h"
+#include "src/seccomp.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+/* Atomically writes the timestamp to the specified fd. */
+int
+save_timestamp_to_fd (int fd, time_t t)
+{
+ return platform->file_write(fd, &t, sizeof (t));
+}
+
+void
+report_setter_error (siginfo_t *info)
+{
+ const char *code;
+ int killit = 0;
+ switch (info->si_code)
+ {
+ case CLD_EXITED:
+ code = "EXITED";
+ break;
+ case CLD_KILLED:
+ code = "KILLED";
+ break;
+ case CLD_DUMPED:
+ code = "DUMPED";
+ break;
+ case CLD_STOPPED:
+ code = "STOPPED";
+ killit = 1;
+ break;
+ case CLD_TRAPPED:
+ code = "TRAPPED";
+ killit = 1;
+ break;
+ case CLD_CONTINUED:
+ code = "CONTINUED";
+ killit = 1;
+ break;
+ default:
+ code = "???";
+ killit = 1;
+ }
+ info ("tlsdate-setter exitting: code:%s status:%d pid:%d uid:%d",
+ code, info->si_status, info->si_pid, info->si_uid);
+ if (killit)
+ kill (info->si_pid, SIGKILL);
+}
+
+void
+time_setter_coprocess (int time_fd, int notify_fd, struct state *state)
+{
+ int save_fd = -1;
+ int status;
+ prctl (PR_SET_NAME, "tlsdated-setter");
+ if (state->opts.should_save_disk && !state->opts.dry_run)
+ {
+ /* TODO(wad) platform->file_open */
+ if ( (save_fd = open (state->timestamp_path,
+ O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
+ {
+ /* Attempt to unlink the path on the way out. */
+ unlink (state->timestamp_path);
+ status = SETTER_NO_SAVE;
+ goto notify_and_die;
+ }
+ }
+ /* XXX: Drop all privs but CAP_SYS_TIME */
+#ifdef HAVE_SECCOMP_FILTER
+ if (enable_setter_seccomp())
+ {
+ status = SETTER_NO_SBOX;
+ goto notify_and_die;
+ }
+#endif
+ while (1)
+ {
+ struct timeval tv = { 0, 0 };
+ /* The wire protocol is a time_t, but the caller should
+ * always be the unprivileged tlsdated process which spawned this
+ * helper.
+ * There are two special messages:
+ * (time_t) 0: requests a clean shutdown
+ * (time_t) < 0: indicates not to write to disk
+ * On Linux, time_t is a signed long. Expanding the protocol
+ * is easy, but writing one long only is ideal.
+ */
+ ssize_t bytes = read (time_fd, &tv.tv_sec, sizeof (tv.tv_sec));
+ int save = 1;
+ if (bytes == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ status = SETTER_READ_ERR;
+ goto notify_and_die;
+ }
+ if (bytes == 0)
+ {
+ /* End of pipe */
+ status = SETTER_READ_ERR;
+ goto notify_and_die;
+ }
+ if (bytes != sizeof (tv.tv_sec))
+ continue;
+ if (tv.tv_sec < 0)
+ {
+ /* Don't write to disk */
+ tv.tv_sec = -tv.tv_sec;
+ save = 0;
+ }
+ if (tv.tv_sec == 0)
+ {
+ status = SETTER_EXIT;
+ goto notify_and_die;
+ }
+ if (is_sane_time (tv.tv_sec))
+ {
+ /* It would be nice if time was only allowed to move forward, but
+ * if a single time source is wrong, then it could make it impossible
+ * to recover from once the time is written to disk.
+ */
+ status = SETTER_BAD_TIME;
+ if (!state->opts.dry_run)
+ {
+ if (settimeofday (&tv, NULL) < 0)
+ {
+ status = SETTER_SET_ERR;
+ goto notify_and_die;
+ }
+ if (state->opts.should_sync_hwclock &&
+ platform->rtc_write(&state->hwclock, &tv))
+ {
+ status = SETTER_NO_RTC;
+ goto notify_and_die;
+ }
+ if (save && save_fd != -1 &&
+ save_timestamp_to_fd (save_fd, tv.tv_sec))
+ {
+ status = SETTER_NO_SAVE;
+ goto notify_and_die;
+ }
+ }
+ status = SETTER_TIME_SET;
+ }
+ /* TODO(wad) platform->file_write */
+ IGNORE_EINTR (write (notify_fd, &status, sizeof(status)));
+ }
+notify_and_die:
+ IGNORE_EINTR (write (notify_fd, &status, sizeof(status)));
+ close (notify_fd);
+ close (save_fd);
+ _exit (status);
+}
diff --git a/src/tlsdate.c b/src/tlsdate.c
new file mode 100644
index 0000000..dd7f993
--- /dev/null
+++ b/src/tlsdate.c
@@ -0,0 +1,235 @@
+/* Copyright (c) 2012, Jacob Appelbaum.
+ * Copyright (c) 2012, The Tor Project, Inc.
+ * Copyright (c) 2012, Christian Grothoff. */
+/* See LICENSE for licensing information */
+/*
+ This file contains the license for tlsdate,
+ a free software project to set your system clock securely.
+
+ It also lists the licenses for other components used by tlsdate.
+
+ For more information about tlsdate, see https://github.com/ioerror/tlsdate
+
+ If you got this file as a part of a larger bundle,
+ there may be other license terms that you should be aware of.
+
+===============================================================================
+tlsdate is distributed under this license:
+
+Copyright (c) 2011-2012, Jacob Appelbaum <jacob@appelbaum.net>
+Copyright (c) 2011-2012, The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+If you got tlsdate as a static binary with OpenSSL included, then you should
+know:
+
+ "This product includes software developed by the OpenSSL Project for use in
+ the OpenSSL Toolkit (http://www.openssl.org/)"
+
+===============================================================================
+*/
+
+/**
+ * \file tlsdate.c
+ * \brief The main program to assist in setting the system clock.
+ **/
+
+/*
+ * tlsdate is a tool for setting the system clock by hand or by communication
+ * with the network. It does not set the RTC. It is designed to be as secure as
+ * TLS (RFC 2246) but of course the security of TLS is often reduced to
+ * whichever CA racket you believe is trustworthy. By default, tlsdate trusts
+ * your local CA root store - so any of these companies could assist in a MITM
+ * attack against you and you'd be screwed.
+
+ * This tool is designed to be run by hand or as a system daemon. It must be
+ * run as root or otherwise have the proper caps; it will not be able to set
+ * the system time without running as root or another privileged user.
+ */
+
+#include "config.h"
+#include "src/tlsdate.h"
+
+
+/** Return the proper commandline switches when the user needs information. */
+static void
+usage (void)
+{
+ fprintf (stderr, "tlsdate usage:\n"
+ " [-h|--help]\n"
+ " [-s|--skip-verification]\n"
+ " [-n|--dont-set-clock]\n"
+ " [-H|--host] [hostname|ip]\n"
+ " [-p|--port] [port number]\n"
+ " [-P|--protocol] [sslv23|sslv3|tlsv1]\n"
+ " [-C|--certcontainer] [dirname|filename]\n"
+ " [-v|--verbose]\n"
+ " [-V|--showtime] [human|raw]\n"
+ " [-t|--timewarp]\n"
+ " [-l|--leap]\n"
+ " [-x|--proxy] [url]\n"
+ " [-w|--http]\n");
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int verbose;
+ int ca_racket;
+ int showtime;
+ int setclock;
+ const char *host;
+ const char *port;
+ const char *protocol;
+ const char *ca_cert_container;
+ int timewarp;
+ int leap;
+ const char *proxy;
+ int http;
+
+ host = DEFAULT_HOST;
+ port = DEFAULT_PORT;
+ protocol = DEFAULT_PROTOCOL;
+ ca_cert_container = DEFAULT_CERTFILE;
+ verbose = 0;
+ ca_racket = 1;
+ showtime = 0;
+ setclock = 1;
+ timewarp = 0;
+ leap = 0;
+ proxy = NULL;
+ http = 0;
+
+ while (1)
+ {
+ int option_index = 0;
+ int c;
+ static struct option long_options[] =
+ {
+ {"verbose", 0, 0, 'v'},
+ {"showtime", 2, 0, 'V'},
+ {"skip-verification", 0, 0, 's'},
+ {"help", 0, 0, 'h'},
+ {"host", 0, 0, 'H'},
+ {"port", 0, 0, 'p'},
+ {"protocol", 0, 0, 'P'},
+ {"dont-set-clock", 0, 0, 'n'},
+ {"certcontainer", 0, 0, 'C'},
+ {"timewarp", 0, 0, 't'},
+ {"leap", 0, 0, 'l'},
+ {"proxy", 0, 0, 'x'},
+ {"http", 0, 0, 'w'},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "vV::shH:p:P:nC:tlx:w",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+ switch (c)
+ {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'V':
+ showtime = (optarg && 0 == strcmp ("raw", optarg) ? 2:1);
+ break;
+ case 's':
+ ca_racket = 0;
+ break;
+ case 'h':
+ usage();
+ exit (1);
+ break;
+ case 'H':
+ host = optarg;
+ break;
+ case 'p':
+ port = optarg;
+ break;
+ case 'P':
+ protocol = optarg;
+ break;
+ case 'n':
+ setclock = 0;
+ break;
+ case 'C':
+ ca_cert_container = optarg;
+ break;
+ case 't':
+ timewarp = 1;
+ break;
+ case 'l':
+ leap = 1;
+ break;
+ case 'x':
+ proxy = optarg;
+ break;
+ case 'w':
+ http = 1;
+ break;
+ case '?':
+ break;
+ default :
+ fprintf (stderr, "Unknown option!\n");
+ usage();
+ exit (1);
+ }
+ }
+ if (1 == verbose) {
+ fprintf(stderr,
+ "V: tlsdate version %s\n"
+ "V: We were called with the following arguments:\n"
+ "V: %s host = %s:%s\n",
+ PACKAGE_VERSION,
+ ca_racket ? "validate SSL certificates" : "disable SSL certificate check",
+ host, port);
+ if (0 == ca_racket)
+ fprintf(stderr, "WARNING: Skipping certificate verification!\n");
+ }
+ execlp (TLSDATE_HELPER,
+ "tlsdate",
+ host,
+ port,
+ protocol,
+ (ca_racket ? "racket" : "unchecked"),
+ (verbose ? "verbose" : "quiet"),
+ ca_cert_container,
+ (setclock ? "setclock" : "dont-set-clock"),
+ (showtime ? (showtime == 2 ? "showtime=raw" : "showtime") : "no-showtime"),
+ (timewarp ? "timewarp" : "no-fun"),
+ (leap ? "leapaway" : "holdfast"),
+ (proxy ? proxy : "none"),
+ (http ? "http" : "tls"),
+ NULL);
+ perror ("Failed to run tlsdate-helper");
+ return 1;
+}
diff --git a/src/tlsdate.h b/src/tlsdate.h
new file mode 100644
index 0000000..52305eb
--- /dev/null
+++ b/src/tlsdate.h
@@ -0,0 +1,245 @@
+/* Copyright (c) 2013, Jacob Appelbaum
+ * Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tlsdate.h
+ * \brief The main header for our clock helper.
+ **/
+
+#ifndef TLSDATE_H
+#define TLSDATE_H
+
+#include "src/configmake.h"
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <limits.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "src/rtc.h"
+
+#define DEFAULT_HOST "google.com"
+#define DEFAULT_PORT "443"
+#define DEFAULT_PROXY "none"
+#define DEFAULT_PROTOCOL "tlsv1"
+#define DEFAULT_CERTDIR "/etc/ssl/certs"
+#define DEFAULT_CERTFILE TLSDATE_CERTFILE
+#define DEFAULT_DAEMON_CACHEDIR "/var/cache/tlsdated"
+#define DEFAULT_DAEMON_TMPSUFFIX ".new"
+#define DEFAULT_TLSDATE TLSDATE
+#define DEFAULT_RTC_DEVICE "/dev/rtc"
+#define DEFAULT_CONF_FILE TLSDATE_CONF_DIR "tlsdated.conf"
+
+/* tlsdated magic numbers */
+#define MAX_TRIES 10
+#define WAIT_BETWEEN_TRIES 10
+#define SUBPROCESS_TRIES 10
+#define SUBPROCESS_WAIT_BETWEEN_TRIES 10
+#define RESOLVER_TIMEOUT 30
+/* Invalidate the network sync once per day. */
+#define STEADY_STATE_INTERVAL (60*60*24)
+/* Check if the clock has jumped every four hours. */
+#define CONTINUITY_INTERVAL (60*60*4)
+#define DEFAULT_SYNC_HWCLOCK 1
+#define DEFAULT_LOAD_FROM_DISK 1
+#define DEFAULT_SAVE_TO_DISK 1
+#define DEFAULT_USE_NETLINK 1
+#define DEFAULT_DRY_RUN 0
+#define MAX_SANE_BACKOFF (10*60) /* exponential backoff should only go this far */
+
+#ifndef TLSDATED_MAX_DATE
+#define TLSDATED_MAX_DATE 1999991337L /* this'll be a great bug some day */
+#endif
+
+#define MAX_EVENT_PRIORITIES 2
+#define PRI_SAVE 0
+#define PRI_NET 1
+#define PRI_WAKE 1
+#define PRI_ANY 1
+
+/* Sync sources in order of "reliability" */
+#define SYNC_TYPE_NONE (0)
+#define SYNC_TYPE_BUILD (1 << 0)
+#define SYNC_TYPE_DISK (1 << 1)
+#define SYNC_TYPE_RTC (1 << 2)
+#define SYNC_TYPE_PLATFORM (1 << 3)
+#define SYNC_TYPE_NET (1 << 4)
+
+/* Simple time setter<>tlsdated protocol */
+#define SETTER_EXIT 0
+#define SETTER_BAD_TIME 1
+#define SETTER_NO_SAVE 2
+#define SETTER_READ_ERR 3
+#define SETTER_TIME_SET 4
+#define SETTER_SET_ERR 5
+#define SETTER_NO_SBOX 6
+#define SETTER_NO_RTC 7
+
+#define TEST_HOST 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', \
+ 'c', 'o', 'm'
+#define TEST_HOST_SIZE 14
+static const char kTestHost[] = { TEST_HOST, 0 };
+#define TEST_PORT 80
+
+/** The current version of tlsdate. */
+#define tlsdate_version VERSION
+
+/** GNU/Hurd support requires that we declare this ourselves: */
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+#ifndef MAXPATHLEN
+#define MAXPATHLEN PATH_MAX
+#endif
+
+struct source
+{
+ struct source *next;
+ char *host;
+ char *port;
+ char *proxy;
+ int id;
+};
+
+struct opts
+{
+ const char *user;
+ const char *group;
+ int max_tries;
+ int min_steady_state_interval;
+ int wait_between_tries;
+ int subprocess_tries;
+ int subprocess_wait_between_tries;
+ int steady_state_interval;
+ int continuity_interval;
+ const char *base_path;
+ char **base_argv;
+ char **argv;
+ int should_sync_hwclock;
+ int should_load_disk;
+ int should_save_disk;
+ int should_netlink;
+ int dry_run;
+ int jitter;
+ char *conf_file;
+ struct source *sources;
+ struct source *cur_source;
+ char *proxy;
+ int leap;
+ int should_dbus;
+};
+
+#define MAX_FQDN_LEN 255
+#define MAX_SCHEME_LEN 9
+#define MAX_PORT_LEN 6 /* incl. : */
+#define MAX_PROXY_URL (MAX_FQDN_LEN + MAX_SCHEME_LEN + MAX_PORT_LEN + 1)
+
+enum event_id_t
+{
+ E_RESOLVER = 0,
+ E_TLSDATE,
+ E_TLSDATE_STATUS,
+ E_TLSDATE_TIMEOUT,
+ E_SAVE,
+ E_SIGCHLD,
+ E_SIGTERM,
+ E_STEADYSTATE,
+ E_ROUTEUP,
+ E_MAX
+};
+
+struct event_base;
+
+/* This struct is used for passing tlsdated runtime state between
+ * events/ in its event loop.
+ */
+struct state
+{
+ struct opts opts;
+ struct event_base *base;
+ void *dbus;
+ char **envp;
+
+ time_t clock_delta;
+ int last_sync_type;
+ time_t last_time;
+
+ char timestamp_path[PATH_MAX];
+ struct rtc_handle hwclock;
+ char dynamic_proxy[MAX_PROXY_URL];
+ /* Event triggered events */
+
+ struct event *events[E_MAX];
+ int tlsdate_monitor_fd;
+ pid_t tlsdate_pid;
+ pid_t setter_pid;
+ int setter_save_fd;
+ int setter_notify_fd;
+ uint32_t backoff;
+ int tries;
+ int resolving;
+ int running; /* tlsdate itself */
+ int exitting;
+};
+
+char timestamp_path[PATH_MAX];
+
+int is_sane_time (time_t ts);
+int load_disk_timestamp (const char *path, time_t * t);
+void save_disk_timestamp (const char *path, time_t t);
+int add_jitter (int base, int jitter);
+void time_setter_coprocess (int time_fd, int notify_fd, struct state *state);
+int tlsdate (struct state *state);
+
+int save_timestamp_to_fd (int fd, time_t t);
+void set_conf_defaults (struct opts *opts);
+int new_tlsdate_monitor_pipe (int fds[2]);
+int read_tlsdate_response (int fd, time_t *t);
+
+void invalidate_time (struct state *state);
+int check_continuity (time_t *delta);
+
+void action_check_continuity (int fd, short what, void *arg);
+void action_kickoff_time_sync (int fd, short what, void *arg);
+void action_invalidate_time (int fd, short what, void *arg);
+void action_stdin_wakeup (int fd, short what, void *arg);
+void action_netlink_ready (int fd, short what, void *arg);
+void action_run_tlsdate (int fd, short what, void *arg);
+void action_sigterm (int fd, short what, void *arg);
+void action_sync_and_save (int fd, short what, void *arg);
+void action_time_set (int fd, short what, void *arg);
+void action_tlsdate_status (int fd, short what, void *arg);
+
+int setup_event_timer_continuity (struct state *state);
+int setup_event_timer_sync (struct state *state);
+int setup_event_route_up (struct state *state);
+int setup_time_setter (struct state *state);
+int setup_tlsdate_status (struct state *state);
+int setup_sigchld_event (struct state *state, int persist);
+
+void report_setter_error (siginfo_t *info);
+
+void sync_and_save (void *hwclock_handle, int should_save);
+
+/** This is where we store parsed commandline options. */
+typedef struct
+{
+ int verbose;
+ int verbose_debug;
+ int ca_racket;
+ int help;
+ int showtime;
+ int setclock;
+ time_t manual_time;
+ char *host;
+ char *port;
+ char *protocol;
+} tlsdate_options_t;
+
+#endif /* TLSDATE_H */
diff --git a/src/tlsdated-unittest.c b/src/tlsdated-unittest.c
new file mode 100644
index 0000000..c82a85c
--- /dev/null
+++ b/src/tlsdated-unittest.c
@@ -0,0 +1,328 @@
+/*
+ * tlsdated-unittest.c - tlsdated unit tests
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include "src/test_harness.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+#include <event2/event.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+FIXTURE (tempdir)
+{
+ char path[PATH_MAX];
+};
+
+FIXTURE_SETUP (tempdir)
+{
+ char *p;
+ strncpy (self->path, "/tmp/tlsdated-unit-XXXXXX", sizeof (self->path));
+ p = mkdtemp (self->path);
+ ASSERT_NE (NULL, p);
+}
+
+FIXTURE_TEARDOWN(tempdir) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%s/load", self->path);
+ unlink(buf);
+ snprintf(buf, sizeof(buf), "%s/save", self->path);
+ unlink(buf);
+ ASSERT_EQ(0, rmdir(self->path));
+}
+
+int write_time (const char *path, time_t time)
+{
+ int fd = open (path, O_WRONLY | O_TRUNC | O_CREAT, 0600);
+ if (fd == -1)
+ return 1;
+ if (save_timestamp_to_fd (fd, time))
+ return 1;
+ if (write (fd, &time, sizeof (time)) != sizeof (time))
+ {
+ close (fd);
+ return 1;
+ }
+ return close (fd);
+}
+
+int read_time (const char *path, time_t* time)
+{
+ int fd = open (path, O_RDONLY);
+ if (fd == -1)
+ return 1;
+ if (read (fd, time, sizeof (*time)) != sizeof (*time))
+ {
+ close (fd);
+ return 1;
+ }
+ return close (fd);
+}
+
+TEST (sane_time)
+{
+ ASSERT_EQ (0, is_sane_time (0));
+ ASSERT_EQ (0, is_sane_time (INT_MAX));
+}
+
+TEST (sane_host_time)
+{
+ ASSERT_EQ (1, is_sane_time (time (NULL)));
+}
+
+TEST_F (tempdir, load_time)
+{
+ char buf[PATH_MAX];
+ time_t tm = 3;
+ time_t now = time (NULL);
+ snprintf (buf, sizeof (buf), "%s/load", self->path);
+ ASSERT_EQ (0, write_time (buf, 0));
+ ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
+ ASSERT_EQ (3, tm);
+ ASSERT_EQ (0, write_time (buf, INT_MAX));
+ ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
+ ASSERT_EQ (3, tm);
+ ASSERT_EQ (0, write_time (buf, now));
+ ASSERT_EQ (0, truncate (buf, 2));
+ ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
+ ASSERT_EQ (3, tm);
+ ASSERT_EQ (0, unlink (buf));
+ ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
+ ASSERT_EQ (3, tm);
+ ASSERT_EQ (0, write_time (buf, now));
+ ASSERT_EQ (0, load_disk_timestamp (buf, &tm));
+ ASSERT_EQ (now, tm);
+}
+
+
+TEST_F (tempdir, save_time)
+{
+ char buf[PATH_MAX];
+ time_t now = time (NULL);
+ time_t tm;
+ snprintf (buf, sizeof (buf), "%s/save", self->path);
+ ASSERT_EQ (0, write_time (buf, now));
+ ASSERT_EQ (0, read_time (buf, &tm));
+ EXPECT_EQ (now, tm);
+}
+
+FIXTURE (tlsdate)
+{
+ struct state state;
+ struct timeval timeout;
+};
+
+
+FIXTURE_SETUP (tlsdate)
+{
+ memset (self, 0, sizeof (*self));
+ /* TODO(wad) make this use the same function tlsdated uses. */
+ self->state.base = event_base_new();
+ set_conf_defaults (&self->state.opts);
+ ASSERT_NE (NULL, self->state.base);
+ event_base_priority_init (self->state.base, MAX_EVENT_PRIORITIES);
+ ASSERT_EQ (0, setup_sigchld_event (&self->state, 1));
+ self->state.events[E_TLSDATE] = event_new (self->state.base, -1, EV_TIMEOUT,
+ action_run_tlsdate, &self->state);
+ ASSERT_NE (NULL, self->state.events[E_TLSDATE]);
+ event_priority_set (self->state.events[E_TLSDATE], PRI_NET);
+ /* The timeout and fd will be filled in per-call. */
+ ASSERT_EQ (0, setup_tlsdate_status (&self->state));
+ self->timeout.tv_sec = 1;
+}
+
+FIXTURE_TEARDOWN (tlsdate)
+{
+ int i;
+ for (i = 0; i < E_MAX; ++i)
+ {
+ struct event *e = self->state.events[i];
+ if (e)
+ {
+ int fd = event_get_fd (e);
+ if (fd >= 0 && ! (event_get_events (e) & EV_SIGNAL))
+ close (fd);
+ event_free (e);
+ self->state.events[i] = NULL;
+ }
+ }
+ /* The other half was closed above. */
+ close (self->state.tlsdate_monitor_fd);
+ if (self->state.tlsdate_pid)
+ {
+ kill (self->state.tlsdate_pid, SIGKILL);
+ waitpid (self->state.tlsdate_pid, NULL, WNOHANG);
+ }
+ if (self->state.base)
+ event_base_free (self->state.base);
+}
+
+static int
+runner (FIXTURE_DATA (tlsdate) *self, time_t *newtime)
+{
+ if (newtime)
+ *newtime = 0;
+ trigger_event (&self->state, E_TLSDATE, 0);
+ event_base_loopexit (self->state.base, &self->timeout);
+ if (event_base_dispatch (self->state.base))
+ return -1;
+ if (self->state.last_time)
+ {
+ if (newtime)
+ *newtime = self->state.last_time;
+ return 0;
+ }
+ return 1;
+}
+
+TEST_F (tlsdate, runner_multi)
+{
+ struct source source =
+ {
+ .next = NULL,
+ .host = "host1",
+ .port = "port1",
+ .proxy = "proxy1"
+ };
+ char *args[] = { "/nonexistent", NULL, NULL };
+ extern char **environ;
+ self->state.opts.sources = &source;
+ self->state.opts.base_argv = args;
+ self->state.opts.subprocess_tries = 2;
+ self->state.opts.subprocess_wait_between_tries = 1;
+ self->state.opts.max_tries = 3;
+ self->state.envp = environ;
+ EXPECT_EQ (1, runner (self, NULL));
+ args[0] = "/bin/false";
+ self->state.tries = 0;
+ self->state.last_sync_type = SYNC_TYPE_NONE;
+ EXPECT_EQ (1, runner (self, NULL));
+ args[0] = "src/test/check-host-1";
+ self->state.tries = 0;
+ self->state.last_sync_type = SYNC_TYPE_NONE;
+ EXPECT_EQ (0, runner (self, NULL));
+ args[0] = "src/test/sleep-wrap";
+ args[1] = "3";
+ self->state.tries = 0;
+ self->state.last_sync_type = SYNC_TYPE_NONE;
+ EXPECT_EQ (0, runner (self, NULL));
+}
+
+TEST (jitter)
+{
+ int i = 0;
+ int r;
+ const int kBase = 100;
+ const int kJitter = 25;
+ int nonequal = 0;
+ for (i = 0; i < 1000; i++)
+ {
+ r = add_jitter (kBase, kJitter);
+ EXPECT_GE (r, kBase - kJitter);
+ EXPECT_LE (r, kBase + kJitter);
+ if (r != kBase)
+ nonequal++;
+ }
+ EXPECT_NE (nonequal, 0);
+}
+
+TEST_F (tlsdate, rotate_hosts)
+{
+ struct source s2 =
+ {
+ .next = NULL,
+ .host = "host2",
+ .port = "port2",
+ .proxy = "proxy2"
+ };
+ struct source s1 =
+ {
+ .next = &s2,
+ .host = "host1",
+ .port = "port1",
+ .proxy = "proxy1"
+ };
+ char *args[] = { "src/test/check-host-1", NULL };
+ extern char **environ;
+ self->state.envp = environ;
+ self->state.opts.sources = &s1;
+ self->state.opts.base_argv = args;
+ self->state.opts.subprocess_tries = 2;
+ self->state.opts.subprocess_wait_between_tries = 1;
+ self->state.opts.max_tries = 5;
+ self->timeout.tv_sec = 2;
+ EXPECT_EQ (0, runner (self, NULL));
+ self->state.tries = 0;
+ args[0] = "src/test/check-host-2";
+ self->state.last_sync_type = SYNC_TYPE_NONE;
+ EXPECT_EQ (0, runner (self, NULL));
+ self->state.tries = 0;
+ args[0] = "src/test/check-host-1";
+ self->state.last_sync_type = SYNC_TYPE_NONE;
+ EXPECT_EQ (0, runner (self, NULL));
+ self->state.tries = 0;
+ args[0] = "src/test/check-host-2";
+ self->state.last_sync_type = SYNC_TYPE_NONE;
+ EXPECT_EQ (0, runner (self, NULL));
+}
+
+TEST_F (tlsdate, proxy_override)
+{
+ struct source s1 =
+ {
+ .next = NULL,
+ .host = "host",
+ .port = "port",
+ .proxy = NULL,
+ };
+ char *args[] = { "src/test/proxy-override", NULL };
+ extern char **environ;
+ self->state.envp = environ;
+ self->state.opts.sources = &s1;
+ self->state.opts.base_argv = args;
+ self->state.opts.subprocess_tries = 2;
+ self->state.opts.subprocess_wait_between_tries = 1;
+ EXPECT_EQ (0, runner (self, NULL));
+ EXPECT_EQ (RECENT_COMPILE_DATE + 1, self->state.last_time);
+ s1.proxy = "socks5://bad.proxy";
+ self->state.tries = 0;
+ self->state.last_sync_type = SYNC_TYPE_NONE;
+ EXPECT_EQ (0, runner (self, NULL));
+ EXPECT_EQ (RECENT_COMPILE_DATE + 3, self->state.last_time);
+ self->state.opts.proxy = "socks5://good.proxy";
+ self->state.tries = 0;
+ self->state.last_sync_type = SYNC_TYPE_NONE;
+ EXPECT_EQ (0, runner (self, NULL));
+ EXPECT_EQ (RECENT_COMPILE_DATE + 2, self->state.last_time);
+}
+
+FIXTURE(mock_platform) {
+ struct platform platform;
+ struct platform *old_platform;
+};
+
+FIXTURE_SETUP(mock_platform) {
+ self->old_platform = platform;
+ self->platform.rtc_open = NULL;
+ self->platform.rtc_write = NULL;
+ self->platform.rtc_read = NULL;
+ self->platform.rtc_close = NULL;
+ platform = &self->platform;
+}
+
+FIXTURE_TEARDOWN(mock_platform) {
+ platform = self->old_platform;
+}
+
+/* TODO: leap_tests, time_setter tests. */
+
+TEST_HARNESS_MAIN
diff --git a/src/tlsdated.c b/src/tlsdated.c
new file mode 100644
index 0000000..0165b58
--- /dev/null
+++ b/src/tlsdated.c
@@ -0,0 +1,602 @@
+/*
+ * tlsdated.c - invoke tlsdate when necessary.
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * We invoke tlsdate once at system startup, then we start trying to invoke
+ * tlsdate when a new network route appears. We try a few times after each route
+ * comes up. As soon as we get a successful tlsdate run, we save that timestamp
+ * to disk, then linger to wait for system shutdown. At system shutdown
+ * (indicated by us getting SIGTERM), we save our timestamp to disk.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <grp.h> /* setgroups */
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/rtc.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/routeup.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+#include "src/dbus.h"
+#include "src/platform.h"
+
+const char *kCacheDir = DEFAULT_DAEMON_CACHEDIR;
+
+int
+is_sane_time (time_t ts)
+{
+ return ts > RECENT_COMPILE_DATE && ts < TLSDATED_MAX_DATE;
+}
+
+/*
+ * Load a time value out of the file named by path. Returns 0 if successful,
+ * -1 if not. The file contains the time in seconds since epoch in host byte
+ * order.
+ */
+int
+load_disk_timestamp (const char *path, time_t * t)
+{
+ int fd = platform->file_open (path, 0 /* RDONLY */, 1 /* CLOEXEC */);
+ time_t tmpt = 0;
+ if (fd < 0)
+ {
+ perror ("Can't open %s for reading", path);
+ return -1;
+ }
+ if (platform->file_read(fd, &tmpt, sizeof(tmpt)))
+ {
+ perror ("Can't read seconds from %s", path);
+ platform->file_close (fd);
+ return -1;
+ }
+ platform->file_close (fd);
+ if (!is_sane_time (tmpt))
+ {
+ error ("Disk timestamp is not sane: %ld", tmpt);
+ return -1;
+ }
+ *t = tmpt;
+ return 0;
+}
+
+
+void
+usage (const char *progn)
+{
+ printf ("Usage: %s [flags...] [--] [tlsdate command...]\n", progn);
+ printf (" -w don't set hwclock\n");
+ printf (" -p dry run (don't really set time)\n");
+ printf (" -r use stdin instead of netlink for routes\n");
+ printf (" -t <n> try n times to synchronize the time\n");
+ printf (" -d <n> delay n seconds between tries\n");
+ printf (" -T <n> give subprocess n chances to exit\n");
+ printf (" -D <n> delay n seconds between wait attempts\n");
+ printf (" -c <path> set the cache directory\n");
+ printf (" -a <n> run at most every n seconds in steady state\n");
+ printf (" -m <n> run at most once every n seconds in steady state\n");
+ printf (" -j <n> add up to n seconds jitter to steady state checks\n");
+ printf (" -l don't load disk timestamps\n");
+ printf (" -s don't save disk timestamps\n");
+ printf (" -U don't use DBus if supported\n");
+ printf (" -u <user> user to change to\n");
+ printf (" -g <grp> group to change to\n");
+ printf (" -v be verbose\n");
+ printf (" -b use verbose debugging\n");
+ printf (" -x <h> set proxy for subprocs to h\n");
+ printf (" -h this\n");
+}
+
+void
+set_conf_defaults (struct opts *opts)
+{
+ static char *kDefaultArgv[] =
+ {
+ (char *) DEFAULT_TLSDATE, (char *) "-H", (char *) DEFAULT_HOST, NULL
+ };
+ opts->user = UNPRIV_USER;
+ opts->group = UNPRIV_GROUP;
+ opts->max_tries = MAX_TRIES;
+ opts->min_steady_state_interval = STEADY_STATE_INTERVAL;
+ opts->wait_between_tries = WAIT_BETWEEN_TRIES;
+ opts->subprocess_tries = SUBPROCESS_TRIES;
+ opts->subprocess_wait_between_tries = SUBPROCESS_WAIT_BETWEEN_TRIES;
+ opts->steady_state_interval = STEADY_STATE_INTERVAL;
+ opts->continuity_interval = CONTINUITY_INTERVAL;
+ opts->base_path = kCacheDir;
+ opts->base_argv = kDefaultArgv;
+ opts->argv = NULL;
+ opts->should_dbus = 1;
+ opts->should_sync_hwclock = DEFAULT_SYNC_HWCLOCK;
+ opts->should_load_disk = DEFAULT_LOAD_FROM_DISK;
+ opts->should_save_disk = DEFAULT_SAVE_TO_DISK;
+ opts->should_netlink = DEFAULT_USE_NETLINK;
+ opts->dry_run = DEFAULT_DRY_RUN;
+ opts->jitter = 0;
+ opts->conf_file = NULL;
+ opts->sources = NULL;
+ opts->cur_source = NULL;
+ opts->proxy = NULL;
+ opts->leap = 0;
+}
+
+void
+parse_argv (struct opts *opts, int argc, char *argv[])
+{
+ int opt;
+ while ((opt = getopt (argc, argv, "hwrpt:d:T:D:c:a:lsvbm:j:f:x:Uu:g:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'w':
+ opts->should_sync_hwclock = 0;
+ break;
+ case 'r':
+ opts->should_netlink = 0;
+ break;
+ case 'U':
+ opts->should_dbus = 0;
+ break;
+ case 'p':
+ opts->dry_run = 1;
+ break;
+ case 't':
+ opts->max_tries = atoi (optarg);
+ break;
+ case 'd':
+ opts->wait_between_tries = atoi (optarg);
+ break;
+ case 'T':
+ opts->subprocess_tries = atoi (optarg);
+ break;
+ case 'D':
+ opts->subprocess_wait_between_tries = atoi (optarg);
+ break;
+ case 'c':
+ opts->base_path = optarg;
+ break;
+ case 'a':
+ opts->steady_state_interval = atoi (optarg);
+ break;
+ case 'l':
+ opts->should_load_disk = 0;
+ break;
+ case 's':
+ opts->should_save_disk = 0;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'b':
+ verbose_debug = 1;
+ break;
+ case 'm':
+ opts->min_steady_state_interval = atoi (optarg);
+ break;
+ case 'j':
+ opts->jitter = atoi (optarg);
+ break;
+ case 'f':
+ opts->conf_file = optarg;
+ break;
+ case 'x':
+ opts->proxy = optarg;
+ break;
+ case 'u':
+ opts->user = optarg;
+ break;
+ case 'g':
+ opts->group = optarg;
+ break;
+ case 'h':
+ default:
+ usage (argv[0]);
+ exit (1);
+ }
+ }
+ if (optind < argc)
+ opts->base_argv = argv + optind;
+ /* Validate arguments */
+}
+
+static
+void add_source_to_conf (struct opts *opts, char *host, char *port, char *proxy)
+{
+ struct source *s;
+ struct source *source = (struct source *) calloc (1, sizeof *source);
+ if (!source)
+ fatal ("out of memory for source");
+ source->host = strdup (host);
+ if (!source->host)
+ fatal ("out of memory for host");
+ source->port = strdup (port);
+ if (!source->port)
+ fatal ("out of memory for port");
+ if (proxy)
+ {
+ source->proxy = strdup (proxy);
+ if (!source->proxy)
+ fatal ("out of memory for proxy");
+ }
+ if (!opts->sources)
+ {
+ opts->sources = source;
+ source->id = 0;
+ }
+ else
+ {
+ for (s = opts->sources; s->next; s = s->next)
+ ;
+ source->id = s->id + 1;
+ s->next = source;
+ }
+}
+
+static struct conf_entry *
+parse_source (struct opts *opts, struct conf_entry *conf)
+{
+ char *host = NULL;
+ char *port = NULL;
+ char *proxy = NULL;
+ /* a source entry:
+ * source
+ * host <host>
+ * port <port>
+ * [proxy <proxy>]
+ * end
+ */
+ assert (!strcmp (conf->key, "source"));
+ conf = conf->next;
+ while (conf && strcmp (conf->key, "end"))
+ {
+ if (!strcmp (conf->key, "host"))
+ host = conf->value;
+ else if (!strcmp (conf->key, "port"))
+ port = conf->value;
+ else if (!strcmp (conf->key, "proxy"))
+ proxy = conf->value;
+ else
+ fatal ("malformed config: '%s' in source stanza", conf->key);
+ conf = conf->next;
+ }
+ if (!conf)
+ fatal ("unclosed source stanza");
+ if (!host || !port)
+ fatal ("incomplete source stanza (needs host, port)");
+ add_source_to_conf (opts, host, port, proxy);
+ return conf;
+}
+
+void
+load_conf (struct opts *opts)
+{
+ FILE *f;
+ struct conf_entry *conf, *e;
+ char *conf_file = opts->conf_file;
+ if (!opts->conf_file)
+ conf_file = (char *) DEFAULT_CONF_FILE;
+ f = fopen (conf_file, "r");
+ if (!f)
+ {
+ if (opts->conf_file)
+ {
+ pfatal ("can't open conf file '%s'", opts->conf_file);
+ }
+ else
+ {
+ pinfo ("can't open conf file '%s'", conf_file);
+ return;
+ }
+ }
+ conf = conf_parse (f);
+ if (!conf)
+ pfatal ("can't parse config file");
+
+ for (e = conf; e; e = e->next)
+ {
+ if (!strcmp (e->key, "max-tries") && e->value)
+ {
+ opts->max_tries = atoi (e->value);
+ }
+ else if (!strcmp (e->key, "min-steady-state-interval") && e->value)
+ {
+ opts->min_steady_state_interval = atoi (e->value);
+ }
+ else if (!strcmp (e->key, "wait-between-tries") && e->value)
+ {
+ opts->wait_between_tries = atoi (e->value);
+ }
+ else if (!strcmp (e->key, "subprocess-tries") && e->value)
+ {
+ opts->subprocess_tries = atoi (e->value);
+ }
+ else if (!strcmp (e->key, "subprocess-wait-between-tries") && e->value)
+ {
+ opts->subprocess_wait_between_tries = atoi (e->value);
+ }
+ else if (!strcmp (e->key, "steady-state-interval") && e->value)
+ {
+ opts->steady_state_interval = atoi (e->value);
+ }
+ else if (!strcmp (e->key, "base-path") && e->value)
+ {
+ opts->base_path = strdup (e->value);
+ if (!opts->base_path)
+ fatal ("out of memory for base path");
+ }
+ else if (!strcmp (e->key, "should-sync-hwclock"))
+ {
+ opts->should_sync_hwclock = e->value ? !strcmp (e->value, "yes") : 1;
+ }
+ else if (!strcmp (e->key, "should-load-disk"))
+ {
+ opts->should_load_disk = e->value ? !strcmp (e->value, "yes") : 1;
+ }
+ else if (!strcmp (e->key, "should-save-disk"))
+ {
+ opts->should_save_disk = e->value ? !strcmp (e->value, "yes") : 1;
+ }
+ else if (!strcmp (e->key, "should-netlink"))
+ {
+ opts->should_netlink = e->value ? !strcmp (e->value, "yes") : 1;
+ }
+ else if (!strcmp (e->key, "dry-run"))
+ {
+ opts->dry_run = e->value ? !strcmp (e->value, "yes") : 1;
+ }
+ else if (!strcmp (e->key, "jitter") && e->value)
+ {
+ opts->jitter = atoi (e->value);
+ }
+ else if (!strcmp (e->key, "verbose"))
+ {
+ verbose = e->value ? !strcmp (e->value, "yes") : 1;
+ }
+ else if (!strcmp (e->key, "source"))
+ {
+ e = parse_source (opts, e);
+ }
+ else if (!strcmp (e->key, "leap"))
+ {
+ opts->leap = e->value ? !strcmp (e->value, "yes") : 1;
+ }
+ }
+}
+
+void
+check_conf (struct state *state)
+{
+ struct opts *opts = &state->opts;
+ if (!opts->max_tries)
+ fatal ("-t argument must be nonzero");
+ if (!opts->wait_between_tries)
+ fatal ("-d argument must be nonzero");
+ if (!opts->steady_state_interval)
+ fatal ("-a argument must be nonzero");
+ if (snprintf (state->timestamp_path, sizeof (state->timestamp_path),
+ "%s/timestamp", opts->base_path) >= sizeof (state->timestamp_path))
+ fatal ("supplied base path is too long: '%s'", opts->base_path);
+ if (opts->jitter >= opts->steady_state_interval)
+ fatal ("jitter must be less than steady state interval (%d >= %d)",
+ opts->jitter, opts->steady_state_interval);
+}
+
+int
+cleanup_main (struct state *state)
+{
+ int i;
+ for (i = 0; i < E_MAX; ++i)
+ {
+ struct event *e = state->events[i];
+ if (e)
+ {
+ int fd = event_get_fd (e);
+ if (fd >= 0 && ! (event_get_events (e) & EV_SIGNAL))
+ close (fd);
+ event_free (e);
+ }
+ }
+ /* The other half was closed above. */
+ platform->file_close (state->tlsdate_monitor_fd);
+ if (state->tlsdate_pid)
+ {
+ platform->process_signal (state->tlsdate_pid, SIGKILL);
+ platform->process_wait (state->tlsdate_pid, NULL, 0 /* !forever */);
+ }
+ /* Best effort to tear it down if it is still alive. */
+ close(state->setter_notify_fd);
+ close(state->setter_save_fd);
+ if (state->setter_pid)
+ {
+ platform->process_signal (state->setter_pid, SIGKILL);
+ platform->process_wait (state->setter_pid, NULL, 0 /* !forever */);
+ }
+ /* TODO(wad) Add dbus_cleanup() */
+ if (state->base)
+ event_base_free (state->base);
+ memset(state, 0, sizeof(*state));
+ info ("tlsdated clean up finished; exiting!");
+ terminate_syslog ();
+ return 0;
+}
+
+#ifdef TLSDATED_MAIN
+int API
+main (int argc, char *argv[], char *envp[])
+{
+ initalize_syslog ();
+ struct state state;
+ /* TODO(wad) EVENT_BASE_FLAG_PRECISE_TIMER | EVENT_BASE_FLAG_PRECISE_TIMER */
+ struct event_base *base = event_base_new();
+ if (!base)
+ {
+ fatal ("could not allocated new event base");
+ }
+ /* Add three priority levels:
+ * 0 - time saving. Must be done before any other events are handled.
+ * 1 - network synchronization events
+ * 2 - any other events (wake, platform, etc)
+ */
+ event_base_priority_init (base, MAX_EVENT_PRIORITIES);
+ memset (&state, 0, sizeof (state));
+ set_conf_defaults (&state.opts);
+ parse_argv (&state.opts, argc, argv);
+ check_conf (&state);
+ load_conf (&state.opts);
+ check_conf (&state);
+ if (!state.opts.sources)
+ add_source_to_conf (&state.opts, DEFAULT_HOST, DEFAULT_PORT, DEFAULT_PROXY);
+ state.base = base;
+ state.envp = envp;
+ state.backoff = state.opts.wait_between_tries;
+ /* TODO(wad) move this into setup_time_setter */
+ /* grab a handle to /dev/rtc for time-setter. */
+ if (state.opts.should_sync_hwclock &&
+ platform->rtc_open(&state.hwclock))
+ {
+ pinfo ("can't open hwclock fd");
+ state.opts.should_sync_hwclock = 0;
+ }
+ /* install the SIGCHLD handler for the setter and tlsdate */
+ if (setup_sigchld_event (&state, 1))
+ {
+ error ("Failed to setup SIGCHLD event");
+ goto out;
+ }
+ /* fork off the privileged helper */
+ verb ("spawning time setting helper . . .");
+ if (setup_time_setter (&state))
+ {
+ error ("could not fork privileged coprocess");
+ goto out;
+ }
+ /* release the hwclock now that the time-setter is running. */
+ if (state.opts.should_sync_hwclock)
+ {
+ platform->rtc_close (&state.hwclock);
+ }
+ /* drop privileges before touching any untrusted data */
+ drop_privs_to (state.opts.user, state.opts.group);
+ /* register a signal handler to save time at shutdown */
+ if (state.opts.should_save_disk)
+ {
+ struct event *event = event_new (base, SIGTERM, EV_SIGNAL|EV_PERSIST,
+ action_sigterm, &state);
+ if (!event)
+ fatal ("Failed to create SIGTERM event");
+ event_priority_set (event, PRI_SAVE);
+ event_add (event, NULL);
+ }
+ if (state.opts.should_dbus && init_dbus (&state))
+ {
+ error ("Failed to initialize DBus");
+ goto out;
+ }
+ /* Register the tlsdate event before any listeners could show up. */
+ state.events[E_TLSDATE] = event_new (base, -1, EV_TIMEOUT,
+ action_run_tlsdate, &state);
+ if (!state.events[E_TLSDATE])
+ {
+ error ("Failed to create tlsdate event");
+ goto out;
+ }
+ event_priority_set (state.events[E_TLSDATE], PRI_NET);
+ /* The timeout and fd will be filled in per-call. */
+ if (setup_tlsdate_status (&state))
+ {
+ error ("Failed to create tlsdate status event");
+ goto out;
+ }
+ /* TODO(wad) Could use a timeout on this to catch setter death? */
+ /* EV_READ is for truncation/EPIPE notification */
+ state.events[E_SAVE] = event_new (base, state.setter_save_fd,
+ EV_READ|EV_WRITE, action_sync_and_save,
+ &state);
+ if (!state.events[E_SAVE])
+ {
+ error ("Failed to create sync & save event");
+ goto out;
+ }
+ event_priority_set (state.events[E_SAVE], PRI_SAVE);
+ /* Start by grabbing the system time. */
+ state.last_sync_type = SYNC_TYPE_RTC;
+ state.last_time = time (NULL);
+ /* If possible, grab disk time and check the two. */
+ if (state.opts.should_load_disk)
+ {
+ time_t disk_time = state.last_time;
+ if (!load_disk_timestamp (state.timestamp_path, &disk_time))
+ {
+ verb ("disk timestamp available: yes");
+ if (!is_sane_time (state.last_time) ||
+ state.last_time < disk_time)
+ {
+ state.last_sync_type = SYNC_TYPE_DISK;
+ state.last_time = disk_time;
+ }
+ }
+ else
+ {
+ verb ("disk timestamp available: no");
+ }
+ }
+ if (!is_sane_time (state.last_time))
+ {
+ state.last_sync_type = SYNC_TYPE_BUILD;
+ state.last_time = RECENT_COMPILE_DATE + 1;
+ }
+ /* Save and announce the initial time source. */
+ trigger_event (&state, E_SAVE, -1);
+ verb ("tlsdated parasitic time synchronization initialized");
+ info ("initial time sync type: %s", sync_type_str (state.last_sync_type));
+ /* Initialize platform specific loop behavior */
+ if (platform_init_cros (&state))
+ {
+ error ("Failed to initialize platform code");
+ goto out;
+ }
+ if (setup_event_route_up (&state))
+ {
+ error ("Failed to setup route up monitoring");
+ goto out;
+ }
+ if (setup_event_timer_sync (&state))
+ {
+ error ("Failed to setup a timer event");
+ goto out;
+ }
+ if (setup_event_timer_continuity (&state))
+ {
+ error ("Failed to setup continuity timer");
+ goto out;
+ }
+ /* Add a forced sync event to the event list. */
+ action_kickoff_time_sync (-1, EV_TIMEOUT, &state);
+ verb ("Entering dispatch . . .");
+ event_base_dispatch (base);
+ verb ("tlsdated event dispatch terminating gracefully");
+out:
+ return cleanup_main (&state);
+}
+#endif /* !TLSDATED_MAIN */
diff --git a/src/util-plan9.c b/src/util-plan9.c
new file mode 100644
index 0000000..77d2077
--- /dev/null
+++ b/src/util-plan9.c
@@ -0,0 +1,112 @@
+/*
+ * util.c - routeup/tlsdated utility functions
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <grp.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#if !_PLAN9_SOURCE
+#include <syslog.h>
+#endif
+#include <unistd.h>
+
+#include "src/util.h"
+
+/** helper function to print message and die */
+void
+die (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+/** helper function for 'verbose' output */
+void
+verb (const char *fmt, ...)
+{
+ va_list ap;
+
+ if (! verbose) return;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+#if !_PLAN9_SOURCE
+void API logat(int isverbose, const char *fmt, ...)
+{
+ if (isverbose && !verbose)
+ return;
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ va_start(ap, fmt);
+ vsyslog(LOG_INFO, fmt, ap);
+ va_end(ap);
+}
+#endif
+
+
+void
+drop_privs_to (const char *user, const char *group)
+{
+#if !_PLAN9_SOURCE
+
+ uid_t uid;
+ gid_t gid;
+ struct passwd *pw;
+ struct group *gr;
+
+ if (0 != getuid ())
+ return; /* not running as root to begin with; should (!) be harmless to continue
+ without dropping to 'nobody' (setting time will fail in the end) */
+ pw = getpwnam(user);
+ gr = getgrnam(group);
+ if (NULL == pw)
+ die ("Failed to obtain UID for `%s'\n", user);
+ if (NULL == gr)
+ die ("Failed to obtain GID for `%s'\n", group);
+ uid = pw->pw_uid;
+ if (0 == uid)
+ die ("UID for `%s' is 0, refusing to run SSL\n", user);
+ gid = pw->pw_gid;
+ if (0 == gid || 0 == gr->gr_gid)
+ die ("GID for `%s' is 0, refusing to run SSL\n", user);
+ if (pw->pw_gid != gr->gr_gid)
+ die ("GID for `%s' is not `%s' as expected, refusing to run SSL\n",
+ user, group);
+
+ if (0 != initgroups((const char *)user, gr->gr_gid))
+ die ("Unable to initgroups for `%s' in group `%s' as expected\n",
+ user, group);
+
+#ifdef HAVE_SETRESGID
+ if (0 != setresgid (gid, gid, gid))
+ die ("Failed to setresgid: %s\n", strerror (errno));
+#else
+ if (0 != (setgid (gid) | setegid (gid)))
+ die ("Failed to setgid: %s\n", strerror (errno));
+#endif
+#ifdef HAVE_SETRESUID
+ if (0 != setresuid (uid, uid, uid))
+ die ("Failed to setresuid: %s\n", strerror (errno));
+#else
+ if (0 != (setuid (uid) | seteuid (uid)))
+ die ("Failed to setuid: %s\n", strerror (errno));
+#endif
+#endif /* !_PLAN9_SOURCE */
+}
+
diff --git a/src/util-plan9.h b/src/util-plan9.h
new file mode 100644
index 0000000..7453235
--- /dev/null
+++ b/src/util-plan9.h
@@ -0,0 +1,41 @@
+/*
+ * util.h - routeup/tlsdated utility functions
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if _PLAN9_SOURCE
+#define API
+#else
+#define API __attribute__((visibility("default")))
+#endif
+
+extern int verbose;
+extern int verbose_debug;
+void die (const char *fmt, ...);
+void verb (const char *fmt, ...);
+extern void logat(int isverbose, const char *fmt, ...);
+
+#define info(fmt, ...) logat(1, fmt, ## __VA_ARGS__)
+#define pinfo(fmt, ...) logat(1, fmt ": %s", ## __VA_ARGS__, strerror(errno))
+#define error(fmt, ...) logat(0, fmt, ## __VA_ARGS__)
+#define perror(fmt, ...) logat(0, fmt ": %s", ## __VA_ARGS__, strerror(errno))
+#define fatal(fmt, ...) do { logat(0, fmt, ## __VA_ARGS__); exit(1); } while (0)
+#define pfatal(fmt, ...) do { \
+ logat(0, fmt ": %s", ## __VA_ARGS__, strerror(errno)); \
+ exit(1); \
+} while (0)
+
+static inline int min(int x, int y) { return x < y ? x : y; }
+
+void drop_privs_to (const char *user, const char *group);
+
+#endif /* !UTIL_H */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..6bb279c
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,439 @@
+/*
+ * util.c - routeup/tlsdated utility functions
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+#include "tlsdate.h"
+
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#ifdef HAVE_LINUX_RTC_H
+#include <linux/rtc.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef WITH_EVENTS
+#include <event2/event.h>
+#endif
+
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+#ifdef HAVE_SECCOMP_FILTER
+#include "src/seccomp.h"
+#endif
+
+#if defined(HAVE_STRUCT_RTC_TIME) && defined(RTC_SET_TIME) && defined(RTC_RD_TIME)
+#define ENABLE_RTC
+#endif
+
+const char *kTempSuffix = DEFAULT_DAEMON_TMPSUFFIX;
+
+/** helper function to print message and die */
+void
+die (const char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ fprintf (stderr, "\n");
+ va_end (ap);
+ exit (1);
+}
+
+/* Initalize syslog */
+void initalize_syslog (void)
+{
+ openlog ("tlsdated", LOG_PID, LOG_DAEMON);
+}
+
+/* Signal to syslog that we're finished logging */
+void terminate_syslog (void)
+{
+ closelog ();
+}
+
+/** helper function for 'verbose' output without syslog support */
+void
+verb_no_syslog (const char *fmt, ...)
+{
+ va_list ap;
+
+ if (! verbose ) return;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ fprintf (stderr, "\n");
+ va_end(ap);
+}
+
+/** helper function for 'verbose' output */
+void
+verb (const char *fmt, ...)
+{
+ va_list ap;
+
+ if (! verbose ) return;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ fprintf (stderr, "\n");
+ va_end(ap);
+ va_start(ap, fmt);
+ vsyslog (LOG_DEBUG, fmt, ap);
+ va_end(ap);
+}
+
+void API logat (int isverbose, const char *fmt, ...)
+{
+ va_list ap;
+ if (isverbose && !verbose)
+ return;
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ fprintf (stderr, "\n");
+ va_end (ap);
+ va_start (ap, fmt);
+ vsyslog (LOG_INFO, fmt, ap);
+ va_end (ap);
+}
+
+void no_new_privs(void)
+{
+#ifdef TARGET_OS_LINUX
+#ifdef HAVE_PRCTL // XXX: Make this specific to PR_SET_NO_NEW_PRIVS
+ // Check to see if we're already set PR_SET_NO_NEW_PRIVS
+ // This happens in tlsdated earlier than when tlsdate-helper drops
+ // privileges.
+ if (0 == prctl (PR_GET_NO_NEW_PRIVS)) {
+ // Remove the ability to regain privilegess
+ if (0 != prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+ die ("Failed to PR_SET_NO_NEW_PRIVS");
+ } else {
+ verb ("V: Parent process has already set PR_SET_NO_NEW_PRIVS");
+ }
+#else
+ verb ("V: we are unwilling to set PR_SET_NO_NEW_PRIVS");
+#endif
+#endif
+}
+
+void enable_seccomp(void)
+{
+#ifdef HAVE_SECCOMP_FILTER
+ int status;
+ prctl (PR_SET_NAME, "tlsdate seccomp");
+ verb ("V: seccomp support is enabled");
+ if (enable_setter_seccomp())
+ {
+ status = SETTER_NO_SBOX;
+ _exit (status);
+ }
+#else
+ verb ("V: seccomp support is disabled");
+#endif
+}
+
+void
+drop_privs_to (const char *user, const char *group)
+{
+ uid_t uid;
+ gid_t gid;
+ struct passwd *pw;
+ struct group *gr;
+
+ if (0 != getuid ())
+ return; /* not running as root to begin with; should (!) be harmless to continue
+ without dropping to 'nobody' (setting time will fail in the end) */
+ pw = getpwnam (user);
+ gr = getgrnam (group);
+ if (NULL == pw)
+ die ("Failed to obtain UID for `%s'\n", user);
+ if (NULL == gr)
+ die ("Failed to obtain GID for `%s'\n", group);
+ uid = pw->pw_uid;
+ if (0 == uid)
+ die ("UID for `%s' is 0, refusing to run SSL\n", user);
+ gid = pw->pw_gid;
+ if (0 == gid || 0 == gr->gr_gid)
+ die ("GID for `%s' is 0, refusing to run SSL\n", user);
+ if (pw->pw_gid != gr->gr_gid)
+ die ("GID for `%s' is not `%s' as expected, refusing to run SSL\n",
+ user, group);
+ if (0 != initgroups ( (const char *) user, gr->gr_gid))
+ die ("Unable to initgroups for `%s' in group `%s' as expected\n",
+ user, group);
+#ifdef HAVE_SETRESGID
+ if (0 != setresgid (gid, gid, gid))
+ die ("Failed to setresgid: %s\n", strerror (errno));
+#else
+ if (0 != (setgid (gid) | setegid (gid)))
+ die ("Failed to setgid: %s\n", strerror (errno));
+#endif
+#ifdef HAVE_SETRESUID
+ if (0 != setresuid (uid, uid, uid))
+ die ("Failed to setresuid: %s\n", strerror (errno));
+#else
+ if (0 != (setuid (uid) | seteuid (uid)))
+ die ("Failed to setuid: %s\n", strerror (errno));
+#endif
+}
+
+#ifdef ENABLE_RTC
+int rtc_open(struct rtc_handle *h)
+{
+ if (!h)
+ return -1;
+ h->fd = -1;
+ /* TODO: Use platform->file_open but drop NOFOLLOW? */
+ h->fd = open(DEFAULT_RTC_DEVICE, O_RDONLY);
+ if (h->fd < 0)
+ {
+ pinfo("can't open rtc");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Set the hardware clock referred to by fd (which should be a descriptor to
+ * some device that implements the interface documented in rtc(4)) to the system
+ * time. See hwclock(8) for details of why this is important. If we fail, we
+ * just return - there's nothing the caller can really do about a failure of
+ * this function except try later.
+ */
+int rtc_write(struct rtc_handle *handle, const struct timeval *tv)
+{
+ struct tm tmr;
+ struct tm *tm;
+ struct rtc_time rtctm;
+ int fd = handle->fd;
+
+ tm = gmtime_r (&tv->tv_sec, &tmr);
+
+ /* these structs are identical, but separately defined */
+ rtctm.tm_sec = tm->tm_sec;
+ rtctm.tm_min = tm->tm_min;
+ rtctm.tm_hour = tm->tm_hour;
+ rtctm.tm_mday = tm->tm_mday;
+ rtctm.tm_mon = tm->tm_mon;
+ rtctm.tm_year = tm->tm_year;
+ rtctm.tm_wday = tm->tm_wday;
+ rtctm.tm_yday = tm->tm_yday;
+ rtctm.tm_isdst = tm->tm_isdst;
+
+ if (ioctl (fd, RTC_SET_TIME, &rtctm))
+ {
+ pinfo ("ioctl(%d, RTC_SET_TIME, ...) failed", fd);
+ return 1;
+ }
+
+ info ("synced rtc to sysclock");
+ return 0;
+}
+
+int rtc_read(struct rtc_handle *handle, struct timeval *tv)
+{
+ struct tm tm;
+ struct rtc_time rtctm;
+ int fd = handle->fd;
+
+ if (ioctl (fd, RTC_RD_TIME, &rtctm))
+ {
+ pinfo ("ioctl(%d, RTC_RD_TIME, ...) failed", fd);
+ return 1;
+ }
+
+ tm.tm_sec = rtctm.tm_sec;
+ tm.tm_min = rtctm.tm_min;
+ tm.tm_hour = rtctm.tm_hour;
+ tm.tm_mday = rtctm.tm_mday;
+ tm.tm_mon = rtctm.tm_mon;
+ tm.tm_year = rtctm.tm_year;
+ tm.tm_wday = rtctm.tm_wday;
+ tm.tm_yday = rtctm.tm_yday;
+ tm.tm_isdst = rtctm.tm_isdst;
+
+ tv->tv_sec = mktime(&tm);
+ tv->tv_usec = 0;
+
+ return 0;
+}
+
+int rtc_close(struct rtc_handle *handle)
+{
+ struct rtc_handle *h = handle;
+ platform->file_close(h->fd);
+ h->fd = -1;
+ return 0;
+}
+#endif
+
+int file_write(int fd, void *buf, size_t sz)
+{
+ struct iovec iov[1];
+ ssize_t ret;
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sz;
+ ret = IGNORE_EINTR (pwritev (fd, iov, 1, 0));
+ if (ret != sz)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+int file_open(const char *path, int write, int cloexec)
+{
+ int fd;
+ int oflags = cloexec ? O_CLOEXEC : 0;
+ if (write)
+ {
+ int perms = S_IRUSR | S_IWUSR;
+ oflags |= O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC;
+ /* Rely on atomic write calls rather than rename() calls. */
+ fd = open(path, oflags, perms);
+ }
+ else
+ {
+ oflags |= O_RDONLY | O_NOFOLLOW;
+ fd = open(path, oflags);
+ }
+ if (fd < 0)
+ {
+ pinfo("open(%s) failed", path);
+ return -1;
+ }
+ return fd;
+}
+
+int file_close(int fd)
+{
+ return close(fd);
+}
+
+int file_read(int fd, void *buf, size_t sz)
+{
+ struct iovec iov[1];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sz;
+ if (preadv (fd, iov, 1, 0) != sz)
+ {
+ /* Returns -1 on read failure */
+ return -1;
+ }
+ /* Returns 0 on a successful buffer fill. */
+ return 0;
+}
+
+int time_get(struct timeval *tv)
+{
+ return gettimeofday(tv, NULL);
+}
+
+int pgrp_enter(void)
+{
+ return setpgid(0, 0);
+}
+
+int pgrp_kill(void)
+{
+ pid_t grp = getpgrp();
+ return kill(-grp, SIGKILL);
+}
+
+int process_signal(pid_t pid, int signal)
+{
+ return kill (pid, signal);
+}
+
+pid_t process_wait(pid_t pid, int *status, int forever)
+{
+ int flag = forever ? 0 : WNOHANG;
+ return waitpid (pid, status, flag);
+}
+
+static struct platform default_platform = {
+#ifdef ENABLE_RTC
+ .rtc_open = rtc_open,
+ .rtc_write = rtc_write,
+ .rtc_read = rtc_read,
+ .rtc_close = rtc_close,
+#endif
+
+ .file_open = file_open,
+ .file_close = file_close,
+ .file_write = file_write,
+ .file_read = file_read,
+
+ .time_get = time_get,
+
+ .pgrp_enter = pgrp_enter,
+ .pgrp_kill = pgrp_kill,
+
+ .process_signal = process_signal,
+ .process_wait = process_wait
+};
+
+struct platform *platform = &default_platform;
+
+/* TODO(wad) rename to schedule_event */
+void
+trigger_event (struct state *state, enum event_id_t id, int sec)
+{
+#ifdef WITH_EVENTS
+ struct event *e = state->events[id];
+ struct timeval delay = { sec, 0 };
+ /* Fallthrough to tlsdate if there is no resolver. */
+ if (!e && id == E_RESOLVER)
+ e = state->events[E_TLSDATE];
+ if (!e)
+ {
+ info ("trigger_event with NULL |e|. I hope this is a test!");
+ return;
+ }
+ if (event_pending (e, EV_READ|EV_WRITE|EV_TIMEOUT|EV_SIGNAL, NULL))
+ event_del (e);
+ if (sec >= 0)
+ event_add (e, &delay);
+ else /* Note! This will not fire a TIMEOUT event. */
+ event_add (e, NULL);
+#endif
+}
+
+const char *
+sync_type_str (int sync_type)
+{
+ switch (sync_type)
+ {
+ case SYNC_TYPE_NONE:
+ return "none";
+ case SYNC_TYPE_BUILD:
+ return "build-timestamp";
+ case SYNC_TYPE_DISK:
+ return "disk-timestamp";
+ case SYNC_TYPE_RTC:
+ return "system-clock";
+ case SYNC_TYPE_PLATFORM:
+ return "platform-feature";
+ case SYNC_TYPE_NET:
+ return "network";
+ default:
+ return "error";
+ }
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..eaceeeb
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,97 @@
+/*
+ * util.h - routeup/tlsdated utility functions
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_PRCTL
+#include <sys/prctl.h>
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+#endif
+#ifndef PR_GET_NO_NEW_PRIVS
+# define PR_GET_NO_NEW_PRIVS 39
+#endif
+#endif
+
+#include "src/rtc.h"
+
+#ifdef TARGET_OS_HAIKU
+#include <stdarg.h>
+#endif
+
+#define API __attribute__((visibility("default")))
+
+extern const char *kTempSuffix;
+#define IGNORE_EINTR(expr) ({ \
+ typeof(expr) _r; \
+ while ((_r = (expr)) == -1 && errno == EINTR); \
+ _r; \
+})
+
+extern int verbose;
+extern int verbose_debug;
+void initalize_syslog (void);
+void terminate_syslog (void);
+void die (const char *fmt, ...);
+void verb (const char *fmt, ...);
+extern void logat (int isverbose, const char *fmt, ...);
+
+#define verb_debug debug
+#define debug(fmt, ...) if (verbose_debug) logat(1, fmt, ## __VA_ARGS__)
+#define info(fmt, ...) logat(0, fmt, ## __VA_ARGS__)
+#define pinfo(fmt, ...) logat(1, fmt ": %s", ## __VA_ARGS__, strerror(errno))
+#define error(fmt, ...) logat(0, fmt, ## __VA_ARGS__)
+#define perror(fmt, ...) logat(0, fmt ": %s", ## __VA_ARGS__, strerror(errno))
+#define fatal(fmt, ...) do { logat(0, fmt, ## __VA_ARGS__); exit(1); } while (0)
+#define pfatal(fmt, ...) do { \
+ logat(0, fmt ": %s", ## __VA_ARGS__, strerror(errno)); \
+ exit(1); \
+} while (0)
+
+static inline int min (int x, int y)
+{
+ return x < y ? x : y;
+}
+
+void drop_privs_to (const char *user, const char *group);
+void no_new_privs (void);
+const char *sync_type_str (int sync_type);
+
+struct state;
+enum event_id_t;
+void trigger_event (struct state *state, enum event_id_t e, int sec);
+
+struct platform {
+ int (*rtc_open)(struct rtc_handle *);
+ int (*rtc_write)(struct rtc_handle *, const struct timeval *tv);
+ int (*rtc_read)(struct rtc_handle *, struct timeval *tv);
+ int (*rtc_close)(struct rtc_handle *);
+
+ int (*file_open)(const char *path, int write, int cloexec);
+ int (*file_close)(int fd);
+ /* Atomic file write and read */
+ int (*file_write)(int fd, void *buf, size_t sz);
+ int (*file_read)(int fd, void *buf, size_t sz);
+
+ int (*time_get)(struct timeval *tv);
+
+ int (*pgrp_enter)(void);
+ int (*pgrp_kill)(void);
+
+ int (*process_signal)(pid_t pid, int sig);
+ int (*process_wait)(pid_t pid, int *status, int timeout);
+};
+
+extern struct platform *platform;
+
+#endif /* !UTIL_H */
diff --git a/src/visibility.h b/src/visibility.h
new file mode 100644
index 0000000..b9452f1
--- /dev/null
+++ b/src/visibility.h
@@ -0,0 +1,75 @@
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Copyright (C) 2012 Brian Aker, brian@tangent.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#if defined(BUILDING_TLSDATE)
+# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
+# define TLSDATE_API __attribute__ ((visibility("default")))
+# define TLSDATE_LOCAL __attribute__ ((visibility("default")))
+# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+# define TLSDATE_API __global
+# define TLSDATE_LOCAL __global
+# elif defined(_MSC_VER)
+# define TLSDATE_API extern __declspec(dllexport)
+# define TLSDATE_LOCAL extern __declspec(dllexport)
+# else
+# define TLSDATE_API
+# define TLSDATE_LOCAL
+# endif
+#else
+# if defined(BUILDING_TLSDATE)
+# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
+# define TLSDATE_API __attribute__ ((visibility("default")))
+# define TLSDATE_LOCAL __attribute__ ((visibility("hidden")))
+# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+# define TLSDATE_API __global
+# define TLSDATE_LOCAL __hidden
+# elif defined(_MSC_VER)
+# define TLSDATE_API extern __declspec(dllexport)
+# define TLSDATE_LOCAL
+# else
+# define TLSDATE_API
+# define TLSDATE_LOCAL
+# endif /* defined(HAVE_VISIBILITY) */
+# else /* defined(BUILDING_TLSDATE) */
+# if defined(_MSC_VER)
+# define TLSDATE_API extern __declspec(dllimport)
+# define TLSDATE_LOCAL
+# else
+# define TLSDATE_API
+# define TLSDATE_LOCAL
+# endif /* defined(_MSC_VER) */
+# endif /* defined(BUILDING_TLSDATE) */
+#endif /* defined(BUILDING_TLSDATEINTERNAL) */
diff --git a/systemd/tlsdated.service b/systemd/tlsdated.service
new file mode 100644
index 0000000..5515a8e
--- /dev/null
+++ b/systemd/tlsdated.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Secure parasitic time daemon
+After=network.target
+
+[Service]
+Type=simple
+EnvironmentFile=/etc/default/tlsdated
+ExecStart=/usr/sbin/tlsdated ${DAEMON_OPTS}
+ExecReload=/bin/kill -HUP ${MAINPID}
+ExecStop=/bin/kill -INT ${MAINPID}
diff --git a/test.conf b/test.conf
new file mode 100644
index 0000000..96827ef
--- /dev/null
+++ b/test.conf
@@ -0,0 +1,2 @@
+min-steady-state-interval 0
+wait-between-tries 1
diff --git a/tests/README b/tests/README
new file mode 100644
index 0000000..e0c0e00
--- /dev/null
+++ b/tests/README
@@ -0,0 +1 @@
+Integration tests for tlsdate/tlsdated.
diff --git a/tests/common.sh b/tests/common.sh
new file mode 100644
index 0000000..9e488db
--- /dev/null
+++ b/tests/common.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+kill_tlsdated() {
+ kill -TERM $PPID
+}
+
+result_passed() {
+ res=$(cat "$(mydir)"/"result")
+ if [ $res = "ok" ]; then
+ return 0
+ fi
+ return 1
+}
+
+check_err() {
+ grep -q "$1" "$(mydir)"/"run-err"
+}
+
+passed_if_timed_out() {
+ echo "ok" > "$(mydir)"/"result"
+}
+
+passed() {
+ echo "ok" > "$(mydir)"/"result"
+ kill_tlsdated
+}
+
+failed() {
+ echo "failed" > "$(mydir)"/"result"
+ kill_tlsdated
+}
+
+mydir() {
+ echo "$(dirname "$0")"
+}
+
+counter() {
+ cat "$(mydir)"/"$1"
+}
+
+inc_counter() {
+ c=$(counter "$1")
+ echo $((c + 1)) >"$(mydir)"/"$1"
+}
+
+reset_counter() {
+ echo 0 > "$(mydir)"/"$1"
+}
+
+reset_time() {
+ date +%s > "$(mydir)"/"$1"
+}
+
+emit_time() {
+ src/test/emit `cat "$(mydir)"/"$1"`
+}
diff --git a/tests/run-idle/output b/tests/run-idle/output
new file mode 100644
index 0000000..9766475
--- /dev/null
+++ b/tests/run-idle/output
@@ -0,0 +1 @@
+ok
diff --git a/tests/run-idle/setup b/tests/run-idle/setup
new file mode 100755
index 0000000..bd12ed6
--- /dev/null
+++ b/tests/run-idle/setup
@@ -0,0 +1,5 @@
+#!/bin/sh
+. "$(dirname "$0")"/../common.sh
+
+reset_time "timestamp"
+reset_counter "runs"
diff --git a/tests/run-idle/subproc.sh b/tests/run-idle/subproc.sh
new file mode 100755
index 0000000..f01a814
--- /dev/null
+++ b/tests/run-idle/subproc.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+. "$(dirname $0)"/../common.sh
+
+inc_counter "runs"
+c=$(counter "runs")
+[ $c -eq 3 ] && passed
+
+# Bump it three seconds to overcome the steady state interval.
+inc_counter "timestamp"
+inc_counter "timestamp"
+inc_counter "timestamp"
+emit_time "timestamp"
diff --git a/tests/run-idle/teardown b/tests/run-idle/teardown
new file mode 100644
index 0000000..b153b10
--- /dev/null
+++ b/tests/run-idle/teardown
@@ -0,0 +1,15 @@
+#!/bin/sh
+. "$(dirname "$0")"/../common.sh
+
+reset_counter "runs"
+# If the run count passed, then make sure the
+# time was being set and it wasn't error calls.
+if result_passed; then
+ if check_err 'time set from the network'; then
+ passed
+ else
+ failed
+ fi
+fi
+
+
diff --git a/tests/run-idle/test.conf b/tests/run-idle/test.conf
new file mode 100644
index 0000000..c97ac9b
--- /dev/null
+++ b/tests/run-idle/test.conf
@@ -0,0 +1,4 @@
+min-steady-state-interval 0
+steady-state-interval 1
+subprocess-tries 1
+subprocess-wait-between-tries 2
diff --git a/tests/run-once/output b/tests/run-once/output
new file mode 100644
index 0000000..9766475
--- /dev/null
+++ b/tests/run-once/output
@@ -0,0 +1 @@
+ok
diff --git a/tests/run-once/run-error b/tests/run-once/run-error
new file mode 100644
index 0000000..f84e1cf
--- /dev/null
+++ b/tests/run-once/run-error
@@ -0,0 +1 @@
+Killed
diff --git a/tests/run-once/subproc.sh b/tests/run-once/subproc.sh
new file mode 100755
index 0000000..5bf92e1
--- /dev/null
+++ b/tests/run-once/subproc.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+. "$(dirname $0)"/../common.sh
+passed
diff --git a/tests/run-routeup/input.sh b/tests/run-routeup/input.sh
new file mode 100755
index 0000000..fd33215
--- /dev/null
+++ b/tests/run-routeup/input.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+# Wake up from stdin twice.
+c=0
+while [ $c -lt 120 ]; do
+ echo
+ sleep 0.2
+ c=$((c+1))
+done
diff --git a/tests/run-routeup/output b/tests/run-routeup/output
new file mode 100644
index 0000000..9766475
--- /dev/null
+++ b/tests/run-routeup/output
@@ -0,0 +1 @@
+ok
diff --git a/tests/run-routeup/setup b/tests/run-routeup/setup
new file mode 100755
index 0000000..c4afd68
--- /dev/null
+++ b/tests/run-routeup/setup
@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")"/../common.sh
+
+reset_counter "runs"
diff --git a/tests/run-routeup/subproc.sh b/tests/run-routeup/subproc.sh
new file mode 100755
index 0000000..18bb5c9
--- /dev/null
+++ b/tests/run-routeup/subproc.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+. "$(dirname $0)"/../common.sh
+
+inc_counter "runs"
+c=$(counter "runs")
+[ $c -eq 2 ] && passed
+
+# Always emit a bogus time so that stdin retriggers.
+src/test/emit "0"
diff --git a/tests/run-routeup/teardown b/tests/run-routeup/teardown
new file mode 100644
index 0000000..c4afd68
--- /dev/null
+++ b/tests/run-routeup/teardown
@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")"/../common.sh
+
+reset_counter "runs"
diff --git a/tests/run-routeup/test.conf b/tests/run-routeup/test.conf
new file mode 100644
index 0000000..14a7747
--- /dev/null
+++ b/tests/run-routeup/test.conf
@@ -0,0 +1,4 @@
+# Don't let steady state trigger the next call.
+min-steady-state-interval 10
+steady-state-interval 30
+wait-between-tries 1
diff --git a/tests/subproc-retry/output b/tests/subproc-retry/output
new file mode 100644
index 0000000..0dae225
--- /dev/null
+++ b/tests/subproc-retry/output
@@ -0,0 +1,3 @@
+dying
+dying
+ok
diff --git a/tests/subproc-retry/setup b/tests/subproc-retry/setup
new file mode 100755
index 0000000..c4afd68
--- /dev/null
+++ b/tests/subproc-retry/setup
@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")"/../common.sh
+
+reset_counter "runs"
diff --git a/tests/subproc-retry/subproc.sh b/tests/subproc-retry/subproc.sh
new file mode 100755
index 0000000..b3fded7
--- /dev/null
+++ b/tests/subproc-retry/subproc.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Die on the first three attempts.
+. "$(dirname $0)"/../common.sh
+
+inc_counter "runs"
+if [ $(counter "runs") -lt 3 ]; then
+ exit 1
+fi
+passed
diff --git a/tests/subproc-retry/teardown b/tests/subproc-retry/teardown
new file mode 100644
index 0000000..c4afd68
--- /dev/null
+++ b/tests/subproc-retry/teardown
@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")"/../common.sh
+
+reset_counter "runs"
diff --git a/tests/wait-idle/output b/tests/wait-idle/output
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/wait-idle/output
diff --git a/tests/wait-idle/setup b/tests/wait-idle/setup
new file mode 100755
index 0000000..bd12ed6
--- /dev/null
+++ b/tests/wait-idle/setup
@@ -0,0 +1,5 @@
+#!/bin/sh
+. "$(dirname "$0")"/../common.sh
+
+reset_time "timestamp"
+reset_counter "runs"
diff --git a/tests/wait-idle/subproc.sh b/tests/wait-idle/subproc.sh
new file mode 100755
index 0000000..2994a5c
--- /dev/null
+++ b/tests/wait-idle/subproc.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Make sure that a longer steady state after a successful run
+# doesn't call again too soon.
+. "$(dirname $0)"/../common.sh
+
+emit_time "timestamp"
+# This one expects a timeout to end it.
+passed_if_timed_out
+
+inc_counter "runs"
+c=$(counter "runs")
+[ $c -eq 2 ] && failed
+
diff --git a/tlsdate-brew-formula.rb b/tlsdate-brew-formula.rb
new file mode 100644
index 0000000..5ed9bf3
--- /dev/null
+++ b/tlsdate-brew-formula.rb
@@ -0,0 +1,27 @@
+require 'formula'
+
+class Tlsdate < Formula
+ homepage 'https://www.github.com/ioerror/tlsdate/'
+ url 'https://nodeload.github.com/ioerror/tlsdate/tar.gz/master'
+ # This hash will never be correct until we put a tagged version into master
+ # update accordingly until we do a proper release that supports OS X
+ sha1 '2e818eb327af74c6a6c86a8c8b3911e20be9bc0f'
+ version '0.0.6'
+
+ depends_on 'autoconf' => :build
+ depends_on 'automake' => :build
+ depends_on 'libtool' => :build
+ depends_on 'pkg-config' => :build
+
+ def install
+ system "./autogen.sh"
+ system "./configure", "--disable-debug", "--disable-dependency-tracking",
+ "--prefix=#{prefix}"
+ system "make"
+ system "make install"
+ end
+
+ def test
+ system "tlsdate -v -n"
+ end
+end
diff --git a/tlsdate-seccomp-amd64.policy b/tlsdate-seccomp-amd64.policy
new file mode 100644
index 0000000..d22afdc
--- /dev/null
+++ b/tlsdate-seccomp-amd64.policy
@@ -0,0 +1,48 @@
+mmap: 1
+open: 1
+read: 1
+close: 1
+fstat: 1
+mprotect: 1
+munmap: 1
+stat: 1
+write: 1
+lseek: 1
+brk: 1
+fcntl: 1
+execve: 1
+sendto: 1
+# Allow domain == PF_FILE || domain == PF_INET || domain == PF_NETLINK
+socket: arg0 == 1 || arg0 == 2 || arg0 == 16
+connect: 1
+poll: 1
+access: 1
+arch_prctl: 1
+wait4: 1
+rt_sigaction: 1
+exit_group: 1
+rt_sigprocmask: 1
+clone: 1
+# Allow request == RTC_SET_TIME || request == FIONREAD
+ioctl: arg1 == 0x4024700a || arg1 == 0x541b
+getuid: 1
+exit: 1
+rt_sigreturn: 1
+rename: 1
+select: 1
+setgid: 1
+settimeofday: 1
+restart_syscall: 1
+setresgid: 1
+setgroups: 1
+setsockopt: 1
+bind: 1
+recvfrom: 1
+setresuid: 1
+nanosleep: 1
+clock_gettime: 1
+clock_settime: 1
+futex: 1
+getrlimit: 1
+set_robust_list: 1
+set_tid_address: 1
diff --git a/tlsdate-seccomp-arm.policy b/tlsdate-seccomp-arm.policy
new file mode 100644
index 0000000..2d31d89
--- /dev/null
+++ b/tlsdate-seccomp-arm.policy
@@ -0,0 +1,50 @@
+open: 1
+read: 1
+mmap2: 1
+stat64: 1
+close: 1
+fstat64: 1
+_newselect: 1
+mprotect: 1
+munmap: 1
+gettimeofday: 1
+_llseek: 1
+write: 1
+rt_sigprocmask: 1
+brk: 1
+execve: 1
+fcntl64: 1
+rt_sigaction: 1
+send: 1
+poll: 1
+# Allow domain == PF_FILE || domain == PF_INET || domain == PF_NETLINK
+socket: arg0 == 1 || arg0 == 2 || arg0 == 16
+uname: 1
+connect: 1
+access: 1
+ARM_set_tls: 1
+wait4: 1
+exit_group: 1
+getuid32: 1
+clone: 1
+# Allow request == RTC_SET_TIME || request == FIONREAD
+ioctl: arg1 == 0x4024700a || arg1 == 0x541b
+setgid32: 1
+recvfrom: 1
+setresuid32: 1
+setgroups32: 1
+settimeofday: 1
+restart_syscall: 1
+setsockopt: 1
+setresgid32: 1
+nanosleep: 1
+exit: 1
+rt_sigreturn: 1
+rename: 1
+bind: 1
+clock_gettime: 1
+clock_settime: 1
+futex: 1
+ugetrlimit: 1
+set_robust_list: 1
+set_tid_address: 1
diff --git a/tlsdate-seccomp-x86.policy b/tlsdate-seccomp-x86.policy
new file mode 100644
index 0000000..da790c9
--- /dev/null
+++ b/tlsdate-seccomp-x86.policy
@@ -0,0 +1,47 @@
+open: 1
+mmap2: 1
+read: 1
+close: 1
+fstat64: 1
+stat64: 1
+munmap: 1
+mprotect: 1
+time: 1
+socketcall: 1
+_llseek: 1
+brk: 1
+write: 1
+execve: 1
+fcntl64: 1
+gettimeofday: 1
+poll: 1
+access: 1
+set_thread_area: 1
+waitpid: 1
+exit_group: 1
+rt_sigprocmask: 1
+getuid32: 1
+clone: 1
+rt_sigaction: 1
+# Allow request == RTC_SET_TIME || request == FIONREAD
+ioctl: arg1 == 0x4024700a || arg1 == 0x541b
+setgid32: 1
+setgroups32: 1
+setresuid32: 1
+settimeofday: 1
+restart_syscall: 1
+setresgid32: 1
+nanosleep: 1
+exit: 1
+rt_sigreturn: 1
+rename: 1
+select: 1
+_newselect: 1
+clock_gettime: 1
+clock_settime: 1
+futex: 1
+getrlimit: 1
+ugetrlimit: 1
+set_robust_list: 1
+set_tid_address: 1
+uname: 1