[med-svn] [r-cran-openssl] 06/08: New upstream version 0.9.6
Andreas Tille
tille at debian.org
Tue Oct 10 17:07:06 UTC 2017
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository r-cran-openssl.
commit 6dc69cb718ea74a04528c621c26659fcfc0d34df
Author: Andreas Tille <tille at debian.org>
Date: Tue Oct 10 19:04:39 2017 +0200
New upstream version 0.9.6
---
DESCRIPTION | 31 +
LICENSE | 2 +
MD5 | 181 +
NAMESPACE | 184 +
NEWS | 71 +
R/aes.R | 98 +
R/askpass.R | 12 +
R/base.R | 110 +
R/base64.R | 35 +
R/bignum.R | 189 +
R/build.R | 24 +
R/cert.R | 84 +
R/diffie.R | 37 +
R/envelope.R | 49 +
R/hash.R | 252 ++
R/info.R | 10 +
R/keygen.R | 39 +
R/list.R | 43 +
R/mykey.R | 40 +
R/openssh.R | 140 +
R/openssl.R | 20 +
R/pkcs12.R | 100 +
R/rand.R | 47 +
R/read.R | 270 ++
R/rsa.R | 46 +
R/signing.R | 63 +
R/ssh2.R | 93 +
R/stream.R | 36 +
R/write.R | 65 +
R/writessh.R | 22 +
build/vignette.rds | Bin 0 -> 355 bytes
cleanup | 2 +
configure | 85 +
configure.win | 0
debian/README.test | 9 -
debian/changelog | 29 -
debian/clean | 1 -
debian/compat | 1 -
debian/control | 32 -
debian/copyright | 32 -
debian/docs | 3 -
debian/rules | 4 -
debian/source/format | 1 -
debian/tests/control | 3 -
debian/tests/run-unit-test | 12 -
debian/watch | 3 -
inst/cacert.pem | 4036 ++++++++++++++++++++
inst/doc/bignum.R | 52 +
inst/doc/bignum.Rmd | 111 +
inst/doc/bignum.html | 241 ++
inst/doc/crypto_hashing.R | 30 +
inst/doc/crypto_hashing.Rmd | 58 +
inst/doc/crypto_hashing.html | 191 +
inst/doc/keys.R | 38 +
inst/doc/keys.Rmd | 99 +
inst/doc/keys.html | 242 ++
inst/doc/secure_rng.R | 28 +
inst/doc/secure_rng.Rmd | 59 +
inst/doc/secure_rng.html | 183 +
man/aes_cbc.Rd | 56 +
man/askpass.Rd | 17 +
man/base64_encode.Rd | 29 +
man/bignum.Rd | 50 +
man/certificates.Rd | 49 +
man/ec_dh.Rd | 43 +
man/encrypt_envelope.Rd | 53 +
man/fingerprint.Rd | 33 +
man/hash.Rd | 108 +
man/keygen.Rd | 35 +
man/my_key.Rd | 34 +
man/openssl.Rd | 27 +
man/openssl_config.Rd | 12 +
man/pkcs12.Rd | 55 +
man/rand_bytes.Rd | 44 +
man/read_key.Rd | 71 +
man/rsa_encrypt.Rd | 48 +
man/signatures.Rd | 51 +
man/write_pem.Rd | 39 +
src/Makevars.in | 7 +
src/Makevars.win | 11 +
src/aes.c | 61 +
src/base64.c | 55 +
src/bignum.c | 173 +
src/cert.c | 149 +
src/compatibility.c | 75 +
src/compatibility.h | 37 +
src/diffie.c | 39 +
src/envelope.c | 96 +
src/error.c | 15 +
src/hash.c | 74 +
src/info.c | 15 +
src/keygen.c | 72 +
src/keys.c | 142 +
src/onload.c | 29 +
src/openssh.c | 289 ++
src/password.c | 40 +
src/pem.c | 90 +
src/pkcs12.c | 122 +
src/pkcs7.c | 107 +
src/rand.c | 17 +
src/rsa.c | 33 +
src/signing.c | 68 +
src/ssl.c | 152 +
src/stream.c | 103 +
src/utils.h | 5 +
src/win32/ipv6.c | 59 +
src/write.c | 51 +
tests/certigo/example-elliptic-sha1.crt | 16 +
tests/certigo/example-elliptic-sha1.key | 10 +
tests/certigo/example-elliptic-sha1.p12 | Bin 0 -> 1391 bytes
tests/certigo/example-elliptic-sha1.p7b | 17 +
tests/certigo/example-leaf.crt | 21 +
tests/certigo/example-leaf.p12 | Bin 0 -> 2582 bytes
tests/certigo/example-leaf.p7b | 22 +
tests/certigo/example-root.crt | 20 +
tests/certigo/example-root.p12 | Bin 0 -> 2542 bytes
tests/certigo/example-root.p7b | 21 +
tests/google.dk/generate.bash | 28 +
.../wildcard-google.dk-chain-password.p12 | Bin 0 -> 2704 bytes
tests/google.dk/wildcard-google.dk-chain.p12 | Bin 0 -> 2704 bytes
tests/google.dk/wildcard-google.dk-chain.pem | 57 +
tests/google.dk/wildcard-google.dk-leaf.crt | Bin 0 -> 905 bytes
tests/google.dk/wildcard-google.dk-leaf.notAfter | 1 +
tests/google.dk/wildcard-google.dk-leaf.notBefore | 1 +
tests/google.dk/wildcard-google.dk-leaf.sha1 | 1 +
tests/google.dk/wildcard-google.dk-leaf.sha256 | 1 +
tests/keys/authorized_keys | 4 +
tests/keys/blabla.pem | 12 +
tests/keys/fingerprints.txt | 17 +
tests/keys/id_dsa | 12 +
tests/keys/id_dsa.pem | 12 +
tests/keys/id_dsa.pub | 1 +
tests/keys/id_dsa.pw | 15 +
tests/keys/id_ecdsa | 5 +
tests/keys/id_ecdsa.pem | 4 +
tests/keys/id_ecdsa.pub | 1 +
tests/keys/id_ecdsa.pw | 8 +
tests/keys/id_ecdsa384 | 6 +
tests/keys/id_ecdsa384.pem | 5 +
tests/keys/id_ecdsa384.pub | 1 +
tests/keys/id_ecdsa384.pw | 9 +
tests/keys/id_ecdsa521 | 7 +
tests/keys/id_ecdsa521.pem | 6 +
tests/keys/id_ecdsa521.pub | 1 +
tests/keys/id_ecdsa521.pw | 10 +
tests/keys/id_ed25519 | 8 +
tests/keys/id_ed25519.pub | 1 +
tests/keys/id_rsa | 27 +
tests/keys/id_rsa.pem | 9 +
tests/keys/id_rsa.pub | 1 +
tests/keys/id_rsa.pw | 30 +
tests/keys/id_rsa.sshpem1 | 9 +
tests/keys/id_rsa.sshpem2 | 8 +
tests/keys/message | 1 +
tests/keys/message.rsa.crypt | Bin 0 -> 256 bytes
tests/keys/message.sig.dsa.sha1 | 1 +
tests/keys/message.sig.dsa.sha256 | Bin 0 -> 47 bytes
tests/keys/message.sig.ecdsa.sha1 | Bin 0 -> 71 bytes
tests/keys/message.sig.ecdsa.sha256 | Bin 0 -> 71 bytes
tests/keys/message.sig.ecdsa384.sha1 | Bin 0 -> 103 bytes
tests/keys/message.sig.ecdsa384.sha256 | Bin 0 -> 104 bytes
tests/keys/message.sig.ecdsa521.sha1 | Bin 0 -> 139 bytes
tests/keys/message.sig.ecdsa521.sha256 | 3 +
tests/keys/message.sig.rsa.md5 | Bin 0 -> 256 bytes
tests/keys/message.sig.rsa.sha1 | 1 +
tests/keys/message.sig.rsa.sha256 | Bin 0 -> 256 bytes
tests/keys/opencpu.org.bundle | 86 +
tests/keys/opencpu.org.cer | Bin 0 -> 1697 bytes
tests/keys/signatures.txt | 36 +
tests/keys/testmd5.sig | Bin 0 -> 256 bytes
tests/keys/testsha1.sig | 1 +
tests/testthat.R | 4 +
tests/testthat/test_bignum.R | 42 +
tests/testthat/test_cert.R | 10 +
tests/testthat/test_encrypt.R | 31 +
tests/testthat/test_hash.R | 28 +
tests/testthat/test_hash_error.R | 13 +
tests/testthat/test_hash_output_length.R | 52 +
tests/testthat/test_hash_output_value.R | 43 +
tests/testthat/test_keys_dsa.R | 83 +
tests/testthat/test_keys_ecdsa.R | 85 +
tests/testthat/test_keys_ecdsa384.R | 80 +
tests/testthat/test_keys_ecdsa521.R | 81 +
tests/testthat/test_keys_rsa.R | 86 +
tests/testthat/test_my_key.R | 27 +
tests/testthat/test_pkcs.R | 73 +
tests/testthat/test_rand_error.R | 7 +
tests/testthat/test_salting.R | 73 +
tools/version.c | 4 +
tools/winlibs.R | 8 +
vignettes/bignum.Rmd | 111 +
vignettes/crypto_hashing.Rmd | 58 +
vignettes/keys.Rmd | 99 +
vignettes/secure_rng.Rmd | 59 +
194 files changed, 12619 insertions(+), 130 deletions(-)
diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000..6400da5
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,31 @@
+Package: openssl
+Type: Package
+Title: Toolkit for Encryption, Signatures and Certificates Based on
+ OpenSSL
+Version: 0.9.6
+Authors at R: c(
+ person("Jeroen", "Ooms", , "jeroen.ooms at stat.ucla.edu", role = c("cre", "aut")),
+ person("Oliver", "Keyes", role = "ctb"))
+Description: Bindings to OpenSSL libssl and libcrypto, plus custom SSH pubkey parsers.
+ Supports RSA, DSA and EC curves P-256, P-384 and P-521. Cryptographic signatures
+ can either be created and verified manually or via x509 certificates. AES can be
+ used in cbc, ctr or gcm mode for symmetric encryption; RSA for asymmetric (public
+ key) encryption or EC for Diffie Hellman. High-level envelope functions combine
+ RSA and AES for encrypting arbitrary sized data. Other utilities include key
+ generators, hash functions (md5, sha1, sha256, etc), base64 encoder, a secure
+ random number generator, and 'bignum' math methods for manually performing
+ crypto calculations on large multibyte integers.
+License: MIT + file LICENSE
+URL: https://github.com/jeroenooms/openssl#readme
+BugReports: https://github.com/jeroenooms/openssl/issues
+SystemRequirements: OpenSSL >= 1.0.1
+VignetteBuilder: knitr
+Suggests: testthat, digest, knitr, rmarkdown, jsonlite, jose
+RoxygenNote: 5.0.1.9000
+NeedsCompilation: yes
+Packaged: 2016-12-30 21:26:04 UTC; jeroen
+Author: Jeroen Ooms [cre, aut],
+ Oliver Keyes [ctb]
+Maintainer: Jeroen Ooms <jeroen.ooms at stat.ucla.edu>
+Repository: CRAN
+Date/Publication: 2016-12-31 01:41:12
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..019ab7d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,2 @@
+YEAR: 2016
+COPYRIGHT HOLDER: Jeroen Ooms
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..59cd78b
--- /dev/null
+++ b/MD5
@@ -0,0 +1,181 @@
+6fa08c0ab0ed08aebbbdf43534cadb67 *DESCRIPTION
+91443a13b3d89ea22bfa1222461b0111 *LICENSE
+31ed63c95b88a309a40dc09625bd24e4 *NAMESPACE
+75553d3044314c14331805d24c33cf11 *NEWS
+156bd963e78beb7896a8dde40c040d87 *R/aes.R
+59033eb1b1690ba5a682648924c0dc01 *R/askpass.R
+25bb161cd43a5861b01e425133591e22 *R/base.R
+cc6804a52ad350613a81e2346b817fdf *R/base64.R
+08f06dd3d19d9edb152a9aee864d395f *R/bignum.R
+5f72eefdfed00a7bdb47aa45bf77bfab *R/build.R
+3bf0a5b72dfc6551ad5fcbaa987fa3d2 *R/cert.R
+0d85897cdc8a00f8c3c20358cab1c3a6 *R/diffie.R
+c606d3fec281684d3d47b88057db3531 *R/envelope.R
+6c3fb3d1dab89f2445e55705bbadd57e *R/hash.R
+bdc2a1aae7843d4bf11e1c014108126a *R/info.R
+da023c47b493f35d10f4797c96cd4079 *R/keygen.R
+6df6efd17687a17a081a299d050b5484 *R/list.R
+4ba3798125ba48569c5096a61114ef1a *R/mykey.R
+2fc2aebae35860987e571d5929226179 *R/openssh.R
+b81ef27e71a21e15e4bcb7c6967da506 *R/openssl.R
+dbc330a3f5d1fcbf234cec9fa081bb25 *R/pkcs12.R
+19f56327a3d01276a02ecea94f19ee00 *R/rand.R
+fede48c6c412123261e7c3428bf6a365 *R/read.R
+e39a40bb6ae575d20b739d1a8d623eb3 *R/rsa.R
+422428316cb16391303a8b3358a4b64a *R/signing.R
+5fa6c5d13e176309876292147410885a *R/ssh2.R
+5ecac70bdaf1e7a02da963da3030fdda *R/stream.R
+0b4d07002d68ea8bbf9cb90fae0c0841 *R/write.R
+250578a5040b1769a81d0e0601efe74c *R/writessh.R
+a41ea1cb9e3fb30c340d719ae49e5b22 *build/vignette.rds
+6071edd604dbeb75308cfbedc7790398 *cleanup
+f0694b4a3b6961941199a632e0db388d *configure
+d41d8cd98f00b204e9800998ecf8427e *configure.win
+8d35a5cef6ce28da07867a0712558067 *inst/cacert.pem
+538ca1f45e2c482e27a792761d92f392 *inst/doc/bignum.R
+a4e5f2bd8377da2198e2920218af2530 *inst/doc/bignum.Rmd
+3b09600561a37b0d2d6c386bfc63c63a *inst/doc/bignum.html
+290c8f4ed75f1b80406a241d34906256 *inst/doc/crypto_hashing.R
+b09c484e5db70d1c14c16989744f45f4 *inst/doc/crypto_hashing.Rmd
+39052b09a8b0b604f4f5113f4bb95915 *inst/doc/crypto_hashing.html
+65488f0ce9e60ae12fb2d12b87a0d81e *inst/doc/keys.R
+84e4760fec6195d3851b4dc45f7857e6 *inst/doc/keys.Rmd
+edaed2f589b92b53176d72afa1619a24 *inst/doc/keys.html
+91da732f2fc44700d7816c659df5a2d3 *inst/doc/secure_rng.R
+35ea87007fe89af619623a6d75c0d02d *inst/doc/secure_rng.Rmd
+4029bdb561d1e936ecdb3ef13672146f *inst/doc/secure_rng.html
+74b6933e818c6823f980df0a8188f449 *man/aes_cbc.Rd
+1c13ed2668ebed2de30350511caea7ae *man/askpass.Rd
+1ca678a165f2d0ffb1c5cbf2e5e44045 *man/base64_encode.Rd
+e1a937fa012e57925cbeb3999604c835 *man/bignum.Rd
+545715dec4fb74d120c08dc0ef603d3b *man/certificates.Rd
+87c3686bcbd46853ed1effa125fd1590 *man/ec_dh.Rd
+28ebdd5a99b60ce912506a78c4aeba24 *man/encrypt_envelope.Rd
+8c25de0977573233776fd94989c8b043 *man/fingerprint.Rd
+9e8aaa526774967243a1424a68918bc4 *man/hash.Rd
+b2b38397d228684dd563e752c6dd7e62 *man/keygen.Rd
+67c1362b33ac630956c5df7d847ca36a *man/my_key.Rd
+b4dd35bdd8b9e97d68d6745e98da81fa *man/openssl.Rd
+7de38a9159ca96b99ceaff5b0dcda70d *man/openssl_config.Rd
+de525b970c0bcc21e6406f81a6671b1c *man/pkcs12.Rd
+cb87777861ac150ab8ca40854e3d2c52 *man/rand_bytes.Rd
+787f03c5b1ba59666fa78a92ccb38a74 *man/read_key.Rd
+395e2868987e31182396aae7d129a60a *man/rsa_encrypt.Rd
+f3a08561a51c4b97a5d2754a0d07111a *man/signatures.Rd
+4160b3fa3eaea2d4882282e7b85ef03a *man/write_pem.Rd
+63fb8fd20f3b348b80351510e2e5675b *src/Makevars.in
+4b696cb9e4e5ccb5297a1f65819b561d *src/Makevars.win
+ec75a500d0835cc440659acff51884cf *src/aes.c
+d9273b6812a70794e297730111c49a94 *src/base64.c
+789556b3dd7d4b043db77afe01f08ada *src/bignum.c
+6752edae2fc2f733baf351cc1149b22d *src/cert.c
+c5b03b47b76b7b90629cdcbbdcabdab3 *src/compatibility.c
+8f3be798aec8d2f53f0e30c6c715374b *src/compatibility.h
+0f19e24b658b557428bf8dd2260a9b80 *src/diffie.c
+f500aaadfec8452ef8b15900fe5889d8 *src/envelope.c
+80a12511a5a8f3f85c7b85fe84bc3111 *src/error.c
+885881b0b39fb78467a181be47eacb33 *src/hash.c
+b2eac88701940d8af4d42b47d315b37a *src/info.c
+5349bde8c0f5fd40969108f9ca808eb7 *src/keygen.c
+d7a97e2adce16528f0ee727cd0303121 *src/keys.c
+24ca50752f9b4fd5e77fb1d74e9e9a50 *src/onload.c
+cff1360009c8a4bff591014b57c7a36a *src/openssh.c
+d7a521f29396b74ed2a3206504865ac6 *src/password.c
+2e931f7bd2eba615eeb182c565ed9253 *src/pem.c
+d17725a19d27e0c13d4fc8043fa1904f *src/pkcs12.c
+ca630c283c9c20103ef87dc212210c9f *src/pkcs7.c
+0a38050f3a4e6bd4a8d84d71235a40fe *src/rand.c
+85c1114dce920807918a9ed6a3c24cef *src/rsa.c
+c89b39f64e800a17d383836724a0cb5d *src/signing.c
+905d1cdba52b93c05ea36c4fac1d8c7c *src/ssl.c
+47b98e462e74c32e0de8ef9df32a6c17 *src/stream.c
+1433f784099134008cae33658e4b7bf7 *src/utils.h
+8d3a14570f0b38da0e4617c229ecc5e1 *src/win32/ipv6.c
+328065f2dd8497384a246e62e357e64f *src/write.c
+6e13759f8f0b554d5cfef55df8ef3ca9 *tests/certigo/example-elliptic-sha1.crt
+97bb9cc7be5ed828703d8712fbb6aacf *tests/certigo/example-elliptic-sha1.key
+4725cf42f74234453fe0699354ab4cbd *tests/certigo/example-elliptic-sha1.p12
+8b0d8ade3245a8fc59b6bbf60503a04c *tests/certigo/example-elliptic-sha1.p7b
+dba3b6d19ae93a96de7b55e1564af27a *tests/certigo/example-leaf.crt
+f87d22f8af64fd7a5775a77aa9c97c13 *tests/certigo/example-leaf.p12
+479d06a600d189071775161befff4f88 *tests/certigo/example-leaf.p7b
+71b5de5e3a8b052cb91239fca7e3ec66 *tests/certigo/example-root.crt
+17974e3ac187cfe3142558867a77f51c *tests/certigo/example-root.p12
+7e76046f9b2549b57c4fa63366b7f293 *tests/certigo/example-root.p7b
+b959506c4973c8a40a71723e4715fa91 *tests/google.dk/generate.bash
+ec9f8443da96deaf9c04b7f67dda694f *tests/google.dk/wildcard-google.dk-chain-password.p12
+e0a58b25b344bb0e5071095bb26749ba *tests/google.dk/wildcard-google.dk-chain.p12
+bb96ba9e169ab56be21727f97ac8bc57 *tests/google.dk/wildcard-google.dk-chain.pem
+1936244e95bda7e721da8d94631f90cc *tests/google.dk/wildcard-google.dk-leaf.crt
+7b3411e4816d89152c94650429a95a3b *tests/google.dk/wildcard-google.dk-leaf.notAfter
+a6e29055c75a61f8b829fabc483e9255 *tests/google.dk/wildcard-google.dk-leaf.notBefore
+6bf06423c730a1accf77702a5f75f202 *tests/google.dk/wildcard-google.dk-leaf.sha1
+c7889c8223d93672ebd0a78fe8b60b69 *tests/google.dk/wildcard-google.dk-leaf.sha256
+86bb4b720c3b04bf3f657ebe5257247e *tests/keys/authorized_keys
+2b826616874713ef8c46cb5e624fb1ed *tests/keys/blabla.pem
+e42a2322835a684123bac213af82e679 *tests/keys/fingerprints.txt
+8bbf8c9d265bad5468e614a8ea0b3170 *tests/keys/id_dsa
+d97d4fa3b8f478a194b4745836995b9b *tests/keys/id_dsa.pem
+013093495d0d2e6a96521a28206b22c0 *tests/keys/id_dsa.pub
+be277f65217534ad5dd6873c88db6a8d *tests/keys/id_dsa.pw
+7111edec2eadc92fbb747792566e6d82 *tests/keys/id_ecdsa
+cbcb9dbb92f8e91c667e8788995f2a26 *tests/keys/id_ecdsa.pem
+f6e08d64ac8d08c62e929d00b355fb82 *tests/keys/id_ecdsa.pub
+e8abfc7cf77edad4f0e586c40ee02220 *tests/keys/id_ecdsa.pw
+8a6d752ac3a71bcb6a927c28bd105091 *tests/keys/id_ecdsa384
+0394a779c3ac47e6e8e4f7a4ba890a49 *tests/keys/id_ecdsa384.pem
+b60fc8835f43d7a7e1146e944e6ac2a9 *tests/keys/id_ecdsa384.pub
+aa781b526a3736482a5de3fa0b5b6369 *tests/keys/id_ecdsa384.pw
+53f0e47d6c669edeb1dd61ef8f05e776 *tests/keys/id_ecdsa521
+236bf61261cd74e72bf41e9e375baf52 *tests/keys/id_ecdsa521.pem
+0a607e5a1cc5f9d7e30e5ca1930527ad *tests/keys/id_ecdsa521.pub
+9c929bc44be5a91f712c94048ed0202c *tests/keys/id_ecdsa521.pw
+ec1176d8fa36002551a80752cf6c7807 *tests/keys/id_ed25519
+68b709541160a7b1a083f43dc7564e6b *tests/keys/id_ed25519.pub
+7250c3815bcd77cbfefac481a18e194d *tests/keys/id_rsa
+df07301131dc1431559faec84f40ceaf *tests/keys/id_rsa.pem
+a506a303ce6dcbb08fe6dda45f99beb6 *tests/keys/id_rsa.pub
+9b4011e6a7f626bce1fe57b5f3295fc5 *tests/keys/id_rsa.pw
+357978e93a18b90eb5ce4546687f68d9 *tests/keys/id_rsa.sshpem1
+a644113625bec4968afac4f4f3ce27d1 *tests/keys/id_rsa.sshpem2
+2309502dc5493f110869b570d9028942 *tests/keys/message
+0acc3b8d66eec5cc3c402526d52b95f8 *tests/keys/message.rsa.crypt
+c75071322c29af08f21846ddcfb1670f *tests/keys/message.sig.dsa.sha1
+13568e19ea856b247dbbd7d43b125fc4 *tests/keys/message.sig.dsa.sha256
+a23014db1616220d6e053a46de241cb9 *tests/keys/message.sig.ecdsa.sha1
+04406f95f68a41d40aab720443a8a997 *tests/keys/message.sig.ecdsa.sha256
+64c3b0f81a5eac0b72312a1a1a2b378d *tests/keys/message.sig.ecdsa384.sha1
+0d5f1679337d35f68d51697e71937da4 *tests/keys/message.sig.ecdsa384.sha256
+d669594c74e25379fbf14aad3044a211 *tests/keys/message.sig.ecdsa521.sha1
+9f6fd35437c7dedd9f09729b5c5ece06 *tests/keys/message.sig.ecdsa521.sha256
+946876a3939d38dcf016ab1a78524b18 *tests/keys/message.sig.rsa.md5
+155adaa2076d9f03e96e639e35bc83ed *tests/keys/message.sig.rsa.sha1
+fd4586ee1fab5300390192ca279a83f9 *tests/keys/message.sig.rsa.sha256
+80e69dad2a0c912b096b75b86d11f925 *tests/keys/opencpu.org.bundle
+9f007e1a097c8d1d34fb78ccb6bcd030 *tests/keys/opencpu.org.cer
+a7b9d2b3e21f6a82a775a95cc47e789b *tests/keys/signatures.txt
+946876a3939d38dcf016ab1a78524b18 *tests/keys/testmd5.sig
+155adaa2076d9f03e96e639e35bc83ed *tests/keys/testsha1.sig
+d36c00d3573ddb09feb853bd5f9f6165 *tests/testthat.R
+1859c337baf484e07cb43695d1e45c5c *tests/testthat/test_bignum.R
+eac7fe63112e5e54063c31bc6b85dc21 *tests/testthat/test_cert.R
+e5bd1c312bdf61667e0f4bb4e7fa3012 *tests/testthat/test_encrypt.R
+2567bc46f4e180187cbe91e3b29ece7a *tests/testthat/test_hash.R
+3769c5642de0c92a01b0ce26a5c2b564 *tests/testthat/test_hash_error.R
+0b06247d355631b5b8514b1f0c400b28 *tests/testthat/test_hash_output_length.R
+dee271a59f13a38d52b45993f006a342 *tests/testthat/test_hash_output_value.R
+9f02afacd5f7bd981ef2f871129277b4 *tests/testthat/test_keys_dsa.R
+bca365b3342c63b5c940d6c0f0b56ffc *tests/testthat/test_keys_ecdsa.R
+b181d0e53d76746081caa03e49b22528 *tests/testthat/test_keys_ecdsa384.R
+f00cf8c15698ca5c777f7b4c329b965d *tests/testthat/test_keys_ecdsa521.R
+097fe4c47ac7a836075bf3d1de36b0d1 *tests/testthat/test_keys_rsa.R
+ef3bf5166624f519570629b396a5481f *tests/testthat/test_my_key.R
+4418540f5953f855f506d85a8651fbfb *tests/testthat/test_pkcs.R
+41db695299df32c13b94f7e373e4f90d *tests/testthat/test_rand_error.R
+7a3694618b99ad418b4b50245aa4bd47 *tests/testthat/test_salting.R
+0ec27c181a66ce5b72bc8c3940e9e00e *tools/version.c
+fa81790d90a551ba6a6ba9afc61b772b *tools/winlibs.R
+a4e5f2bd8377da2198e2920218af2530 *vignettes/bignum.Rmd
+b09c484e5db70d1c14c16989744f45f4 *vignettes/crypto_hashing.Rmd
+84e4760fec6195d3851b4dc45f7857e6 *vignettes/keys.Rmd
+35ea87007fe89af619623a6d75c0d02d *vignettes/secure_rng.Rmd
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000..ecb310b
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,184 @@
+# Generated by roxygen2: do not edit by hand
+
+S3method("!=",bignum)
+S3method("$",cert)
+S3method("$",key)
+S3method("$",pubkey)
+S3method("$<-",cert)
+S3method("$<-",key)
+S3method("$<-",pubkey)
+S3method("%%",bignum)
+S3method("%/%",bignum)
+S3method("*",bignum)
+S3method("+",bignum)
+S3method("-",bignum)
+S3method("/",bignum)
+S3method("<",bignum)
+S3method("<=",bignum)
+S3method("==",bignum)
+S3method(">",bignum)
+S3method(">=",bignum)
+S3method("[",cert)
+S3method("[",key)
+S3method("[",pubkey)
+S3method("[<-",cert)
+S3method("[<-",key)
+S3method("[<-",pubkey)
+S3method("[[",cert)
+S3method("[[",key)
+S3method("[[",pubkey)
+S3method("[[<-",cert)
+S3method("[[<-",key)
+S3method("[[<-",pubkey)
+S3method("^",bignum)
+S3method(.DollarNames,cert)
+S3method(.DollarNames,key)
+S3method(.DollarNames,pubkey)
+S3method(as.character,bignum)
+S3method(as.character,hash)
+S3method(as.environment,cert)
+S3method(as.environment,key)
+S3method(as.environment,pubkey)
+S3method(as.list,cert)
+S3method(as.list,key)
+S3method(as.list,pubkey)
+S3method(fingerprint,key)
+S3method(fingerprint,pubkey)
+S3method(names,cert)
+S3method(names,key)
+S3method(names,pubkey)
+S3method(print,bignum)
+S3method(print,bytes)
+S3method(print,cert)
+S3method(print,hash)
+S3method(print,key)
+S3method(print,pubkey)
+S3method(str,cert)
+S3method(str,key)
+S3method(str,pubkey)
+export(aes_cbc_decrypt)
+export(aes_cbc_encrypt)
+export(aes_ctr_decrypt)
+export(aes_ctr_encrypt)
+export(aes_gcm_decrypt)
+export(aes_gcm_encrypt)
+export(aes_keygen)
+export(askpass)
+export(base64_decode)
+export(base64_encode)
+export(bignum)
+export(bignum_mod_exp)
+export(bignum_mod_inv)
+export(blake2b)
+export(blake2s)
+export(ca_bundle)
+export(cert_verify)
+export(decrypt_envelope)
+export(download_ssl_cert)
+export(dsa_keygen)
+export(ec_dh)
+export(ec_keygen)
+export(encrypt_envelope)
+export(fingerprint)
+export(md4)
+export(md5)
+export(my_key)
+export(my_pubkey)
+export(openssl_config)
+export(rand_bytes)
+export(rand_num)
+export(read_cert)
+export(read_cert_bundle)
+export(read_key)
+export(read_p12)
+export(read_p7b)
+export(read_pem)
+export(read_pubkey)
+export(ripemd160)
+export(rsa_decrypt)
+export(rsa_encrypt)
+export(rsa_keygen)
+export(sha1)
+export(sha2)
+export(sha224)
+export(sha256)
+export(sha384)
+export(sha512)
+export(signature_create)
+export(signature_verify)
+export(write_der)
+export(write_p12)
+export(write_p7b)
+export(write_pem)
+export(write_ssh)
+importFrom(utils,.DollarNames)
+useDynLib(openssl,R_RAND_bytes)
+useDynLib(openssl,R_aes_any)
+useDynLib(openssl,R_base64_decode)
+useDynLib(openssl,R_base64_encode)
+useDynLib(openssl,R_bignum_add)
+useDynLib(openssl,R_bignum_as_character)
+useDynLib(openssl,R_bignum_bits)
+useDynLib(openssl,R_bignum_compare)
+useDynLib(openssl,R_bignum_devide)
+useDynLib(openssl,R_bignum_exp)
+useDynLib(openssl,R_bignum_mod)
+useDynLib(openssl,R_bignum_mod_exp)
+useDynLib(openssl,R_bignum_mod_inv)
+useDynLib(openssl,R_bignum_multiply)
+useDynLib(openssl,R_bignum_subtract)
+useDynLib(openssl,R_cert_info)
+useDynLib(openssl,R_cert_pubkey)
+useDynLib(openssl,R_cert_verify_cert)
+useDynLib(openssl,R_derive_pubkey)
+useDynLib(openssl,R_diffie_hellman)
+useDynLib(openssl,R_digest)
+useDynLib(openssl,R_digest_raw)
+useDynLib(openssl,R_download_cert)
+useDynLib(openssl,R_dsa_priv_decompose)
+useDynLib(openssl,R_dsa_pubkey_build)
+useDynLib(openssl,R_dsa_pubkey_decompose)
+useDynLib(openssl,R_ecdsa_key_build)
+useDynLib(openssl,R_ecdsa_priv_decompose)
+useDynLib(openssl,R_ecdsa_pubkey_build)
+useDynLib(openssl,R_ecdsa_pubkey_decompose)
+useDynLib(openssl,R_envelope_decrypt)
+useDynLib(openssl,R_envelope_encrypt)
+useDynLib(openssl,R_hash_sign)
+useDynLib(openssl,R_hash_verify)
+useDynLib(openssl,R_hmac_feed)
+useDynLib(openssl,R_hmac_final)
+useDynLib(openssl,R_hmac_init)
+useDynLib(openssl,R_keygen_dsa)
+useDynLib(openssl,R_keygen_ecdsa)
+useDynLib(openssl,R_keygen_rsa)
+useDynLib(openssl,R_md_feed)
+useDynLib(openssl,R_md_final)
+useDynLib(openssl,R_md_init)
+useDynLib(openssl,R_openssl_config)
+useDynLib(openssl,R_parse_bignum)
+useDynLib(openssl,R_parse_der_cert)
+useDynLib(openssl,R_parse_der_key)
+useDynLib(openssl,R_parse_der_pkcs7)
+useDynLib(openssl,R_parse_der_pubkey)
+useDynLib(openssl,R_parse_pem)
+useDynLib(openssl,R_parse_pem_cert)
+useDynLib(openssl,R_parse_pem_key)
+useDynLib(openssl,R_parse_pem_pkcs1)
+useDynLib(openssl,R_parse_pem_pkcs7)
+useDynLib(openssl,R_parse_pem_pubkey)
+useDynLib(openssl,R_parse_pkcs12)
+useDynLib(openssl,R_pem_write_cert)
+useDynLib(openssl,R_pem_write_key)
+useDynLib(openssl,R_pem_write_pubkey)
+useDynLib(openssl,R_pubkey_bitsize)
+useDynLib(openssl,R_pubkey_type)
+useDynLib(openssl,R_pubkey_verify_cert)
+useDynLib(openssl,R_rsa_decrypt)
+useDynLib(openssl,R_rsa_encrypt)
+useDynLib(openssl,R_rsa_key_build)
+useDynLib(openssl,R_rsa_priv_decompose)
+useDynLib(openssl,R_rsa_pubkey_build)
+useDynLib(openssl,R_rsa_pubkey_decompose)
+useDynLib(openssl,R_write_pkcs12)
+useDynLib(openssl,R_write_pkcs7)
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..f1a0078
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,71 @@
+0.9.6
+ - Add read_p7b() and write_p7b() for certificate bundles
+ - Rename read_pkcs12 / write_pkcs12 to read_p12 / write_p12
+ - More unit test for rountripping certs
+ - Workaround for PEM files with "RSA PUBLIC KEY" instead of "PUBLIC KEY" header
+ - Fix example in bignum vignette for OpenSSL 1.1.0 (increase RSA key size)
+ - Sync bundled cacert.pem with Mozilla as of: Wed Sep 14 03:12:05 2016
+ - Added blake2b and blake2s hash functions (only available in libssl 1.1)
+ - Fix support for LibreSSL
+
+0.9.5
+ - Support for new API in OpenSSL 1.1.0
+ - Remove 'pseudo_rand_bytes()' (deprecated in libssl)
+ - Work around missing EVP_CIPH_GCM_MODE in OpenSSL 1.0.0
+ - Add read_pkcs12() and write_pkcs12() functions
+ - Add read_pem() for debugging PEM files
+ - Add base methods [, [[, $, names, .DollarNames for keys and certificates
+ - Update libssl on Windows to 1.0.2h
+ - Add #define _POSIX_C_SOURCE in ssl.c to ensure getaddrinfo() is available
+ - Add as.character.hash method for raw hashes
+ - Clear error buffer when raising an error
+
+0.9.4
+ - Fix ec_keygen() for old versions of OpenSSL
+ - Added aes_ctr() and aes_gcm() modes
+ - Added aes_keygen()
+ - Added bignum_mod_inv()
+ - Internal tools for JWT/JWK support (see pkg: jose)
+
+0.9.3
+ - Added ec_dh() function for ECDH
+ - Added --atleast-version=1.0 to pkg-config in configure script
+ - Switch as.list(cert) to RFC2253 format for 'subject' and 'issuer' fields
+
+0.9.2
+ - Disable EC stuff for OPENSSL_NO_EC (needed on some Solaris / Gentoo)
+ - Added openssl_config() function to test if libssl is built with EC support
+ - Make configure script bourne compatible (remove bash shebang)
+ - Tweak for OpenBSD in ssl.c
+ - Added sha224, sha384 and sha2 functions
+ - Export the fingerprint function
+
+0.9.1
+ - Fix for getaddrinfo() in Solaris
+ - Use the configurable askpass() for password prompt
+
+0.9
+ - Switched download_ssl_cert to getaddrinfo() api for ipv6 support
+ - Fix for example for naming conflict with new digest package
+
+0.8
+ - Configure script now checks for OpenSSL minimum version 1.0.0
+
+0.7
+ - Breaking change: hash functions now use hmac 'key' instead of a 'salt'
+ - The my_key() and my_pubkey() functions now work as documented
+ - as.list(cert) add alt_names field for https certs with multiple domains
+ - added export_pem for certificates
+
+0.6
+ - Added --force-bottle to autobrew installer
+ - Use nonblocking socket in ssl to set connection timeout
+ - Fix UBSAN problem in ssl.c
+ - Fix ASAN problem in hash.c
+
+0.5
+ - Major overhaul, add encryption, signature, cert stuff
+ - Upgrade libssl and libcrypto on windows to 1.0.2d
+
+0.4
+ - Added base64 functions
diff --git a/R/aes.R b/R/aes.R
new file mode 100644
index 0000000..f8a0e0d
--- /dev/null
+++ b/R/aes.R
@@ -0,0 +1,98 @@
+#' Symmetric AES encryption
+#'
+#' Low-level symmetric encryption/decryption using the AES block cipher in CBC mode.
+#' The key is a raw vector, for example a hash of some secret. When no shared
+#' secret is available, a random key can be used which is exchanged via an
+#' asymettric protocol such as RSA. See \code{\link{rsa_encrypt}} for a worked example
+#' or \code{\link{encrypt_envelope}} for a high-level wrapper combining AES and RSA.
+#'
+#' @export
+#' @rdname aes_cbc
+#' @name aes_cbc
+#' @param length how many bytes to generate. Usually 16 (128-bit) or 12 (92-bit) for \code{aes_gcm}
+#' @param data raw vector or path to file with data to encrypt or decrypt
+#' @param key raw vector of length 16, 24 or 32, e.g. the hash of a shared secret
+#' @param iv raw vector of length 16 (aes block size) or NULL. The initialization vector
+#' is not secret but should be random
+#' @examples # aes-256 requires 32 byte key
+#' passphrase <- charToRaw("This is super secret")
+#' key <- sha256(passphrase)
+#'
+#' # symmetric encryption uses same key for decryption
+#' x <- serialize(iris, NULL)
+#' y <- aes_cbc_encrypt(x, key = key)
+#' x2 <- aes_cbc_decrypt(y, key = key)
+#' stopifnot(identical(x, x2))
+aes_ctr_encrypt <- function(data, key, iv = rand_bytes(16)){
+ aes_encrypt(data, key, iv, "ctr")
+}
+
+#' @export
+#' @rdname aes_cbc
+aes_ctr_decrypt <- function(data, key, iv = attr(data, "iv")){
+ aes_decrypt(data, key, iv, "ctr")
+}
+
+#' @export
+#' @rdname aes_cbc
+aes_cbc_encrypt <- function(data, key, iv = rand_bytes(16)){
+ aes_encrypt(data, key, iv, "cbc")
+}
+
+#' @export
+#' @rdname aes_cbc
+aes_cbc_decrypt <- function(data, key, iv = attr(data, "iv")){
+ aes_decrypt(data, key, iv, "cbc")
+}
+
+#' @export
+#' @rdname aes_cbc
+aes_gcm_encrypt <- function(data, key, iv = rand_bytes(16)){
+ aes_encrypt(data, key, iv, "gcm")
+}
+
+#' @export
+#' @rdname aes_cbc
+aes_gcm_decrypt <- function(data, key, iv = attr(data, "iv")){
+ aes_decrypt(data, key, iv, "gcm")
+}
+
+aes_encrypt <- function(data, key, iv, mode){
+ data <- path_or_raw(data)
+ if(!is.raw(data))
+ stop("The 'data' must path to a file or raw vector")
+ out <- aes_any(data, key, iv, TRUE, mode)
+ structure(out, iv = iv)
+}
+
+aes_decrypt <- function(data, key, iv, mode){
+ data <- path_or_raw(data)
+ if(!is.raw(data))
+ stop("The 'data' must be raw vector")
+ aes_any(data, key, iv, FALSE, mode)
+}
+
+#' @useDynLib openssl R_aes_any
+aes_any <- function(x, key, iv = NULL, encrypt, mode){
+ if(is.null(iv)){
+ iv <- as.raw(rep(0, 16))
+ }
+ stopifnot(is.raw(x))
+ stopifnot(is.raw(key))
+ stopifnot(is.raw(iv))
+ stopifnot(is.logical(encrypt))
+ stopifnot(is.character(mode))
+ cipher <- paste("aes", length(key) * 8, mode, sep = "-")
+ .Call(R_aes_any, x, key, iv, encrypt, cipher)
+}
+
+#' @rdname aes_cbc
+#' @export
+aes_keygen <- function(length = 16){
+ structure(rand_bytes(length), class = c("bytes", "aes", "raw"))
+}
+
+#' @export
+print.bytes <- function(x, ...){
+ cat(class(x)[-1], paste(x, collapse = ":"), "\n")
+}
diff --git a/R/askpass.R b/R/askpass.R
new file mode 100644
index 0000000..3a48981
--- /dev/null
+++ b/R/askpass.R
@@ -0,0 +1,12 @@
+#' Password Prompt Utility
+#'
+#' Function to prompt the user for a password to read a protected private key.
+#' Frontends can provide a custom password entry widget by setting the \code{askpass}
+#' option. If no such option is specified we default to \code{\link{readline}}.
+#'
+#' @export
+#' @param prompt the string printed when prompting the user for input.
+askpass <- function(prompt = "Please enter your password: "){
+ FUN <- getOption("askpass", readline)
+ FUN(prompt)
+}
diff --git a/R/base.R b/R/base.R
new file mode 100644
index 0000000..c9760ee
--- /dev/null
+++ b/R/base.R
@@ -0,0 +1,110 @@
+#' @export
+`[[.cert` <- function(x, y) as.list(x)[[y]]
+
+#' @export
+`[[.key` <- `[[.cert`
+
+#' @export
+`[[.pubkey` <- `[[.cert`
+
+
+#' @export
+`$.cert` <- `[[.cert`
+
+#' @export
+`$.key` <- `[[.cert`
+
+#' @export
+`$.pubkey` <- `[[.cert`
+
+
+#' @export
+`[.cert` <- function(x, y) as.list(x)[y]
+
+#' @export
+`[.key` <- `[.cert`
+
+#' @export
+`[.pubkey` <- `[.cert`
+
+
+#' @export
+names.cert <- function(x) names(as.list(x))
+
+#' @export
+names.key <- names.cert
+
+#' @export
+names.pubkey <- names.cert
+
+
+#' @export
+as.environment.cert <- function(x) as.environment(as.list(x))
+
+#' @export
+as.environment.key <- as.environment.cert
+
+#' @export
+as.environment.pubkey <- as.environment.cert
+
+
+#' @export
+#' @importFrom utils .DollarNames
+.DollarNames.cert <- function(x, pattern = "") {
+ x <- as.list(x)
+ matches <- grep(pattern, names(x), value = TRUE)
+ structure(matches,
+ types = vapply(x[matches], typeof, character(1), USE.NAMES = FALSE))
+}
+
+#' @export
+.DollarNames.key <- .DollarNames.cert
+
+#' @export
+.DollarNames.pubkey <- .DollarNames.cert
+
+
+#' @export
+str.cert <- function(object, ...) utils::str(as.list(object), ...)
+
+#' @export
+str.key <- str.cert
+
+#' @export
+str.pubkey <- function(object, ...){
+ x <- as.list(object)
+ x$ssh <- paste(substring(x$ssh, 1, getOption('width') - 30), "...")
+ utils::str(x, ...)
+}
+
+
+### Not (yet?) implemented stuff
+
+stopfun <- function(..., value){ stop("object cannot be modified", call. = FALSE) }
+
+#' @export
+`[<-.cert` <- stopfun
+
+#' @export
+`[<-.key` <- stopfun
+
+#' @export
+`[<-.pubkey` <- stopfun
+
+#' @export
+`[[<-.cert` <- stopfun
+
+#' @export
+`[[<-.key` <- stopfun
+
+#' @export
+`[[<-.pubkey` <- stopfun
+
+#' @export
+`$<-.cert` <- stopfun
+
+#' @export
+`$<-.key` <- stopfun
+
+#' @export
+`$<-.pubkey` <- stopfun
diff --git a/R/base64.R b/R/base64.R
new file mode 100644
index 0000000..3dc49b6
--- /dev/null
+++ b/R/base64.R
@@ -0,0 +1,35 @@
+#' Encode and decode base64
+#'
+#' Encode and decode binary data into a base64 string. Character vectors are
+#' automatically collapsed into a single string.
+#'
+#' @rdname base64_encode
+#' @useDynLib openssl R_base64_encode
+#' @param bin raw or character vector with data to encode into base64
+#' @param linebreaks insert linebreaks in the base64 message to make it more readable
+#' @param text string with base64 data to decode
+#' @export
+#' @examples input <- charToRaw("foo = bar + 5")
+#' message <- base64_encode(input)
+#' output <- base64_decode(message)
+#' identical(output, input)
+base64_encode <- function(bin, linebreaks = FALSE){
+ if(is.character(bin)){
+ bin <- charToRaw(paste(bin, collapse=""))
+ }
+ stopifnot(is.raw(bin))
+ .Call(R_base64_encode, bin, as.logical(linebreaks))
+}
+
+#' @rdname base64_encode
+#' @useDynLib openssl R_base64_decode
+#' @export
+base64_decode <- function(text){
+ if(is.raw(text)){
+ text <- rawToChar(text)
+ }
+ stopifnot(is.character(text))
+ text <- paste(text, collapse="")
+ text <- gsub("[\r\n]", "", text)[[1]]
+ .Call(R_base64_decode, text)
+}
diff --git a/R/bignum.R b/R/bignum.R
new file mode 100644
index 0000000..1b1cbcd
--- /dev/null
+++ b/R/bignum.R
@@ -0,0 +1,189 @@
+#' Big number arithmetic
+#'
+#' Basic operations for working with large integers. The \code{bignum}
+#' funtion converts a positive integer, string or raw vector into a bignum type.
+#' All basic \link{Arithmetic} and \link{Comparison} operators such as
+#' \code{+}, \code{-}, \code{*}, \code{^}, \code{\%\%}, \code{\%/\%}, \code{==},
+#' \code{!=}, \code{<}, \code{<=}, \code{>} and \code{>=} are implemented for
+#' bignum objects. The
+#' \href{https://en.wikipedia.org/wiki/Modular_exponentiation}{Modular exponenent}
+#' (\code{a^b \%\% m}) can be calculated using \code{\link{bignum_mod_exp}}
+#' when \code{b} is too large for calculating \code{a^b} directly.
+#'
+#' @export
+#' @name bignum
+#' @rdname bignum
+#' @param x an integer, string (hex or dec) or raw vector
+#' @param a bignum value for \code{(a^b \%\% m)}
+#' @param b bignum value for \code{(a^b \%\% m)}
+#' @param m bignum value for \code{(a^b \%\% m)}
+#' @param hex set to TRUE to parse strings as hex rather than decimal notation
+#' @useDynLib openssl R_parse_bignum
+#' @examples # create a bignum
+#' x <- bignum(123L)
+#' y <- bignum("123456789123456789")
+#' z <- bignum("D41D8CD98F00B204E9800998ECF8427E", hex = TRUE)
+#'
+#' # Basic arithmetic
+#' div <- z %/% y
+#' mod <- z %% y
+#' z2 <- div * y + mod
+#' stopifnot(z2 == z)
+#' stopifnot(div < z)
+bignum <- function(x, hex = FALSE){
+ if(inherits(x, "bignum"))
+ return(x)
+ stopifnot(is.raw(x) || is.character(x) || is.numeric(x))
+ if(is.numeric(x)){
+ if(is_positive_integer(x)){
+ x <- formatC(x, format = "fg")
+ } else {
+ stop("Cannot convert to bignum: x must be positive integer, character or raw", call. = FALSE)
+ }
+ }
+ if(is.character(x)){
+ if(identical(x, "0")){
+ # special case always valid
+ } else if(isTRUE(hex)){
+ if(!grepl("^([a-fA-F0-9]{2})+$", x))
+ stop("Value '", x, "' is not valid hex string", call. = FALSE)
+ } else {
+ if(!grepl("^[0-9]+$", x))
+ stop("Value '", x, "' is not valid integer", call. = FALSE)
+ }
+ }
+ .Call(R_parse_bignum, x, hex)
+}
+
+bn <- bignum
+
+#' @export
+print.bignum <- function(x, hex = FALSE, ...){
+ cat("[b]", as.character.bignum(x, hex = hex))
+}
+
+#' @export
+#' @useDynLib openssl R_bignum_as_character
+as.character.bignum <- function(x, hex = FALSE, ...){
+ .Call(R_bignum_as_character, x, hex)
+}
+
+#' @export
+#' @useDynLib openssl R_bignum_add
+`+.bignum` <- function(x, y){
+ .Call(R_bignum_add, bn(x), bn(y))
+}
+
+#' @export
+#' @useDynLib openssl R_bignum_subtract
+`-.bignum` <- function(x, y){
+ x <- bn(x)
+ y <- bn(y)
+ stopifnot(x >= y)
+ .Call(R_bignum_subtract, x, y)
+}
+
+#' @export
+#' @useDynLib openssl R_bignum_multiply
+`*.bignum` <- function(x, y){
+ .Call(R_bignum_multiply, bn(x), bn(y))
+}
+
+#' @export
+#' @useDynLib openssl R_bignum_exp
+`^.bignum` <- function(x, y){
+ .Call(R_bignum_exp, bn(x), bn(y))
+}
+
+#' @export
+#' @useDynLib openssl R_bignum_devide
+`%/%.bignum` <- function(x, y){
+ .Call(R_bignum_devide, bn(x), bn(y))
+}
+
+
+# Doesn't help because R always evaluates 'x' to determine dispatch method
+#' @export
+`%%.bignum` <- function(x, y){
+ xcall = substitute(x)
+ if(length(xcall) == 3 && identical(xcall[[1]], quote(`^`))){
+ a <- eval(xcall[[2]])
+ b <- eval(xcall[[3]])
+ bignum_mod_exp(a, b, y)
+ } else {
+ bignum_mod(x, y)
+ }
+}
+
+#' @export
+#' @useDynLib openssl R_bignum_compare
+`>.bignum` <- function(x, y){
+ identical(1L, .Call(R_bignum_compare, bn(x), bn(y)));
+}
+
+#' @export
+#' @useDynLib openssl R_bignum_compare
+`<.bignum` <- function(x, y){
+ identical(-1L, .Call(R_bignum_compare, bn(x), bn(y)));
+}
+
+#' @export
+#' @useDynLib openssl R_bignum_compare
+`==.bignum` <- function(x, y){
+ identical(0L, .Call(R_bignum_compare, bn(x), bn(y)));
+}
+
+#' @export
+`!=.bignum` <- function(x, y){
+ !identical(0L, .Call(R_bignum_compare, bn(x), bn(y)));
+}
+
+#' @export
+`>=.bignum` <- function(x, y){
+ .Call(R_bignum_compare, bn(x), bn(y)) > -1L;
+}
+
+#' @export
+`<=.bignum` <- function(x, y){
+ .Call(R_bignum_compare, bn(x), bn(y)) < 1L;
+}
+
+#' @export
+`/.bignum` <- function(x, y){
+ stop("Use integer division %/% and modulo %% for dividing bignum objects", call. = FALSE)
+}
+
+#' @useDynLib openssl R_bignum_mod
+bignum_mod <- function(x, y){
+ .Call(R_bignum_mod, x, y)
+}
+
+#' @export
+#' @rdname bignum
+#' @useDynLib openssl R_bignum_mod_exp
+bignum_mod_exp <- function(a, b, m){
+ .Call(R_bignum_mod_exp, a, b, m)
+}
+
+#' @export
+#' @rdname bignum
+#' @useDynLib openssl R_bignum_mod_inv
+bignum_mod_inv <- function(a, m){
+ .Call(R_bignum_mod_inv, a, m)
+}
+
+#' @useDynLib openssl R_bignum_bits
+bignum_bits <- function(x){
+ .Call(R_bignum_bits, x)
+}
+
+is_positive_integer <- function(x) {
+ if(x < 0)
+ return(FALSE)
+ if(is.integer(x))
+ return(TRUE)
+ tol <- sqrt(.Machine$double.eps)
+ if(x < 2^53 && abs(x - round(x)) < tol)
+ return(TRUE)
+ return(FALSE)
+}
diff --git a/R/build.R b/R/build.R
new file mode 100644
index 0000000..d2b8a34
--- /dev/null
+++ b/R/build.R
@@ -0,0 +1,24 @@
+#' @useDynLib openssl R_ecdsa_pubkey_build
+ecdsa_pubkey_build <- function(x, y, nist_name){
+ .Call(R_ecdsa_pubkey_build, x, y, nist_name);
+}
+
+#' @useDynLib openssl R_dsa_pubkey_build
+dsa_pubkey_build <- function(p,q,g,y){
+ .Call(R_dsa_pubkey_build, p, q, g, y)
+}
+
+#' @useDynLib openssl R_rsa_pubkey_build
+rsa_pubkey_build <- function(exp, mod){
+ .Call(R_rsa_pubkey_build, exp, mod)
+}
+
+#' @useDynLib openssl R_ecdsa_key_build
+ecdsa_key_build <- function(x, y, d, nist_name){
+ .Call(R_ecdsa_key_build, x, y, d, nist_name)
+}
+
+#' @useDynLib openssl R_rsa_key_build
+rsa_key_build <- function(e, n, p, q, d, dp = (d %% (p-1)), dq = (d %% (q-1)), qi = bignum_mod_inv(q, p)){
+ .Call(R_rsa_key_build, e, n, p, q, d, dp, dq, qi)
+}
diff --git a/R/cert.R b/R/cert.R
new file mode 100644
index 0000000..d1265d6
--- /dev/null
+++ b/R/cert.R
@@ -0,0 +1,84 @@
+#' X509 certificates
+#'
+#' Read, download, analyize and verify X.509 certificates.
+#'
+#' If https verification fails and you can't figure out why, have a look
+#' at \url{https://ssldecoder.org}.
+#'
+#' @useDynLib openssl R_cert_verify_cert R_pubkey_verify_cert
+#' @export
+#' @rdname certificates
+#' @seealso \link{read_cert}
+#' @param cert certficate (or certificate-chain) to be verified. Must be cert or list or path.
+#' @param root trusted pubkey or certificate(s) e.g. CA bundle.
+#' @examples # Verify the r-project HTTPS cert
+#' chain <- download_ssl_cert("www.r-project.org", 443)
+#' print(chain)
+#' print(as.list(chain[[1]])$pubkey)
+#' cert_verify(chain, ca_bundle())
+#'
+#' # Another example
+#' chain <- download_ssl_cert("public.opencpu.org")
+#' ocpu <- chain[[1]]
+#' as.list(ocpu)$subject
+#'
+#' # Write PEM format
+#' write_pem(ocpu)
+cert_verify <- function(cert, root = ca_bundle()){
+ if(is.raw(cert))
+ cert <- list(cert)
+ if(!is.list(cert))
+ cert <- read_cert_bundle(cert)
+ stopifnot(inherits(cert[[1]], "cert"))
+ if(!is.raw(root) && !is.list(root)){
+ buf <- read_input(root)
+ names <- pem_names(buf)
+ if(any(grepl("CERT", names))){
+ root <- read_cert_bundle(root)
+ } else {
+ root <- read_pubkey(root)
+ }
+ }
+ if(inherits(root, "pubkey")){
+ pubkey_verify_cert(cert[[1]], root)
+ } else {
+ stopifnot(all(sapply(root, inherits, "cert")))
+ cert_verify_cert(cert[[1]], cert[-1], root)
+ }
+}
+
+#' @useDynLib openssl R_download_cert
+#' @export
+#' @rdname certificates
+#' @param host string: hostname of the server to connect to
+#' @param port string or integer: port or protocol to use, e.g: \code{443} or \code{"https"}
+download_ssl_cert <- function(host = "localhost", port = 443){
+ if(grepl("https?://", host))
+ stop("Argument 'host' must be a hostname, not url. Take out the https:// prefix.")
+ stopifnot(is.character(host))
+ .Call(R_download_cert, host, as.character(port))
+}
+
+#' @useDynLib openssl R_cert_verify_cert
+cert_verify_cert <- function(cert, chain, root){
+ .Call(R_cert_verify_cert, cert, chain, root)
+}
+
+#' @useDynLib openssl R_pubkey_verify_cert
+pubkey_verify_cert <- function(cert, pubkey){
+ .Call(R_pubkey_verify_cert, cert, pubkey)
+}
+
+#' @export
+#' @rdname certificates
+ca_bundle <- function(){
+ path <- system.file("cacert.pem", package = "openssl")
+ read_cert_bundle(path)
+}
+
+#' @useDynLib openssl R_cert_info
+cert_info <- function(cert){
+ stopifnot(is.raw(cert))
+ out <- .Call(R_cert_info, cert)
+ structure(out, names = c("subject", "issuer", "algorithm", "signature", "validity", "self_signed", "alt_names"))
+}
diff --git a/R/diffie.R b/R/diffie.R
new file mode 100644
index 0000000..6eea6da
--- /dev/null
+++ b/R/diffie.R
@@ -0,0 +1,37 @@
+#' Diffie-Hellman Key Agreement
+#'
+#' Key agreement is one-step method of creating a shared secret between two
+#' peers. Both peers can indendently derive the joined secret by combining
+#' his or her private key with the public key from the peer.
+#'
+#' Currently only Elliptic Curve Diffie Hellman (ECDH) is implemented.
+#'
+#' @export
+#' @rdname ec_dh
+#' @name ec_dh
+#' @useDynLib openssl R_diffie_hellman
+#' @param key your own private key
+#' @param peerkey the public key from your peer
+#' @param password passed to \link{read_key} for reading protected private keys
+#' @references \url{https://wiki.openssl.org/index.php/EVP_Key_Agreement},
+#' \url{https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman}
+#' @examples \dontrun{
+#' # Need two EC keypairs from the same curve
+#' alice_key <- ec_keygen("P-521")
+#' bob_key <- ec_keygen("P-521")
+#'
+#' # Derive public keys
+#' alice_pub <- as.list(alice_key)$pubkey
+#' bob_pub <- as.list(bob_key)$pubkey
+#'
+#'# Both peers can derive the (same) shared secret via each other's pubkey
+#' ec_dh(alice_key, bob_pub)
+#' ec_dh(bob_key, alice_pub)
+#' }
+ec_dh <- function(key = my_key(), peerkey, password = askpass){
+ key <- read_key(key, password = password)
+ peerkey <- read_pubkey(peerkey)
+ stopifnot(inherits(key, "ecdsa"))
+ stopifnot(inherits(peerkey, "ecdsa"))
+ .Call(R_diffie_hellman, key, peerkey)
+}
diff --git a/R/envelope.R b/R/envelope.R
new file mode 100644
index 0000000..ba6d5b7
--- /dev/null
+++ b/R/envelope.R
@@ -0,0 +1,49 @@
+#' Envelope encryption
+#'
+#' An \href{https://wiki.openssl.org/index.php/EVP_Asymmetric_Encryption_and_Decryption_of_an_Envelope}{envelope}
+#' contains ciphertext along with an encrypted session key and optionally and initialiation
+#' vector. The \code{\link{encrypt_envelope}} generates a random IV and session-key which is
+#' used to encrypt the \code{data} with \code{\link[openssl:aes_cbc]{AES}} stream cipher. The
+#' session key itself is encrypted using the given RSA key (see \code{\link{rsa_encrypt}}) and
+#' stored or sent along with the encrypted data. Each of these outputs is required to decrypt
+#' the data with the corresponding private key.
+#'
+#' @useDynLib openssl R_envelope_encrypt
+#' @aliases envelope
+#' @references \url{https://wiki.openssl.org/index.php/EVP_Asymmetric_Encryption_and_Decryption_of_an_Envelope}
+#' @export
+#' @rdname encrypt_envelope
+#' @inheritParams signature_create
+#' @param iv 16 byte raw vector returned by \code{encrypt_envelope}.
+#' @param session raw vector with encrypted session key as returned by \code{encrypt_envelope}.
+#' @examples # Requires RSA key
+#' key <- rsa_keygen()
+#' pubkey <- key$pubkey
+#' msg <- serialize(iris, NULL)
+#'
+#' # Encrypt
+#' out <- encrypt_envelope(msg, pubkey)
+#' str(out)
+#'
+#' # Decrypt
+#' orig <- decrypt_envelope(out$data, out$iv, out$session, key)
+#' stopifnot(identical(msg, orig))
+encrypt_envelope <- function(data, pubkey = my_pubkey()){
+ pk <- read_pubkey(pubkey)
+ stopifnot(inherits(pk, "rsa"))
+ data <- path_or_raw(data)
+ out <- .Call(R_envelope_encrypt, data, pk)
+ structure(out, names = c("iv", "session", "data"))
+}
+
+#' @useDynLib openssl R_envelope_decrypt
+#' @export
+#' @rdname encrypt_envelope
+decrypt_envelope <- function(data, iv, session, key = my_key(), password){
+ sk <- read_key(key, password = password)
+ stopifnot(inherits(sk, "rsa"))
+ stopifnot(is.raw(iv))
+ stopifnot(is.raw(session))
+ data <- path_or_raw(data)
+ .Call(R_envelope_decrypt, data, iv, session, sk)
+}
diff --git a/R/hash.R b/R/hash.R
new file mode 100644
index 0000000..13c1e6d
--- /dev/null
+++ b/R/hash.R
@@ -0,0 +1,252 @@
+#' Vectorized hash/hmac functions
+#'
+#' All hash functions either calculate a hash-digest for \code{key == NULL} or HMAC
+#' (hashed message authentication code) when \code{key} is not \code{NULL}. Supported
+#' inputs are binary (raw vector), strings (character vector) or a connection object.
+#'
+#' Functions are vectorized for the case of character vectors: a vector with \code{n}
+#' strings returns \code{n} hashes. When passing a connection object, the contents will
+#' be stream-hashed which minimizes the amount of required memory. This is recommended
+#' for hashing files from disk or network.
+#'
+#' The sha2 family of algorithms (sha224, sha256, sha384 and sha512) is generally
+#' recommended for sensitive information. While sha1 and md5 are usually sufficient for
+#' collision-resistant identifiers, they are no longer considered secure for cryptographic
+#' purposes.
+#'
+#' In applications where hashes should be irreversible (such as names or passwords) it is
+#' often recommended to use a random \emph{key} for HMAC hashing. This prevents attacks where
+#' we can lookup hashes of common and/or short strings. See examples. A common special case
+#' is adding a random salt to a large number of records to test for uniqueness within the
+#' dataset, while simultaneously rendering the results incomparable to other datasets.
+#'
+#' The \code{blake2b} and \code{blake2s} algorithms are only available if your system has
+#' libssl 1.1 or newer.
+#'
+#' @param x character vector, raw vector or connection object.
+#' @param key string or raw vector used as the key for HMAC hashing
+#' @param size must be equal to 224 256 384 or 512
+#' @references Digest types: \url{https://www.openssl.org/docs/manmaster/man1/dgst.html}
+#' @export
+#' @aliases hmac mac
+#' @rdname hash
+#' @name hashing
+#' @useDynLib openssl R_digest_raw R_digest
+#' @examples # Support both strings and binary
+#' md5(c("foo", "bar"))
+#' md5("foo", key = "secret")
+#'
+#' hash <- md5(charToRaw("foo"))
+#' as.character(hash, sep = ":")
+#'
+#' # Compare to digest
+#' digest::digest("foo", "md5", serialize = FALSE)
+#'
+#' # Other way around
+#' digest::digest(cars, skip = 0)
+#' md5(serialize(cars, NULL))
+#'
+#' # Stream-verify from connections (including files)
+#' myfile <- system.file("CITATION")
+#' md5(file(myfile))
+#' md5(file(myfile), key = "secret")
+#'
+#' \dontrun{check md5 from: http://cran.r-project.org/bin/windows/base/old/3.1.1/md5sum.txt
+#' md5(url("http://cran.r-project.org/bin/windows/base/old/3.1.1/R-3.1.1-win.exe"))}
+#'
+#' # Use a salt to prevent dictionary attacks
+#' sha1("admin") # googleable
+#' sha1("admin", key = "random_salt_value") #not googleable
+#'
+#' # Use a random salt to identify duplicates while anonymizing values
+#' sha256("john") # googleable
+#' sha256(c("john", "mary", "john"), key = "random_salt_value")
+sha1 <- function(x, key = NULL){
+ rawstringhash(x, "sha1", key)
+}
+
+#' @rdname hash
+#' @export
+sha224 <- function(x, key = NULL){
+ rawstringhash(x, "sha224", key)
+}
+
+#' @rdname hash
+#' @export
+sha256 <- function(x, key = NULL){
+ rawstringhash(x, "sha256", key)
+}
+
+#' @rdname hash
+#' @export
+sha384 <- function(x, key = NULL){
+ rawstringhash(x, "sha384", key)
+}
+
+#' @rdname hash
+#' @export
+sha512 <- function(x, key = NULL){
+ rawstringhash(x, "sha512", key)
+}
+
+#' @rdname hash
+#' @export
+sha2 <- function(x, size = 256, key = NULL){
+ rawstringhash(x, paste0("sha", size), key)
+}
+
+#' @rdname hash
+#' @export
+md4 <- function(x, key = NULL){
+ rawstringhash(x, "md4", key)
+}
+
+#' @rdname hash
+#' @export
+md5 <- function(x, key = NULL){
+ rawstringhash(x, "md5", key)
+}
+
+#' @rdname hash
+#' @export
+blake2b <- function(x, key = NULL){
+ rawstringhash(x, "blake2b512", key)
+}
+
+#' @rdname hash
+#' @export
+blake2s <- function(x, key = NULL){
+ rawstringhash(x, "blake2s256", key)
+}
+
+#' @rdname hash
+#' @export
+ripemd160 <- function(x, key = NULL){
+ rawstringhash(x, "ripemd160", key)
+}
+
+# Low level interfaces, not exported.
+rawhash <- function(x, algo, key = NULL){
+ stopifnot(is.raw(x))
+ stopifnot(is.null(key) || is.raw(key))
+ .Call(R_digest_raw, x, as.character(algo), key)
+}
+
+#' @useDynLib openssl R_digest
+stringhash <- function(x, algo, key = NULL){
+ stopifnot(is.character(x))
+ stopifnot(is.null(key) || is.raw(key))
+ .Call(R_digest,x, as.character(algo), key)
+}
+
+connectionhash <- function(con, algo){
+ md <- md_init(algo);
+ if(!isOpen(con)){
+ open(con, "rb")
+ on.exit(close(con))
+ }
+ if(summary(con)$text == "binary"){
+ while(length(data <- readBin(con, raw(), 512*1024))){
+ md_feed(md, data)
+ }
+ } else {
+ while(length(data <- readLines(con, n = 1L, warn = FALSE))){
+ md_feed(md, charToRaw(data))
+ }
+ }
+ md_final(md)
+}
+
+connectionhmac <- function(con, algo, key){
+ if(is.character(key))
+ key <- charToRaw(key)
+ hmac <- hmac_init(algo, key);
+ if(!isOpen(con)){
+ open(con, "rb")
+ on.exit(close(con))
+ }
+ if(summary(con)$text == "binary"){
+ while(length(data <- readBin(con, raw(), 1024))){
+ hmac_feed(hmac, data)
+ }
+ } else {
+ while(length(data <- readLines(con, n = 1L, warn = FALSE))){
+ hmac_feed(hmac, charToRaw(data))
+ }
+ }
+ hmac_final(hmac)
+}
+
+rawstringhash <- function(x, algo, key){
+ if(is.character(key))
+ key <- charToRaw(key)
+ hash <- if(inherits(x, "connection")){
+ if(is.null(key)){
+ connectionhash(x, algo)
+ } else {
+ connectionhmac(x, algo, key)
+ }
+ } else if(is.raw(x)){
+ rawhash(x, algo, key)
+ } else if(is.character(x)){
+ stringhash(x, algo, key)
+ } else {
+ stop("Argument 'x' must be raw or character vector.")
+ }
+ out <- structure(hash, class = c("hash", algo))
+ if(!is.null(key))
+ class(out) <- c(class(out), "hmac")
+ out
+}
+
+hash_type <- function(hash){
+ if(!is.raw(hash))
+ stop("hash must be raw vector or hex string")
+ if(inherits(hash, "md5") || length(hash) == 16){
+ "md5"
+ } else if(inherits(hash, "sha1") || length(hash) == 20){
+ "sha1"
+ } else if(inherits(hash, "sha256") || length(hash) == 32){
+ "sha256"
+ } else{
+ stop("Hash of length ", length(hash), " not supported")
+ }
+}
+
+is_hexraw <- function(str){
+ is.character(str) &&
+ (length(str) == 1) &&
+ grepl("^[a-f0-9 :]+$", tolower(str))
+}
+
+hex_to_raw <- function(str){
+ stopifnot(length(str) == 1)
+ str <- gsub("[ :]", "", str)
+ len <- nchar(str)/2
+ out <- raw(len)
+ for(i in 1:len){
+ out[i] <- as.raw(as.hexmode(substr(str, 2*i-1, 2*i)))
+ }
+ out
+}
+
+parse_hash <- function(x){
+ if(is.raw(x)) return(x)
+ if(is.character(x)) return(hex_to_raw(x[1]))
+ stop("Invalid hash: ", x)
+}
+
+#' @export
+print.hash <- function(x, sep = ":", ...){
+ if(is.raw(x))
+ cat(class(x)[-1], as.character(x, sep = sep), "\n")
+ else
+ print(unclass(x, ...))
+}
+
+#' @export
+as.character.hash <- function(x, sep = "", ...){
+ if(is.raw(x))
+ structure(paste(unclass(x), collapse = sep), class = class(x))
+ else x
+}
diff --git a/R/info.R b/R/info.R
new file mode 100644
index 0000000..7e14fe7
--- /dev/null
+++ b/R/info.R
@@ -0,0 +1,10 @@
+#' OpenSSL Configuration Info
+#'
+#' Shows libssl version and configuration information.
+#'
+#' @export
+#' @useDynLib openssl R_openssl_config
+openssl_config <- function(){
+ out <- .Call(R_openssl_config)
+ structure(out, names = c("version", "ec"))
+}
diff --git a/R/keygen.R b/R/keygen.R
new file mode 100644
index 0000000..5de64bf
--- /dev/null
+++ b/R/keygen.R
@@ -0,0 +1,39 @@
+#' Generate Key pair
+#'
+#' The \code{keygen} functions generate a random private key. Use \code{as.list(key)$pubkey}
+#' to derive the corresponding public key. Use \link{write_pem} to save a private key
+#' to a file, optionally with a password.
+#'
+#' @export
+#' @rdname keygen
+#' @name keygen
+#' @useDynLib openssl R_keygen_rsa
+#' @param bits bitsize of the generated RSA/DSA key
+#' @param curve which NIST curve to use
+#' @examples # Generate keypair
+#' key <- rsa_keygen()
+#' pubkey <- as.list(key)$pubkey
+#'
+#' # Write/read the key with a passphrase
+#' write_pem(key, "id_rsa", password = "supersecret")
+#' read_key("id_rsa", password = "supersecret")
+rsa_keygen <- function(bits = 2048){
+ key <- .Call(R_keygen_rsa, as.integer(bits))
+ structure(key, class = c("key", "rsa"))
+}
+
+#' @export
+#' @rdname keygen
+#' @useDynLib openssl R_keygen_dsa
+dsa_keygen <- function(bits = 1024){
+ key <- .Call(R_keygen_dsa, as.integer(bits))
+ structure(key, class = c("key", "dsa"))
+}
+
+#' @export
+#' @rdname keygen
+#' @useDynLib openssl R_keygen_ecdsa
+ec_keygen <- function(curve = c("P-256", "P-384", "P-521")){
+ key <- .Call(R_keygen_ecdsa, match.arg(curve))
+ structure(key, class = c("key", "ecdsa"))
+}
diff --git a/R/list.R b/R/list.R
new file mode 100644
index 0000000..9f0590d
--- /dev/null
+++ b/R/list.R
@@ -0,0 +1,43 @@
+#' @export
+as.list.key <- function(x, ...){
+ key <- x
+ pubkey <- derive_pubkey(key)
+ pk <- as.list(pubkey)
+ list(
+ type = pk$type,
+ size = pk$size,
+ pubkey = pubkey,
+ data = decompose(key)
+ )
+}
+
+#' @export
+as.list.pubkey <- function(x, ...){
+ pubkey <- x
+ data <- decompose(pubkey)
+ type <- ifelse(inherits(pubkey, "ed25519"), "ed25519", pubkey_type(pubkey))
+ size <- pubkey_bitsize(pubkey)
+ header <- switch(type,
+ "rsa" = "ssh-rsa",
+ "dsa" = "ssh-dss",
+ "ed25519" = "ssh-ed25519",
+ "ecdsa" = paste0("ecdsa-sha2-nistp", substring(data$curve, 3)),
+ stop("Unsupported keytype: ", type)
+ )
+ fp <- unlist(unname(fpdata(pubkey)))
+ list(
+ type = type,
+ size = size,
+ ssh = paste(header, base64_encode(fp)),
+ fingerprint = md5(fp),
+ data = data
+ )
+}
+
+#' @export
+as.list.cert <- function(x, ...){
+ cert <- x
+ info <- cert_info(cert)
+ info$pubkey <- cert_pubkey(cert)
+ info
+}
diff --git a/R/mykey.R b/R/mykey.R
new file mode 100644
index 0000000..5b6b765
--- /dev/null
+++ b/R/mykey.R
@@ -0,0 +1,40 @@
+#' Default keypair
+#'
+#' Set a default keypair via \code{USER_KEY} and \code{USER_PUKBEY} variables.
+#'
+#' The \code{my_key()} function checks environment variable \code{USER_KEY} for a
+#' path to a private keyfile. If unset it defaults to \code{"~/.ssh/id_rsa"}.
+#'
+#' The \code{my_pubkey()} function first tries \code{USER_PUBKEY} and if unset
+#' it checks for \code{USER_KEY} to derive the corresponding pubkey. If both are
+#' unset it defaults to \code{"~/.ssh/id_rsa.pub"}.
+#'
+#' @export
+#' @rdname my_key
+#' @examples # Set random RSA key as default
+#' key <- rsa_keygen()
+#' write_pem(key, tmp <- tempfile(), password = "")
+#' rm(key)
+#' Sys.setenv("USER_KEY" = tmp)
+#'
+#' # Check the new keys
+#' print(my_key())
+#' print(my_pubkey())
+my_key <- function(){
+ path <- Sys.getenv("USER_KEY", "~/.ssh/id_rsa")
+ if(!file.exists(path))
+ stop("No suitable user key found.")
+ read_key(path)
+}
+
+#' @export
+#' @rdname my_key
+my_pubkey <- function(){
+ path <- Sys.getenv("USER_PUBKEY", Sys.getenv("USER_KEY", "~/.ssh/id_rsa.pub"))
+ if(file.exists(path))
+ return(read_pubkey(path))
+
+ # alternatively derive pubkey from key
+ key <- my_key()
+ key$pubkey
+}
diff --git a/R/openssh.R b/R/openssh.R
new file mode 100644
index 0000000..23247b3
--- /dev/null
+++ b/R/openssh.R
@@ -0,0 +1,140 @@
+#' OpenSSH fingerprint
+#'
+#' Calculates the OpenSSH fingerprint of a public key. This value should
+#' match what you get to see when connecting with SSH to a server. Note
+#' that some other systems might use a different algorithm to derive a
+#' (different) fingerprint for the same keypair.
+#'
+#' @export
+#' @param key a public or private key
+#' @param hashfun which hash function to use to calculate the fingerprint
+#' @examples mykey <- rsa_keygen()
+#' pubkey <- as.list(mykey)$pubkey
+#' fingerprint(mykey)
+#' fingerprint(pubkey)
+#'
+#' # Some systems use other hash functions
+#' fingerprint(pubkey, sha1)
+#' fingerprint(pubkey, sha256)
+#'
+#' # Other key types
+#' fingerprint(dsa_keygen())
+fingerprint <- function(key, hashfun = md5){
+ UseMethod("fingerprint")
+}
+
+#' @export
+fingerprint.key <- function(key, hashfun = md5){
+ pubkey <- derive_pubkey(key)
+ fingerprint(pubkey, hashfun = hashfun)
+}
+
+#' @export
+fingerprint.pubkey <- function(key, hashfun = md5){
+ hashdata <- fpdata(key)
+ hashfun(unlist(unname(hashdata)))
+}
+
+fpdata <- function(x, ...){
+ UseMethod("fpdata")
+}
+
+fpdata.rsa <- function(pubkey){
+ input <- c(list(charToRaw("ssh-rsa")), decompose(pubkey))
+ lapply(input, function(x){
+ c(writeBin(length(x), raw(), endian = "big"), x)
+ })
+}
+
+fpdata.dsa <- function(pubkey){
+ input <- c(list(charToRaw("ssh-dss")), decompose(pubkey))
+ lapply(input, function(x){
+ c(writeBin(length(x), raw(), endian = "big"), x)
+ })
+}
+
+fpdata.ecdsa <- function(pubkey){
+ bindata <- decompose(pubkey)
+ nist_name <- bindata[[1]]
+ ssh_name <- switch(nist_name,
+ "P-256" = "nistp256",
+ "P-384" = "nistp384",
+ "P-521" = "nistp521",
+ stop("Unknown curve type: ", nist_name)
+ )
+ keydata <- c(as.raw(4), bindata[[2]], bindata[[3]])
+ input <- c(list(charToRaw(paste0("ecdsa-sha2-", ssh_name))), list(charToRaw(ssh_name)), list(keydata))
+ lapply(input, function(x){
+ c(writeBin(length(x), raw(), endian = "big"), x)
+ })
+}
+
+fpdata.ed25519 <- function(pubkey){
+ input <- c(list(charToRaw("ssh-ed25519")), list(pubkey))
+ lapply(input, function(x){
+ c(writeBin(length(x), raw(), endian = "big"), x)
+ })
+}
+
+#' @useDynLib openssl R_pubkey_type
+pubkey_type <- function(key){
+ .Call(R_pubkey_type, key)
+}
+
+#' @useDynLib openssl R_pubkey_bitsize
+pubkey_bitsize <- function(key){
+ .Call(R_pubkey_bitsize, key)
+}
+
+decompose <- function(x, ...){
+ UseMethod("decompose")
+}
+
+decompose.pubkey <- function(x, ...){
+ UseMethod("pubkey_decompose")
+}
+
+decompose.key <- function(x, ...){
+ UseMethod("priv_decompose")
+}
+
+#' @useDynLib openssl R_rsa_pubkey_decompose
+pubkey_decompose.rsa <- function(key){
+ out <- .Call(R_rsa_pubkey_decompose, key)
+ structure(out, names = c("e", "n"))
+}
+
+#' @useDynLib openssl R_rsa_priv_decompose
+priv_decompose.rsa <- function(key){
+ out <- .Call(R_rsa_priv_decompose, key)
+ structure(out, names = c("e", "n", "p", "q", "d", "dp", "dq", "qi"))
+}
+
+#' @useDynLib openssl R_dsa_pubkey_decompose
+pubkey_decompose.dsa <- function(key){
+ out <- .Call(R_dsa_pubkey_decompose, key)
+ structure(out, names = c("p", "q", "g", "y"))
+}
+
+#' @useDynLib openssl R_dsa_priv_decompose
+priv_decompose.dsa <- function(key){
+ out <- .Call(R_dsa_priv_decompose, key)
+ structure(out, names = c("p", "q", "g", "y", "x"))
+}
+
+#' @useDynLib openssl R_ecdsa_pubkey_decompose
+pubkey_decompose.ecdsa <- function(key){
+ out <- .Call(R_ecdsa_pubkey_decompose, key)
+ structure(out, names = c("curve", "x", "y"))
+}
+
+#' @useDynLib openssl R_ecdsa_priv_decompose
+priv_decompose.ecdsa <- function(key){
+ out <- .Call(R_ecdsa_priv_decompose, key)
+ structure(out, names = c("curve", "x", "y", "secret"))
+}
+
+
+pubkey_decompose.ed25519 <- function(key){
+ unclass(key)
+}
diff --git a/R/openssl.R b/R/openssl.R
new file mode 100644
index 0000000..8614e50
--- /dev/null
+++ b/R/openssl.R
@@ -0,0 +1,20 @@
+#' Toolkit for Encryption, Signatures and Certificates based on OpenSSL
+#'
+#' Bindings to OpenSSL libssl and libcrypto, plus custom SSH \link[openssl:read_key]{pubkey}
+#' parsers. Supports RSA, DSA and NIST curves P-256, P-384 and P-521. Cryptographic
+#' \link[openssl:signature_verify]{signatures} can either be created and verified
+#' manually or via x509 \link[openssl:cert_verify]{certificates}. The
+#' \link[openssl:aes_cbc]{AES block cipher} is used in CBC mode for symmetric
+#' encryption; RSA for \link[openssl:rsa_encrypt]{asymmetric (public key)}
+#' encryption. High-level \link[openssl:encrypt_envelope]{envelope} methods
+#' combine RSA and AES for encrypting arbitrary sized data. Other utilities include
+#' \link[openssl:rsa_keygen]{key generators}, hash functions (\code{\link[openssl:md5]{md5}},
+#' \code{\link[openssl:sha1]{sha1}}, \code{\link[openssl:sha256]{sha256}}, etc),
+#' \code{\link[openssl:base64_encode]{base64}} encoder, a secure \link[openssl:rand_bytes]{random number generator},
+#' and \code{\link[openssl:bignum]{bignum}} math methods for manually performing crypto
+#' calculations on large multibyte integers.
+#'@author Jeroen Ooms, Oliver Keyes
+#'@docType package
+#'@name openssl
+#'@aliases openssl openssl-package
+NULL
diff --git a/R/pkcs12.R b/R/pkcs12.R
new file mode 100644
index 0000000..4df842b
--- /dev/null
+++ b/R/pkcs12.R
@@ -0,0 +1,100 @@
+#' PKCS7 / PKCS12 bundles
+#'
+#' PKCS7 and PKCS12 are container formats for storing multiple certificates and/or keys.
+#'
+#' The PKCS#7 or P7B format is a container for one or more certificates. It can either
+#' be stored in binary form or in a PEM file. P7B files are typically used to import
+#' and export public certificates.
+#'
+#' The PKCS#12 or PFX format is a binary-only format for storing the server certificate,
+#' any intermediate certificates, and the private key into a single encryptable file.
+#' PFX files are usually found with the extensions .pfx and .p12. PFX files are typically
+#' used to import and export certificates with their private keys.
+#'
+#' The PKCS formats also allow for including signatures and CRLs but this is quite rare
+#' and these are currently ignored.
+#'
+#' @export
+#' @rdname pkcs12
+#' @aliases pkcs12 pfx
+#' @param key a private key
+#' @param cert certificate that matches `key`
+#' @param ca a list of certificates (the CA chain)
+#' @param name a friendly title for the bundle
+#' @param password string or function to set/get the password.
+#' @param path a file where to write the output to. If `NULL` the output is returned
+#' as a raw vector.
+#' @useDynLib openssl R_write_pkcs12
+write_p12 <- function(key = NULL, cert = NULL, ca = NULL, name = NULL, password = NULL, path = NULL){
+ if(!length(key) && !length(cert) && !length(ca))
+ stop("Either 'key' or 'cert' or 'ca' must be given")
+ if(is.function(password))
+ password <- password("Enter a new password for your p12 file")
+ if(length(key)) key <- read_key(key)
+ if(length(cert)) cert <- read_cert(cert)
+ if(length(name)) stopifnot(is.character(name))
+ if(length(password)) stopifnot(is.character(password))
+ bin <- .Call(R_write_pkcs12, key, cert, ca, name, password)
+ if(is.null(path)) return(bin)
+ writeBin(bin, path)
+ invisible(path)
+}
+
+#' @export
+#' @rdname pkcs12
+#' @useDynLib openssl R_write_pkcs7
+#' @param der set to TRUE for binary files and FALSE for PEM files
+write_p7b <- function(ca, path = NULL){
+ ca <- if(inherits(ca, "cert")) {
+ list(ca)
+ } else {
+ lapply(ca, read_cert)
+ }
+ bin <- .Call(R_write_pkcs7, ca)
+ if(is.null(path)) return(bin)
+ writeBin(bin, path)
+ invisible(path)
+}
+
+#' @export
+#' @rdname pkcs12
+#' @param file path or raw vector with binary PKCS12 data to parse
+read_p12 <- function(file, password = askpass){
+ buf <- read_input(file)
+ data <- parse_pkcs12(buf, password)
+ out <- list(cert = NULL, key = NULL, ca = NULL)
+ if(length(data[[1]]))
+ out$cert <- read_cert(data[[1]], der = TRUE)
+ if(length(data[[2]]))
+ out$key <- read_key(data[[2]], der = TRUE)
+ if(length(data[[3]]))
+ out$ca <- lapply(data[[3]], read_cert, der = TRUE)
+ return(out)
+}
+
+#' @export
+#' @rdname pkcs12
+read_p7b <- function(file, der = is.raw(file)){
+ buf <- read_input(file)
+ if(!isTRUE(der)){
+ buf <- parse_pem_pkcs7(buf)
+ }
+ data <- structure(parse_der_pkcs7(buf), names = c("certs", "crl"))
+ # Don't return the CRL, nobody seems to use that
+ lapply(data$certs, read_cert)
+}
+
+#' @useDynLib openssl R_parse_pkcs12
+parse_pkcs12 <- function(buf, password){
+ .Call(R_parse_pkcs12, buf, password)
+}
+
+#' @useDynLib openssl R_parse_der_pkcs7
+parse_der_pkcs7 <- function(buf){
+ .Call(R_parse_der_pkcs7, buf)
+}
+
+#' @useDynLib openssl R_parse_pem_pkcs7
+parse_pem_pkcs7 <- function(buf){
+ .Call(R_parse_pem_pkcs7, buf)
+}
diff --git a/R/rand.R b/R/rand.R
new file mode 100644
index 0000000..b15ba89
--- /dev/null
+++ b/R/rand.R
@@ -0,0 +1,47 @@
+# Generate random bytes with OpenSSL
+#
+# These functions interface to the OpenSSL random number generators. They
+# can generate crypto secure random numbers in R.
+#
+#' @title Generate random bytes and numbers with OpenSSL
+#' @aliases rand_num
+#' @rdname rand_bytes
+#' @description this set of functions generates random bytes or numbers from OpenSSL. This
+#' provides a cryptographically secure alternative to R's default random number generator.
+#' \code{rand_bytes} generates \code{n} random cryptographically secure bytes
+#' @useDynLib openssl R_RAND_bytes
+#' @param n number of random bytes or numbers to generate
+#' @references OpenSSL manual: \url{https://www.openssl.org/docs/manmaster/man3/RAND_bytes.html}
+#' @examples rnd <- rand_bytes(10)
+#' as.numeric(rnd)
+#' as.character(rnd)
+#' as.logical(rawToBits(rnd))
+#'
+#' # bytes range from 0 to 255
+#' rnd <- rand_bytes(100000)
+#' hist(as.numeric(rnd), breaks=-1:255)
+#'
+#' # Generate random doubles between 0 and 1
+#' rand_num(5)
+#'
+#' # Use CDF to map [0,1] into random draws from a distribution
+#' x <- qnorm(rand_num(1000), mean=100, sd=15)
+#' hist(x)
+#'
+#' y <- qbinom(rand_num(1000), size=10, prob=0.3)
+#' hist(y)
+#' @export
+rand_bytes <- function(n = 1){
+ if(!is.numeric(n)){
+ stop("Please provide a numeric value for n")
+ }
+ .Call(R_RAND_bytes, n)
+}
+
+#' @rdname rand_bytes
+#' @export
+rand_num <- function(n = 1){
+ # 64 bit double requires 8 bytes.
+ x <- matrix(as.numeric(rand_bytes(n*8)), ncol = 8)
+ as.numeric(x %*% 256^-(1:8))
+}
diff --git a/R/read.R b/R/read.R
new file mode 100644
index 0000000..aee20c2
--- /dev/null
+++ b/R/read.R
@@ -0,0 +1,270 @@
+#' Parsing keys and certificates
+#'
+#' The \code{read_key} function (private keys) and \code{read_pubkey} (public keys)
+#' support both SSH pubkey format and OpenSSL PEM format (base64 data with a \code{--BEGIN}
+#' and \code{---END} header), and automatically convert where necessary. The functions assume
+#' a single key per file except for \code{read_cert_bundle} which supports PEM files
+#' with multiple certificates.
+#'
+#' Most versions of OpenSSL support at least RSA, DSA and ECDSA keys. Certificates must
+#' conform to the X509 standard.
+#'
+#' The \code{password} argument is needed when reading keys that are protected with a
+#' passphrase. It can either be a string containing the passphrase, or a custom calback
+#' function that will be called by OpenSSL to read the passphrase. The function should
+#' take one argument (a string with a message) and return a string. The default is to
+#' use \code{readline} which will prompt the user in an interactive R session.
+#'
+#' @export
+#' @param file Either a path to a file, a connection, or literal data (a string for
+#' pem/ssh format, or a raw vector in der format)
+#' @param password A string or callback function to read protected keys
+#' @param der set to \code{TRUE} if \code{file} is in binary DER format
+#' @return An object of class \code{cert}, \code{key} or \code{pubkey} which holds the data
+#' in binary DER format and can be decomposed using \code{as.list}.
+#' @rdname read_key
+#' @seealso \link{download_ssl_cert}
+#' @examples \dontrun{# Read private key
+#' key <- read_key("~/.ssh/id_rsa")
+#' str(key)
+#'
+#' # Read public key
+#' pubkey <- read_pubkey("~/.ssh/id_rsa.pub")
+#' str(pubkey)
+#'
+#' # Read certificates
+#' txt <- readLines("https://curl.haxx.se/ca/cacert.pem")
+#' bundle <- read_cert_bundle(txt)
+#' print(bundle)
+#' }
+read_key <- function(file, password = askpass, der = is.raw(file)){
+ buf <- read_input(file)
+ key <- if(isTRUE(der)){
+ parse_der_key(buf)
+ } else if(length(grepRaw("BEGIN OPENSSH PRIVATE KEY", buf, fixed = TRUE))){
+ stop("OpenSSL does not support them fancy OPENSSH bcrypt/ed25519 keys")
+ } else if(is_pubkey_str(buf)){
+ stop("Input is a public key. Use read_pubkey() to read")
+ } else {
+ names <- pem_names(buf)
+ if(!length(names) || !any(nchar(names) > 0))
+ stop("Failed to parse private key PEM file")
+ if(any(grepl("PUBLIC", names)))
+ stop("Input is a public key. Use read_pubkey() to read")
+ if(any(grepl("CERTIFICATE", names)))
+ stop("Input is a certificate. Use read_cert() to read.")
+ if(!any(grepl("PRIVATE", names)))
+ stop("Invalid input: ", names)
+ parse_pem_key(buf, password)
+ }
+ structure(key, class = c("key", pubkey_type(derive_pubkey(key))))
+}
+
+#' @export
+#' @rdname read_key
+read_pubkey <- function(file, der = is.raw(file)){
+ if(inherits(file, "key") || inherits(file, "cert"))
+ return(as.list(file)$pubkey)
+ if(is_pubkey_str(file))
+ file <- textConnection(file)
+ buf <- read_input(file)
+ key <- if(isTRUE(der)){
+ parse_der_pubkey(buf)
+ } else if(length(grepRaw("BEGIN SSH2 PUBLIC KEY", buf, fixed = TRUE))){
+ parse_ssh_pem(buf)
+ } else if(is_pubkey_str(buf)){
+ parse_openssh(buf)
+ } else {
+ names <- pem_names(buf)
+ if(!length(names) || !any(nchar(names) > 0)){
+ stop("Failed to parse pubkey PEM file")
+ } else if(any(grepl("RSA PUBLIC KEY", names))){
+ parse_legacy_pubkey(buf)
+ } else if(any(grepl("PUBLIC", names))){
+ parse_pem_pubkey(buf)
+ } else if(any(grepl("PRIVATE|PARAMETERS", names))){
+ derive_pubkey(read_key(buf, der = FALSE))
+ } else if(any(grepl("CERTIFICATE", names))){
+ cert_pubkey(parse_pem_cert(buf))
+ } else {
+ stop("Invalid PEM type: ", names)
+ }
+ }
+ if(is.null(attr(key, "class")))
+ class(key) <- c("pubkey", pubkey_type(key))
+ key
+}
+
+#' @export
+#' @rdname read_key
+read_cert <- function(file, der = is.raw(file)){
+ buf <- read_input(file)
+ cert <- if(der){
+ parse_der_cert(buf)
+ } else {
+ parse_pem_cert(buf)
+ }
+ structure(cert, class = "cert")
+}
+
+#' @export
+#' @rdname read_key
+read_cert_bundle <- function(file){
+ buf <- read_input(file)
+ lapply(split_pem(buf), read_cert)
+}
+
+read_input <- function(x){
+ if(is.raw(x)){
+ x
+ } else if(inherits(x, "connection")){
+ if(summary(x)$text == "text") {
+ charToRaw(paste(readLines(x), collapse = "\n"))
+ } else {
+ out <- raw();
+ while(length(buf <- readBin(x, raw(), 1e6))){
+ out <- c(out, buf)
+ }
+ out
+ }
+ } else if(is.character(x) && length(x) == 1 && !grepl("\n", x) && !is_pubkey_str(x)){
+ x <- normalizePath(path.expand(x), mustWork = TRUE)
+ info <- file.info(x)
+ stopifnot(!info$isdir)
+ readBin(x, raw(), info$size)
+ } else if(is.character(x)) {
+ charToRaw(paste(x, collapse = "\n"))
+ } else {
+ stop("file must be connection, raw vector or file path")
+ }
+}
+
+#' The `read_pem` function parses the PEM file into a header and a data payload. It
+#' is mostly useful for debugging.
+#' @export
+#' @rdname read_key
+read_pem <- function(file){
+ buf <- read_input(file)
+ out <- parse_pem(buf)
+ data <- lapply(out, `[[`, "data")
+ names <- vapply(out, `[[`, character(1), "name")
+ structure(data, names = names)
+}
+
+#' @useDynLib openssl R_parse_pem
+parse_pem <- function(input){
+ stopifnot(is.raw(input))
+ out <- .Call(R_parse_pem, input)
+ lapply(out, structure, names = c("name", "header", "data"))
+}
+
+pem_names <- function(input){
+ out <- parse_pem(input)
+ vapply(out, `[[`, character(1), "name")
+}
+
+#' @useDynLib openssl R_parse_pem_key
+parse_pem_key <- function(buf, password = readline){
+ .Call(R_parse_pem_key, buf, password)
+}
+
+#' @useDynLib openssl R_parse_der_key
+parse_der_key <- function(buf){
+ .Call(R_parse_der_key, buf)
+}
+
+#' @useDynLib openssl R_parse_pem_pubkey
+parse_pem_pubkey <- function(buf){
+ .Call(R_parse_pem_pubkey, buf)
+}
+
+#' @useDynLib openssl R_parse_pem_pkcs1
+parse_legacy_pubkey <- function(buf){
+ # It is a common problem that clients add the wrong header
+ tryCatch({
+ .Call(R_parse_pem_pkcs1, buf)
+ }, error = function(e){
+ out <- gsub("RSA PUBLIC", "PUBLIC", rawToChar(buf), fixed = TRUE)
+ parse_pem_pubkey(charToRaw(out))
+ })
+}
+
+#' @useDynLib openssl R_parse_der_pubkey
+parse_der_pubkey <- function(buf){
+ .Call(R_parse_der_pubkey, buf)
+}
+
+#' @useDynLib openssl R_parse_pem_cert
+parse_pem_cert <- function(buf, password){
+ .Call(R_parse_pem_cert, buf)
+}
+
+#' @useDynLib openssl R_parse_der_cert
+parse_der_cert <- function(buf){
+ .Call(R_parse_der_cert, buf)
+}
+
+#' @useDynLib openssl R_derive_pubkey
+derive_pubkey <- function(key){
+ pk <- .Call(R_derive_pubkey, key)
+ structure(pk, class = c("pubkey", class(key)[2]))
+}
+
+#' @useDynLib openssl R_cert_pubkey
+cert_pubkey <- function(cert){
+ pubkey <- .Call(R_cert_pubkey, cert)
+ type <- pubkey_type(pubkey)
+ structure(pubkey, class = c("pubkey", type))
+}
+
+# Detect openssh2 public key strings
+is_pubkey_str <- function(str){
+ if(is.character(str))
+ str <- charToRaw(paste(str, collapse = "\n"))
+ as.logical(length(grepRaw("^(ssh|ecdsa)-[a-z0-9-]+\\s+", str, ignore.case = TRUE)))
+}
+
+# Split a pem file with multiple keys/certs
+split_pem <- function(text) {
+ if(is.raw(text))
+ text <- rawToChar(text)
+ pattern <- "(-+BEGIN)(.+?)(-+END)(.+?)(-+)"
+ m <- gregexpr(pattern, text)
+ regmatches(text, m)[[1]]
+}
+
+#' @export
+print.key <- function(x, ...){
+ pk <- derive_pubkey(x)
+ fp <- fingerprint(pk)
+ cat(sprintf("[%d-bit %s private key]\n", pubkey_bitsize(pk), pubkey_type(pk)))
+ cat(sprintf("md5: %s\n", paste(fp, collapse = ":")))
+}
+
+#' @export
+print.pubkey <- function(x, ...){
+ fp <- fingerprint(x)
+ type <- class(x)[2]
+ cat(sprintf("[%d-bit %s public key]\n", pubkey_bitsize(x), pubkey_type(x)))
+ cat(sprintf("md5: %s\n", paste(fp, collapse = ":")))
+}
+
+#' @export
+print.cert <- function(x, ...){
+ subject <- cert_info(x)$subject
+ cname <- regmatches(subject, regexpr("CN ?=[^,]*", subject))
+ cname <- ifelse(length(cname), gsub("CN ?=", "", cname), "")
+ cat(sprintf("[x509 certificate] %s\n", cname))
+ cat(sprintf("md5: %s\n", paste(md5(x), collapse = ":")))
+ cat(sprintf("sha1: %s\n", paste(sha1(x), collapse = ":")))
+}
+
+path_or_raw <- function(x){
+ if(is.raw(x)) return(x)
+ if(is.character(x) && length(x) == 1){
+ path <- normalizePath(x, mustWork = TRUE)
+ bin <- readBin(path, raw(), file.info(path)$size)
+ return(bin)
+ }
+ stop("x must be raw data vector or path to file on disk.")
+}
diff --git a/R/rsa.R b/R/rsa.R
new file mode 100644
index 0000000..42caae9
--- /dev/null
+++ b/R/rsa.R
@@ -0,0 +1,46 @@
+#' Low-level RSA encryption
+#'
+#' Asymmetric encryption and decryption with RSA. Because RSA can only encrypt messages
+#' smaller than the size of the key, it is typically used only for exchanging a random
+#' session-key. This session key is used to encipher arbitrary sized data via a stream
+#' cipher such as \link{aes_cbc}. See \code{\link{encrypt_envelope}} for a high-level
+#' wrappers combining RSA and AES in this way.
+#'
+#' @export
+#' @param data raw vector of max 245 bytes (for 2048 bit keys) with data to encrypt/decrypt
+#' @inheritParams signature_create
+#' @rdname rsa_encrypt
+#' @aliases rsa encrypt
+#' @useDynLib openssl R_rsa_encrypt
+#' @examples # Generate test keys
+#' key <- rsa_keygen()
+#' pubkey <- key$pubkey
+#'
+#' # Encrypt data with AES
+#' tempkey <- rand_bytes(32)
+#' iv <- rand_bytes(16)
+#' blob <- aes_cbc_encrypt(system.file("CITATION"), tempkey, iv = iv)
+#'
+#' # Encrypt tempkey using receivers public RSA key
+#' ciphertext <- rsa_encrypt(tempkey, pubkey)
+#'
+#' # Receiver decrypts tempkey from private RSA key
+#' tempkey <- rsa_decrypt(ciphertext, key)
+#' message <- aes_cbc_decrypt(blob, tempkey, iv)
+#' out <- rawToChar(message)
+rsa_encrypt <- function(data, pubkey = my_pubkey()){
+ pk <- read_pubkey(pubkey)
+ stopifnot(inherits(pk, "rsa"))
+ stopifnot(is.raw(data))
+ .Call(R_rsa_encrypt, data, pk)
+}
+
+#' @useDynLib openssl R_rsa_decrypt
+#' @export
+#' @rdname rsa_encrypt
+rsa_decrypt <- function(data, key = my_key(), password = askpass){
+ sk <- read_key(key, password)
+ stopifnot(inherits(sk, "rsa"))
+ stopifnot(is.raw(data))
+ .Call(R_rsa_decrypt, data, sk)
+}
diff --git a/R/signing.R b/R/signing.R
new file mode 100644
index 0000000..8549946
--- /dev/null
+++ b/R/signing.R
@@ -0,0 +1,63 @@
+#' Signatures
+#'
+#' Sign and verify a message digest. RSA supports both MD5 and SHA signatures
+#' whereas DSA and EC keys only support SHA.
+#'
+#' @export
+#' @rdname signatures
+#' @param data raw data vector or file path for message to be signed.
+#' If \code{hash == NULL} then \code{data} must be a hash string or raw vector.
+#' @param hash the digest function to use. Must be one of \code{\link{md5}},
+#' \code{\link{sha1}}, \code{\link{sha256}}, \code{\link{sha512}} or \code{NULL}.
+#' @param key private key or file path. See \code{\link{read_key}}.
+#' @param pubkey public key or file path. See \code{\link{read_pubkey}}.
+#' @param sig raw vector or file path for the signature data.
+#' @param password string or a function to read protected keys. See \code{\link{read_key}}.
+#' @examples # Generate a keypair
+#' key <- rsa_keygen()
+#' pubkey <- key$pubkey
+#'
+#' # Sign a file
+#' data <- system.file("DESCRIPTION")
+#' sig <- signature_create(data, key = key)
+#' stopifnot(signature_verify(data, sig, pubkey = pubkey))
+#'
+#' # Sign raw data
+#' data <- serialize(iris, NULL)
+#' sig <- signature_create(data, sha256, key = key)
+#' stopifnot(signature_verify(data, sig, sha256, pubkey = pubkey))
+#'
+#' # Sign a hash
+#' md <- md5(data)
+#' sig <- signature_create(md, hash = NULL, key = key)
+#' stopifnot(signature_verify(md, sig, hash = NULL, pubkey = pubkey))
+signature_create <- function(data, hash = sha1, key = my_key(), password = askpass){
+ data <- path_or_raw(data)
+ sk <- read_key(key, password = password)
+ md <- if(is.null(hash)) parse_hash(data) else hash(data)
+ if(!is.raw(md) || !(length(md) %in% c(16, 20, 28, 32, 48, 64)))
+ stop("data must be md5, sha1, or sha2 digest")
+ hash_sign(md, sk)
+}
+
+#' @export
+#' @rdname signatures
+signature_verify <- function(data, sig, hash = sha1, pubkey = my_pubkey()){
+ data <- path_or_raw(data)
+ sig <- path_or_raw(sig)
+ pk <- read_pubkey(pubkey)
+ md <- if(is.null(hash)) parse_hash(data) else hash(data)
+ if(!is.raw(md) || !(length(md) %in% c(16, 20, 28, 32, 48, 64)))
+ stop("data must be md5, sha1, or sha2 digest")
+ hash_verify(md, sig, pk)
+}
+
+#' @useDynLib openssl R_hash_sign
+hash_sign <- function(hash, key){
+ .Call(R_hash_sign, hash, key)
+}
+
+#' @useDynLib openssl R_hash_verify
+hash_verify <- function(hash, sig, pubkey){
+ .Call(R_hash_verify, hash, sig, pubkey)
+}
diff --git a/R/ssh2.R b/R/ssh2.R
new file mode 100644
index 0000000..489f59b
--- /dev/null
+++ b/R/ssh2.R
@@ -0,0 +1,93 @@
+parse_ssh_pem <- function(buf){
+ # extract the ssh2 pubkey text block
+ text <- rawToChar(buf)
+ regex <- "([-]+ BEGIN SSH2 PUBLIC KEY [-]+)(.*?)([-]+ END SSH2 PUBLIC KEY [-]+)"
+ m <- regexpr(regex, text)
+ if(m < 0)
+ stop("Failed to find SSH2 public key header/footer")
+
+ # strip off text headers and comments
+ text <- regmatches(text, m)
+ text <- sub("([-]+ BEGIN SSH2 PUBLIC KEY [-]+)[\\s]*", "", text)
+ text <- sub("([-]+ END SSH2 PUBLIC KEY [-]+)[\\s]*", "", text)
+ text <- sub("Comment(.*?)\\n", "", text)
+
+ # construct the actual key
+ ssh_build(text)
+}
+
+validate_openssh <- function(str){
+ is.character(str) && grepl("^(ssh-dss|ssh-rsa|ssh-ed25519|ecdsa-sha2-nistp\\d+)\\s+", str[1])
+}
+
+parse_openssh <- function(buf){
+ text <- rawToChar(buf)
+ if(!validate_openssh(text))
+ stop("Unsupported ssh key id format: ", substring(text, 1, 15))
+
+ # Extract the base64 part
+ text <- sub("^\\S+\\s+", "", text)
+ text <- regmatches(text, regexpr("^\\S*", text))
+ ssh_build(text)
+}
+
+# parse ssh binary format
+ssh_build <- function(b64text){
+ con <- rawConnection(base64_decode(b64text), open = "rb")
+ on.exit(close(con))
+ out <- list();
+ while(length(size <- readBin(con, 1L, endian = "big"))){
+ if(size == 0) break
+ buf <- readBin(con, raw(), size)
+ stopifnot(length(buf) == size)
+ out <- c(out, list(buf))
+ }
+
+ # extract key format
+ header <- rawToChar(out[[1]])
+ switch(header,
+ "ssh-dss" = dsa_build(out),
+ "ssh-rsa" = rsa_build(out),
+ "ssh-ed25519" = ed25519_build(out),
+ "ecdsa-sha2-nistp256" = ecdsa_build(out),
+ "ecdsa-sha2-nistp384" = ecdsa_build(out),
+ "ecdsa-sha2-nistp521" = ecdsa_build(out),
+ stop("Unsupported keytype: ", header)
+ )
+}
+
+rsa_build <- function(keydata){
+ exp <- keydata[[2]]
+ mod <- keydata[[3]]
+ rsa_pubkey_build(exp, mod)
+}
+
+dsa_build <- function(keydata){
+ p <- keydata[[2]]
+ q <- keydata[[3]]
+ g <- keydata[[4]]
+ y <- keydata[[5]]
+ dsa_pubkey_build(p, q, g, y)
+}
+
+ecdsa_build <- function(keydata){
+ curve_name <- rawToChar(keydata[[2]])
+ nist_name <- switch(curve_name,
+ "nistp256" = "P-256",
+ "nistp384" = "P-384",
+ "nistp521" = "P-521",
+ stop("Unsupported curve type: ", curve_name)
+ );
+ ec_point <- keydata[[3]]
+ if(ec_point[1] != 0x04)
+ stop("Invalid ecdsa format (not uncompressed?)")
+ ec_point <- ec_point[-1];
+ curve_size <- length(ec_point)/2
+ x <- utils::head(ec_point, curve_size)
+ y <- utils::tail(ec_point, curve_size)
+ ecdsa_pubkey_build(x, y, nist_name)
+}
+
+ed25519_build <- function(keydata){
+ structure(keydata[[2]], class = c("pubkey", "ed25519"))
+}
diff --git a/R/stream.R b/R/stream.R
new file mode 100644
index 0000000..08dd34f
--- /dev/null
+++ b/R/stream.R
@@ -0,0 +1,36 @@
+#' @useDynLib openssl R_md_init
+md_init <- function(algo){
+ .Call(R_md_init, as.character(algo))
+}
+
+#' @useDynLib openssl R_md_feed
+md_feed <- function(md, data){
+ stopifnot(inherits(md, "md"))
+ stopifnot(is.raw(data))
+ .Call(R_md_feed, md, data)
+}
+
+#' @useDynLib openssl R_md_final
+md_final <- function(md){
+ stopifnot(inherits(md, "md"))
+ .Call(R_md_final, md)
+}
+
+#' @useDynLib openssl R_hmac_init
+hmac_init <- function(algo, key){
+ .Call(R_hmac_init, as.character(algo), key)
+}
+
+#' @useDynLib openssl R_hmac_feed
+hmac_feed <- function(ptr, data){
+ stopifnot(inherits(ptr, "md"))
+ stopifnot(is.raw(data))
+ .Call(R_hmac_feed, ptr, data)
+}
+
+#' @useDynLib openssl R_hmac_final
+hmac_final <- function(md){
+ stopifnot(inherits(md, "md"))
+ .Call(R_hmac_final, md)
+}
+
diff --git a/R/write.R b/R/write.R
new file mode 100644
index 0000000..50dd41a
--- /dev/null
+++ b/R/write.R
@@ -0,0 +1,65 @@
+#' Export key or certificate
+#'
+#' The \code{write_pem} functions exports a key or certificate to the standard
+#' base64 PEM format. For private keys it is possible to set a password.
+#'
+#' @export
+#' @param x a public/private key or certificate object
+#' @param password string or callback function to set password (only applicable for
+#' private keys).
+#' @param path file to write to. If \code{NULL} it returns the output as a string.
+#' @rdname write_pem
+write_pem <- function(x, path = NULL, password = NULL){
+ str <- pem_export(x, password)
+ if(is.null(path)) return(str)
+ writeLines(str, path)
+ invisible(path)
+}
+
+#' @export
+#' @rdname write_pem
+write_der <- function(x, path = NULL){
+ bin <- der_export(x)
+ if(is.null(path)) return(bin)
+ writeBin(unclass(bin), path)
+ invisible(path)
+}
+
+pem_export <- function(x, ...){
+ UseMethod("pem_export")
+}
+
+der_export <- function(x, ...){
+ UseMethod("der_export")
+}
+
+#' @useDynLib openssl R_pem_write_key
+pem_export.key <- function(x, password, ...){
+ if(is.function(password))
+ password <- password("Enter new passphrase (or hit ENTER for no password): ")
+ stopifnot(is.character(password) || is.null(password))
+ .Call(R_pem_write_key, x, password)
+}
+
+#' @useDynLib openssl R_pem_write_pubkey
+pem_export.pubkey <- function(x, ...){
+ .Call(R_pem_write_pubkey, x)
+}
+
+
+#' @useDynLib openssl R_pem_write_cert
+pem_export.cert <- function(x, ...){
+ .Call(R_pem_write_cert, x)
+}
+
+der_export.key <- function(x, ...){
+ unclass(x)
+}
+
+der_export.pubkey <- function(x, ...){
+ unclass(x)
+}
+
+der_export.cert <- function(x, ...){
+ unclass(x)
+}
diff --git a/R/writessh.R b/R/writessh.R
new file mode 100644
index 0000000..61f3566
--- /dev/null
+++ b/R/writessh.R
@@ -0,0 +1,22 @@
+#' @export
+#' @rdname write_pem
+#' @param pubkey a public key
+#' @examples # Generate RSA keypair
+#' key <- rsa_keygen()
+#' pubkey <- key$pubkey
+#'
+#' # Write to output formats
+#' write_ssh(pubkey)
+#' write_pem(pubkey)
+#' write_pem(key, password = "super secret")
+write_ssh <- function(pubkey, path = NULL){
+ if(inherits(pubkey, "key"))
+ pubkey <- derive_pubkey(pubkey)
+ if(!inherits(pubkey, "pubkey"))
+ stop("Invalid pubkey file.")
+ str <- as.list(pubkey)$ssh
+ if(is.null(path)) return(str)
+ writeLines(str, path)
+ invisible(path)
+}
+
diff --git a/build/vignette.rds b/build/vignette.rds
new file mode 100644
index 0000000..d885b89
Binary files /dev/null and b/build/vignette.rds differ
diff --git a/cleanup b/cleanup
new file mode 100755
index 0000000..3c020d3
--- /dev/null
+++ b/cleanup
@@ -0,0 +1,2 @@
+#!/bin/sh
+rm -f src/Makevars
diff --git a/configure b/configure
new file mode 100755
index 0000000..ab12978
--- /dev/null
+++ b/configure
@@ -0,0 +1,85 @@
+# Anticonf (tm) script by Jeroen Ooms (2015)
+# This script will query 'pkg-config' for the required cflags and ldflags.
+# If pkg-config is unavailable or does not find the library, try setting
+# INCLUDE_DIR and LIB_DIR manually via e.g:
+# R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib'
+
+# Library settings
+PKG_CONFIG_NAME="openssl"
+PKG_DEB_NAME="libssl-dev"
+PKG_RPM_NAME="openssl-devel"
+PKG_CSW_NAME="libssl_dev"
+PKG_BREW_NAME="openssl at 1.1"
+PKG_TEST_FILE="tools/version.c"
+PKG_LIBS="-lssl -lcrypto"
+PKG_CFLAGS=""
+
+# Use pkg-config if available
+pkg-config ${PKG_CONFIG_NAME} --atleast-version=1.0 2>/dev/null
+if [ $? -eq 0 ]; then
+ PKGCONFIG_CFLAGS=`pkg-config --cflags ${PKG_CONFIG_NAME}`
+ PKGCONFIG_LIBS=`pkg-config --libs ${PKG_CONFIG_NAME}`
+fi
+
+# Note that cflags may be empty in case of success
+if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then
+ echo "Found INCLUDE_DIR and/or LIB_DIR!"
+ PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS"
+ PKG_LIBS="-L$LIB_DIR $PKG_LIBS"
+elif [ "$PKGCONFIG_CFLAGS" ] || [ "$PKGCONFIG_LIBS" ]; then
+ echo "Found pkg-config cflags and libs!"
+ PKG_CFLAGS=${PKGCONFIG_CFLAGS}
+ PKG_LIBS=${PKGCONFIG_LIBS}
+else
+ case "$OSTYPE" in "darwin"*)
+ brew --version 2>/dev/null
+ if [ $? -eq 0 ]; then
+ BREWDIR=`brew --prefix`
+ else
+ BREWDIR="/tmp/homebrew"
+ rm -Rf $BREWDIR
+ mkdir -p $BREWDIR
+ echo "Auto-brewing $PKG_BREW_NAME in $BREWDIR..."
+ curl -fsSL https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C $BREWDIR
+ HOMEBREW_CACHE="/tmp" $BREWDIR/bin/brew install --force-bottle $PKG_BREW_NAME 2>&1 | perl -pe 's/Warning/Note/gi'
+ rm -f $BREWDIR/opt/$PKG_BREW_NAME/lib/*.dylib
+ fi
+ PKG_CFLAGS="-I$BREWDIR/opt/openssl at 1.1/include -I$BREWDIR/opt/openssl/include"
+ PKG_LIBS="-L$BREWDIR/opt/openssl at 1.1/lib -L$BREWDIR/opt/openssl/lib $PKG_LIBS"
+ ;;
+ esac
+fi
+
+# For debugging
+echo "Using PKG_CFLAGS=$PKG_CFLAGS"
+echo "Using PKG_LIBS=$PKG_LIBS"
+
+# Find compiler
+CC=`${R_HOME}/bin/R CMD config CC`
+CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS`
+CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS`
+
+# Test configuration
+${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E ${PKG_TEST_FILE} >/dev/null 2>&1
+
+# Customize the error
+if [ $? -ne 0 ]; then
+ echo "------------------------- ANTICONF ERROR ---------------------------"
+ echo "Configuration failed because $PKG_CONFIG_NAME was not found. Try installing:"
+ echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu, etc)"
+ echo " * rpm: $PKG_RPM_NAME (Fedora, CentOS, RHEL)"
+ echo " * csw: $PKG_CSW_NAME (Solaris)"
+ echo " * brew: $PKG_BREW_NAME (Mac OSX)"
+ echo "If $PKG_CONFIG_NAME is already installed, check that 'pkg-config' is in your"
+ echo "PATH and PKG_CONFIG_PATH contains a $PKG_CONFIG_NAME.pc file. If pkg-config"
+ echo "is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:"
+ echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'"
+ echo "--------------------------------------------------------------------"
+ exit 1;
+fi
+
+# Write to Makevars
+sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars
+
+# Success
+exit 0
diff --git a/configure.win b/configure.win
new file mode 100755
index 0000000..e69de29
diff --git a/debian/README.test b/debian/README.test
deleted file mode 100644
index 8d70ca3..0000000
--- a/debian/README.test
+++ /dev/null
@@ -1,9 +0,0 @@
-Notes on how this package can be tested.
-────────────────────────────────────────
-
-This package can be tested by running the provided test:
-
-cd tests
-LC_ALL=C R --no-save < testthat.R
-
-in order to confirm its integrity.
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 0275147..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,29 +0,0 @@
-r-cran-openssl (0.9.6-1) unstable; urgency=medium
-
- * New upstream version
- * debhelper 10
- * d/watch: version=4
-
- -- Andreas Tille <tille at debian.org> Thu, 05 Jan 2017 17:19:50 +0100
-
-r-cran-openssl (0.9.5-1) unstable; urgency=medium
-
- * New upstream version
- Closes: #828529
- * Convert to dh-r
- * Canonical CRAN homepage
-
- -- Andreas Tille <tille at debian.org> Fri, 28 Oct 2016 13:24:10 +0200
-
-r-cran-openssl (0.9.4-1) unstable; urgency=medium
-
- * New upstream version
- * cme fix dpkg-control
-
- -- Andreas Tille <tille at debian.org> Mon, 27 Jun 2016 11:48:02 +0200
-
-r-cran-openssl (0.9.2-1) unstable; urgency=low
-
- * Initial release (Closes: #819008)
-
- -- Andreas Tille <tille at debian.org> Tue, 22 Mar 2016 21:32:09 +0100
diff --git a/debian/clean b/debian/clean
deleted file mode 100644
index be3bc49..0000000
--- a/debian/clean
+++ /dev/null
@@ -1 +0,0 @@
-src/Makevars
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index f599e28..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-10
diff --git a/debian/control b/debian/control
deleted file mode 100644
index b2b0673..0000000
--- a/debian/control
+++ /dev/null
@@ -1,32 +0,0 @@
-Source: r-cran-openssl
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Andreas Tille <tille at debian.org>
-Section: gnu-r
-Priority: optional
-Build-Depends: debhelper (>= 10),
- dh-r,
- r-base-dev,
- libssl-dev
-Standards-Version: 3.9.8
-Vcs-Browser: https://anonscm.debian.org/viewvc/debian-med/trunk/packages/R/r-cran-openssl/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/R/r-cran-openssl/trunk/
-Homepage: https://cran.r-project.org/package=openssl
-
-Package: r-cran-openssl
-Architecture: any
-Depends: ${misc:Depends},
- ${shlibs:Depends},
- ${R:Depends}
-Recommends: ${R:Recommends}
-Suggests: ${R:Suggests}
-Description: GNU R toolkit for encryption, signatures and certificates based on OpenSSL
- Bindings to OpenSSL libssl and libcrypto, plus custom SSH pubkey
- parsers. Supports RSA, DSA and NIST curves P-256, P-384 and P-521.
- Cryptographic signatures can either be created and verified manually or
- via x509 certificates. AES block cipher is used in CBC mode for
- symmetric encryption; RSA for asymmetric (public key) encryption. High-
- level envelope functions combine RSA and AES for encrypting arbitrary
- sized data. Other utilities include key generators, hash functions (md5,
- sha1, sha256, etc), base64 encoder, a secure random number generator,
- and 'bignum' math methods for manually performing crypto calculations on
- large multibyte integers.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 8504aa7..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,32 +0,0 @@
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Contact: Jeroen Ooms <jeroen.ooms at stat.ucla.edu>
-Source: https://cran.r-project.org/package=openssl
-
-Files: *
-Copyright: 2013-2016 Jeroen Ooms <jeroen.ooms at stat.ucla.edu>,
- Oliver Keyes
-License: MIT
-
-Files: debian/*
-Copyright: 2016 Andreas Tille <tille at debian.org>
-License: MIT
-
-License: MIT
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
- .
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
- .
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/debian/docs b/debian/docs
deleted file mode 100644
index 960011c..0000000
--- a/debian/docs
+++ /dev/null
@@ -1,3 +0,0 @@
-tests
-debian/README.test
-debian/tests/run-unit-test
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index 68d9a36..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/make -f
-
-%:
- dh $@ --buildsystem R
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/tests/control b/debian/tests/control
deleted file mode 100644
index b044b0c..0000000
--- a/debian/tests/control
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests: run-unit-test
-Depends: @, r-cran-testthat
-Restrictions: allow-stderr
diff --git a/debian/tests/run-unit-test b/debian/tests/run-unit-test
deleted file mode 100644
index f1031e6..0000000
--- a/debian/tests/run-unit-test
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh -e
-
-oname=openssl
-pkg=r-cran-`echo $oname | tr [A-Z] [a-z]`
-
-if [ "$ADTTMP" = "" ] ; then
- ADTTMP=`mktemp -d /tmp/${pkg}-test.XXXXXX`
-fi
-cd $ADTTMP
-cp -a /usr/share/doc/${pkg}/tests/* $ADTTMP
-LC_ALL=C R --no-save < testthat.R
-rm -fr $ADTTMP/*
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index 19f7765..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,3 +0,0 @@
-version=4
-http://cran.r-project.org/src/contrib/openssl_([-0-9\.]*).tar.gz
-
diff --git a/inst/cacert.pem b/inst/cacert.pem
new file mode 100644
index 0000000..74e5f52
--- /dev/null
+++ b/inst/cacert.pem
@@ -0,0 +1,4036 @@
+##
+## Bundle of CA Root Certificates
+##
+## Certificate data from Mozilla as of: Wed Sep 14 03:12:05 2016
+##
+## This is a bundle of X.509 certificates of public Certificate Authorities
+## (CA). These were automatically extracted from Mozilla's root certificates
+## file (certdata.txt). This file can be found in the mozilla source tree:
+## http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
+##
+## It contains the certificates in PEM format and therefore
+## can be directly used with curl / libcurl / php_curl, or with
+## an Apache+mod_ssl webserver for SSL client authentication.
+## Just configure this file as the SSLCACertificateFile.
+##
+## Conversion done with mk-ca-bundle.pl version 1.26.
+## SHA256: 01bbf1ecdd693f554ff4dcbe15880b3e6c33188a956c15ff845d313ca69cfeb8
+##
+
+
+GlobalSign Root CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
+GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
+b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
+BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
+VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
+DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
+THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
+Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
+c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
+gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
+AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
+Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
+j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
+hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
+X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
+ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
+s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
+S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
+TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
+ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
+YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
+BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
+9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
+01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
+9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1
+EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc
+cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw
+EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj
+055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f
+j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0
+xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa
+t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+Entrust.net Premium 2048 Secure Server CA
+=========================================
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
+ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
+bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
+BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
+NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
+d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
+ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
+Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
+hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
+nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
+VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
+KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
+T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
+zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
+J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
+nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
+-----END CERTIFICATE-----
+
+Baltimore CyberTrust Root
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
+ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
+ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
+SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
+dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
+uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
+UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
+G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
+XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
+l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
+VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
+BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
+cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
+hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
+Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
+RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+AddTrust Low-Value Services Root
+================================
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU
+cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw
+CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO
+ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6
+54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr
+oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1
+Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui
+GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w
+HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD
+AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT
+RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw
+HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt
+ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph
+iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr
+mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj
+ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+
+AddTrust External Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD
+VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw
+NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU
+cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg
+Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821
++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw
+Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo
+aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy
+2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7
+7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL
+VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk
+VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
+j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355
+e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u
+G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+AddTrust Public Services Root
+=============================
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU
+cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ
+BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l
+dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu
+nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i
+d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG
+Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw
+HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G
+A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G
+A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4
+JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL
++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9
+Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H
+EufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+
+AddTrust Qualified Certificates Root
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU
+cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx
+CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ
+IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx
+64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3
+KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o
+L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR
+wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU
+MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE
+BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y
+azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG
+GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze
+RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB
+iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
+BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
+b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
+A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
+MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
+MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
+Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
+dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
+A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
+Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
+j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
+rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
+MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
+hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
+Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
+v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
+W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
+tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+
+RSA Security 2048 v3
+====================
+-----BEGIN CERTIFICATE-----
+MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK
+ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy
+MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb
+BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7
+Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb
+WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH
+KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP
++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E
+FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY
+v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj
+0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj
+VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395
+nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA
+pKnXwiJPZ9d37CAFYd4=
+-----END CERTIFICATE-----
+
+GeoTrust Global CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw
+MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
+LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo
+BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet
+8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc
+T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU
+vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk
+DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q
+zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4
+d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2
+mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p
+XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
+Mw==
+-----END CERTIFICATE-----
+
+GeoTrust Global CA 2
+====================
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw
+MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
+LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/
+NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k
+LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA
+Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b
+HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH
+K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7
+srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh
+ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL
+OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC
+x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF
+H4z1Ir+rzoPz4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1
+MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu
+Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t
+JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e
+RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs
+7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d
+8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V
+qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga
+Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB
+Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu
+KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08
+ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0
+XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
+hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2
+qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL
+oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK
+xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF
+KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2
+DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK
+xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU
+p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI
+P/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA 2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0
+MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg
+SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0
+DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17
+j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q
+JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a
+QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2
+WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP
+20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn
+ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC
+SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG
+8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2
++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
+BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ
+4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+
+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq
+A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg
+Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP
+pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d
+FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp
+gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
+X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+Visa eCommerce Root
+===================
+-----BEGIN CERTIFICATE-----
+MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG
+EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug
+QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2
+WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm
+VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
+bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL
+F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b
+RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0
+TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI
+/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs
+GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc
+CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW
+YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz
+zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu
+YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
+398znM/jra6O1I7mT1GvFpLgXPYHDw==
+-----END CERTIFICATE-----
+
+Certum Root CA
+==============
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK
+ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla
+Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u
+by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x
+wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL
+kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ
+89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K
+Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P
+NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+
+GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg
+GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/
+0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS
+qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
+
+Comodo AAA Services root
+========================
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
+MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
+c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
+BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
+C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
+i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
+Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
+Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
+Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
+BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
+cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
+LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
+7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
+8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
+12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+Comodo Secure Services root
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw
+MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu
+Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi
+BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP
+9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc
+rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC
+oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V
+p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E
+FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
+gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj
+YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm
+aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm
+4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL
+DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw
+pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H
+RR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+
+Comodo Trusted Services root
+============================
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw
+MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h
+bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw
+IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7
+3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y
+/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6
+juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS
+ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud
+DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp
+ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl
+cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw
+uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA
+BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l
+R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O
+9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+
+QuoVadis Root CA
+================
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE
+ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz
+MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp
+cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD
+EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk
+J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL
+F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL
+YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen
+AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w
+PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y
+ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7
+MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj
+YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
+ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW
+Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu
+BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw
+FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6
+tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo
+fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul
+LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x
+gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi
+5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi
+5nrQNiOKSnQ2+Q==
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 2
+==================
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 3
+==================
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+
+Security Communication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
+8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
+DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
+5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
+DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
+JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
+0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
+mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
+s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
+6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
+FL39vmwLAw==
+-----END CERTIFICATE-----
+
+Sonera Class 2 Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
+U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw
+NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
+IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3
+/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT
+dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG
+f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P
+tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH
+nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT
+XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt
+0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI
+cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph
+Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx
+EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
+llpwrN9M
+-----END CERTIFICATE-----
+
+UTN USERFirst Hardware Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd
+BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx
+OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0
+eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz
+ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI
+wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd
+tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8
+i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf
+Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw
+gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF
+lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF
+UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF
+BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW
+XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2
+lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn
+iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67
+nfhmqA==
+-----END CERTIFICATE-----
+
+Camerfirma Chambers of Commerce Root
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
+ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx
+NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp
+cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn
+MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC
+AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU
+xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH
+NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW
+DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV
+d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud
+EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v
+cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P
+AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh
+bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD
+VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi
+fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD
+L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN
+UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n
+ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1
+erfutGWaIZDgqtCYvDi1czyL+Nw=
+-----END CERTIFICATE-----
+
+Camerfirma Global Chambersign Root
+==================================
+-----BEGIN CERTIFICATE-----
+MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
+ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx
+NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt
+YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg
+MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw
+ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J
+1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O
+by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl
+6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c
+8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/
+BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j
+aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B
+Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj
+aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y
+ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
+bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA
+PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y
+gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ
+PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4
+IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes
+t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
+-----END CERTIFICATE-----
+
+XRamp Global CA Root
+====================
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
+BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
+dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
+HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
+U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
+IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
+foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
+zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
+AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
+xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
+oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
+AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
+/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
+nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
+8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+Go Daddy Class 2 CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
+VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
+A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
+RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
+ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
+2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
+qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
+YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
+vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
+BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
+atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
+MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
+PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
+I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
+Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
+vZ8=
+-----END CERTIFICATE-----
+
+Starfield Class 2 CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
+U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
+MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
+A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
+SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
+bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
+JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
+epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
+F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
+MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
+hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
+bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
+afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
+PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
+KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
+QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority
+================================
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
+NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
+37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj
+YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH
+AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw
+Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg
+U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5
+LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh
+cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT
+dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC
+AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh
+3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm
+vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk
+fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3
+fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ
+EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl
+1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/
+lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro
+g14=
+-----END CERTIFICATE-----
+
+Taiwan GRCA
+===========
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG
+EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X
+DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv
+dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN
+w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5
+BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O
+1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO
+htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov
+J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7
+Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t
+B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB
+O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8
+lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV
+HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2
+09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
+TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj
+Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2
+Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU
+D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz
+DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk
+Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk
+7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ
+CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy
++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS
+-----END CERTIFICATE-----
+
+Swisscom Root CA 1
+==================
+-----BEGIN CERTIFICATE-----
+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
+NY6E0F/6MBr1mmz0DlP5OlvRHA==
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
+MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
+9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
+UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
+/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
+oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
+GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
+66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
+hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
+EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
+SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
+8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+DigiCert Global Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
+MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
+TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
+BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
+4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
+7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
+o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
+8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
+BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
+EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
+tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
+UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+DigiCert High Assurance EV Root CA
+==================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
+KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
+MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
+MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
+Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
+Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
+OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
+MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
+NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
+h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
+Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
+JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
+V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
+myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
+mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
+-----END CERTIFICATE-----
+
+Certplus Class 2 Primary CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE
+BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN
+OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy
+dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR
+5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ
+Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO
+YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e
+e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME
+CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ
+YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t
+L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD
+P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R
+TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+
+7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW
+//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
+l7+ijrRU
+-----END CERTIFICATE-----
+
+DST Root CA X3
+==============
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
+ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
+DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
+cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
+rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
+UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
+xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
+utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
+MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
+dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
+GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
+RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
+fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+
+DST ACES CA X6
+==============
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT
+MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha
+MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE
+CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI
+DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa
+pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow
+GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy
+MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu
+Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy
+dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU
+CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2
+5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t
+Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
+nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs
+vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3
+oKfN5XozNmr6mis=
+-----END CERTIFICATE-----
+
+SwissSign Gold CA - G2
+======================
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+
+SwissSign Silver CA - G2
+========================
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx
+CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ
+cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN
+b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9
+nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge
+RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt
+tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI
+hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K
+Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN
+NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa
+Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
+1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+
+thawte Primary Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3
+MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg
+SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv
+KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT
+FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs
+oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ
+1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc
+q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K
+aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p
+afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF
+AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
+uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89
+jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH
+z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G5
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
+biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
+dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
+j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
+Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
+Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
+fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
+Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
+SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
+KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
+Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
+ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+
+SecureTrust CA
+==============
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
+dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
+BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
+OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
+DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
+GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
+01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
+ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
+aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
+SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
+mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
+nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
+-----END CERTIFICATE-----
+
+Secure Global CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
+bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
+MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
+Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
+YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
+bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
+8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
+HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
+0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
+oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
+MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
+CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
+3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
+-----END CERTIFICATE-----
+
+COMODO Certification Authority
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
+BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
+A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
+MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
+T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
+xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
+4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
+1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
+rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
+b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
+AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
+OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
+IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
+-----END CERTIFICATE-----
+
+Network Solutions Certificate Authority
+=======================================
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
+EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr
+IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx
+MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx
+jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT
+aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT
+crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc
+/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB
+AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv
+bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA
+A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q
+4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/
+GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
+ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
+-----END CERTIFICATE-----
+
+WellsSecure Public Root Certificate Authority
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM
+F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw
+NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN
+MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl
+bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD
+VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1
+iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13
+i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8
+bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB
+K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB
+AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu
+cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm
+lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB
+i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww
+GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI
+K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0
+bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj
+qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es
+E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ
+tylv2G0xffX8oRAHh84vWdw+WNs=
+-----END CERTIFICATE-----
+
+COMODO ECC Certification Authority
+==================================
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
+R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
+ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
+GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
+4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
+wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
+FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
+U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
+
+IGC/A
+=====
+-----BEGIN CERTIFICATE-----
+MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD
+VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE
+Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy
+MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI
+EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT
+STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2
+TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW
+So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy
+HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd
+frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ
+tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB
+egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC
+iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK
+q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q
+MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg
+Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI
+lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF
+0mBWWg==
+-----END CERTIFICATE-----
+
+Security Communication EV RootCA1
+=================================
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh
+dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE
+BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl
+Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO
+/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX
+WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z
+ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4
+bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK
+9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm
+iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG
+Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW
+mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW
+T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
+-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GA CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE
+BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG
+A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH
+bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD
+VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw
+IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5
+IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9
+Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg
+Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD
+d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ
+/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R
+LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm
+MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4
++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY
+okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=
+-----END CERTIFICATE-----
+
+Microsec e-Szigno Root CA
+=========================
+-----BEGIN CERTIFICATE-----
+MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE
+BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL
+EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0
+MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz
+dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT
+GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG
+d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N
+oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc
+QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ
+PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb
+MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG
+IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD
+VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3
+LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A
+dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn
+AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA
+4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg
+AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA
+egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6
+Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO
+PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv
+c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h
+cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw
+IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT
+WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV
+MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER
+MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp
+Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal
+HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT
+nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE
+aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a
+86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK
+yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB
+S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU=
+-----END CERTIFICATE-----
+
+Certigna
+========
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
+EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
+MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
+Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
+XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
+GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
+ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
+DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
+Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
+tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
+BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
+SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
+hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
+PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
+1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
+WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
+-----END CERTIFICATE-----
+
+Deutsche Telekom Root CA 2
+==========================
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT
+RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG
+A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5
+MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G
+A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS
+b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5
+bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI
+KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY
+AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK
+Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV
+jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV
+HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr
+E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy
+zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8
+rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G
+dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
+Cm26OWMohpLzGITY+9HPBVZkVw==
+-----END CERTIFICATE-----
+
+Cybertrust Global Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li
+ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4
+MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD
+ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW
+0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL
+AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin
+89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT
+8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2
+MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G
+A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO
+lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi
+5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2
+hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T
+X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
+WL1WMRJOEcgh4LMRkWXbtKaIOM5V
+-----END CERTIFICATE-----
+
+ePKI Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
+EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
+MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
+MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
+IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
+lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
+qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
+12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
+WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
+lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
+vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
+Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
+MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
+ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
+1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
+KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
+xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
+NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
+GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
+xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
+gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
+sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
+BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
+-----END CERTIFICATE-----
+
+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
+=============================================================================================================================
+-----BEGIN CERTIFICATE-----
+MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH
+DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q
+aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry
+b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV
+BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg
+S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4
+MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl
+IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF
+n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl
+IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft
+dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl
+cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO
+Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1
+xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR
+6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL
+hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd
+BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4
+N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT
+y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh
+LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M
+dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=
+-----END CERTIFICATE-----
+
+Buypass Class 2 CA 1
+====================
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2
+MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
+c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M
+cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83
+0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4
+0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R
+uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P
+AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV
+1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt
+7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2
+fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w
+wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho
+-----END CERTIFICATE-----
+
+EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1
+==========================================================================
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+
+certSIGN ROOT CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
+VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
+Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
+CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
+JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
+rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
+ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
+0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
+AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
+AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
+SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
+x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
+vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
+TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
+-----END CERTIFICATE-----
+
+CNNIC ROOT
+==========
+-----BEGIN CERTIFICATE-----
+MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE
+ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw
+OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD
+o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz
+VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT
+VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or
+czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK
+y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC
+wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S
+lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5
+Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM
+O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8
+BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2
+G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m
+mxE=
+-----END CERTIFICATE-----
+
+ApplicationCA - Japanese Government
+===================================
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT
+SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw
+MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl
+cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4
+fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN
+wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE
+jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu
+nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU
+WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV
+BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD
+vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs
+o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g
+/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD
+io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW
+dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL
+rosot4LKGAfmt1t06SAZf7IbiVQ=
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G3
+=============================================
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
+NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
+YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
+LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
+K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
+c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
+IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
+dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
+2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
+cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
+Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
+t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G2
+===========================
+-----BEGIN CERTIFICATE-----
+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC
+VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu
+IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg
+Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV
+MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG
+b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt
+IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS
+LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5
+8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
+mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN
+G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K
+rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G3
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w
+ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
+d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD
+VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG
+A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At
+P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC
++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY
+7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW
+vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ
+KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK
+A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC
+8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm
+er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G2
+=============================================
+-----BEGIN CERTIFICATE-----
+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1
+OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
+MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl
+b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG
+BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc
+KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+
+EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m
+ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2
+npaqBA+K
+-----END CERTIFICATE-----
+
+VeriSign Universal Root Certification Authority
+===============================================
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
+IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj
+1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP
+MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72
+9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I
+AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR
+tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G
+CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O
+a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3
+Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx
+Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx
+P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P
+wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4
+mJO37M2CYfE45k+XmCpajQ==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G4
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC
+VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
+b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz
+ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
+cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
+b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8
+Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz
+rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw
+HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u
+Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD
+A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx
+AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
+-----END CERTIFICATE-----
+
+NetLock Arany (Class Gold) Főtanúsítvány
+============================================
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
+A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
+dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
+cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
+MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
+ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
+c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
+0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
+/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
+H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
+fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
+neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
+qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
+YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
+bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
+NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
+dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA - G2
+==================================
+-----BEGIN CERTIFICATE-----
+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
+66+KAQ==
+-----END CERTIFICATE-----
+
+Juur-SK
+=======
+-----BEGIN CERTIFICATE-----
+MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA
+c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw
+DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG
+SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy
+aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf
+TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC
++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw
+UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa
+Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF
+MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD
+HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh
+AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA
+cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr
+AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw
+cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
+FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G
+A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo
+ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL
+abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678
+IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh
+Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2
+yyqcjg==
+-----END CERTIFICATE-----
+
+Hongkong Post Root CA 1
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT
+DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx
+NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n
+IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1
+ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr
+auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh
+qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY
+V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV
+HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i
+h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio
+l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei
+IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps
+T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT
+c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==
+-----END CERTIFICATE-----
+
+SecureSign RootCA11
+===================
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi
+SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS
+b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw
+KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1
+cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL
+TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO
+wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq
+g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP
+O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA
+bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX
+t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh
+OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r
+bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ
+Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01
+y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061
+lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=
+-----END CERTIFICATE-----
+
+ACEDICOM Root
+=============
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+
+Microsec e-Szigno Root CA 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
+MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
+c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
+dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
+BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
+U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
+fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
+0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
+pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
+1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
+AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
+QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
+FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
+lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
+I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
+tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
+yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
+LXpUq3DDfSJlgnCW
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R3
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
+iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
+0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
+rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
+OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
+xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
+lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
+EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
+bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
+YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
+kpeDMdmztcpHWD9f
+-----END CERTIFICATE-----
+
+Autoridad de Certificacion Firmaprofesional CIF A62634068
+=========================================================
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
+BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
+QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
+NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
+Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
+B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
+7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
+ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
+plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
+MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
+LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
+bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
+vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
+EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
+DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
+cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
+bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
+ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
+51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
+R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
+T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
+Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
+osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
+crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
+saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
+KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
+6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
+-----END CERTIFICATE-----
+
+Izenpe.com
+==========
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+
+Chambers of Commerce Root - 2008
+================================
+-----BEGIN CERTIFICATE-----
+MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
+Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
+ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
+EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
+cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
+XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
+h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
+ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
+NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
+D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
+lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
+0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
+ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
+EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
+G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
+BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
+bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
+bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
+CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
+AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
+wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
+3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
+RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
+M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
+YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
+9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
+zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
+nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
+OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
+-----END CERTIFICATE-----
+
+Global Chambersign Root - 2008
+==============================
+-----BEGIN CERTIFICATE-----
+MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
+NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
+Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
+QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
+aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
+VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
+XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
+ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
+/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
+TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
+H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
+Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
+HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
+wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
+AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
+BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
+BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
+aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
+aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
+1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
+dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
+/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
+ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
+dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
+9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
+foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
+qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
+P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
+c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
+09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
+-----END CERTIFICATE-----
+
+Go Daddy Root Certificate Authority - G2
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
+MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
+A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
+9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
+fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
+NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
+BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
+vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
+5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
+N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
+-----END CERTIFICATE-----
+
+Starfield Root Certificate Authority - G2
+=========================================
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
+eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
+DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
+VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
+W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
+bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
+N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
+ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
+JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
+TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
+4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
+F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
+c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+
+Starfield Services Root Certificate Authority - G2
+==================================================
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
+IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
+BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
+dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
+h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
+hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
+LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
+rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
+SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
+E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
+xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
+YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
+-----END CERTIFICATE-----
+
+AffirmTrust Commercial
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
+MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
+DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
+C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
+BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
+MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
+HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
+hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
+qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
+0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
+sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+
+AffirmTrust Networking
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
+MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
+Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
+dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
+/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
+h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
+HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
+UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
+12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
+WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
+/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+
+AffirmTrust Premium
+===================
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
+OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
+dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
+BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
+5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
+GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
+p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
+S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
+6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
+/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
+MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
+6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
+L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
+BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
+IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
+g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
+zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+
+AffirmTrust Premium ECC
+=======================
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
+BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
+MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
+cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
+N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
+BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
+BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
+57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
+eQ==
+-----END CERTIFICATE-----
+
+Certum Trusted Network CA
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
+ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
+MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
+ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
+l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
+J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
+fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
+cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
+Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
+DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
+jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
+mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
+Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
+-----END CERTIFICATE-----
+
+Certinomis - Autorité Racine
+=============================
+-----BEGIN CERTIFICATE-----
+MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
+Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg
+LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG
+A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw
+JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa
+wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly
+Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw
+2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N
+jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q
+c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC
+lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb
+xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g
+530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna
+4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ
+KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x
+WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva
+R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40
+nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B
+CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv
+JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE
+qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b
+WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE
+wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/
+vgt2Fl43N+bYdJeimUV5
+-----END CERTIFICATE-----
+
+Root CA Generalitat Valenciana
+==============================
+-----BEGIN CERTIFICATE-----
+MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE
+ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290
+IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3
+WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE
+CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2
+F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B
+ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ
+D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte
+JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB
+AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n
+dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB
+ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl
+AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA
+YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy
+AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA
+aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt
+AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA
+YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu
+AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA
+OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0
+dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV
+BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G
+A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S
+b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh
+TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz
+Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63
+NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH
+iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt
++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
+-----END CERTIFICATE-----
+
+TWCA Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
+VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
+EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
+IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
+QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
+oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
+4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
+y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
+9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
+mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
+QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
+T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
+Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
+-----END CERTIFICATE-----
+
+Security Communication RootCA2
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
+dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
+SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
+aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
+3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
+spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
+EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
+QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
+u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
+3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
+tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
+mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
+-----END CERTIFICATE-----
+
+EC-ACC
+======
+-----BEGIN CERTIFICATE-----
+MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE
+BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w
+ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD
+VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE
+CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT
+BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7
+MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt
+SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl
+Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh
+cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK
+w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT
+ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4
+HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a
+E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw
+0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD
+VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0
+Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l
+dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ
+lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa
+Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe
+l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2
+E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D
+5EI=
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions RootCA 2011
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
+O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
+aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
+AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
+IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
+1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
+71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
+8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
+3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
+MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
+b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
+XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
+TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
+/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
+7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
+-----END CERTIFICATE-----
+
+Actalis Authentication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+
+Trustis FPS Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG
+EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290
+IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV
+BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ
+RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk
+H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa
+cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt
+o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA
+AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd
+BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c
+GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC
+yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P
+8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV
+l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl
+iB6XzCGcKQENZetX2fNXlrtIzYE=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority
+================================
+-----BEGIN CERTIFICATE-----
+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
+NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
+37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ
+Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0
+dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu
+c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv
+bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0
+aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t
+L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG
+cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5
+fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm
+N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN
+Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T
+tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX
+e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA
+2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs
+HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib
+D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority G2
+===================================
+-----BEGIN CERTIFICATE-----
+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE
+ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O
+o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG
+4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi
+Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul
+Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs
+O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H
+vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L
+nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS
+FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa
+z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ
+KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk
+J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+
+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG
+/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc
+nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld
+blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc
+l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm
+7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm
+obp573PYtlNXLfbQ4ddI
+-----END CERTIFICATE-----
+
+Buypass Class 2 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
+DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
+g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
+9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
+/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
+CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
+awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
+zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
+Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
+Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
+M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
+A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
+osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
+aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
+DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
+LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
+oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
+wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
+CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
+rJgWVqA=
+-----END CERTIFICATE-----
+
+Buypass Class 3 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
+DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
+sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
+5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
+7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
+ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
+2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
+/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
+RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
+Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
+j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
+cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
+uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
+Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
+ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
+KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
+6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
+UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
+eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
+Cp/HuZc=
+-----END CERTIFICATE-----
+
+T-TeleSec GlobalRoot Class 3
+============================
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
+MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
+9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
+NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
+iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
+0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
+AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
+fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
+ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
+P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
+-----END CERTIFICATE-----
+
+EE Certification Centre Root CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
+EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy
+dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw
+MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB
+UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy
+ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM
+TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2
+rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw
+93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN
+P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ
+MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF
+BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj
+xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM
+lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
+uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU
+3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM
+dcGWxZ0=
+-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 2007
+=================================================
+-----BEGIN CERTIFICATE-----
+MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
+MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
+QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X
+DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl
+a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN
+BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp
+bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N
+YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv
+KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya
+KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT
+rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC
+AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s
+Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I
+aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO
+Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb
+BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK
+poRq0Tl9
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
+Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
+LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
+ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
+BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
+KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
+p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
+AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
+4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
+eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
+MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
+PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
+OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
+2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
+o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
+dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
+X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 EV 2009
+=================================
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
+egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
+zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
+7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
+sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
+11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
+cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
+ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
+MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
+b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
+c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
+PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
+nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
+ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
+NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
+w9y4AyHqnxbxLFS1
+-----END CERTIFICATE-----
+
+PSCProcert
+==========
+-----BEGIN CERTIFICATE-----
+MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk
+ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ
+MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz
+dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl
+cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw
+IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw
+MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w
+DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD
+ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp
+Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC
+wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA
+3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh
+RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO
+EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2
+0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH
+0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU
+td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw
+Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp
+r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/
+AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz
+Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId
+xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp
+ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH
+EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h
+Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k
+ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG
+9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG
+MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG
+LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52
+ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy
+YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v
+Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o
+dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq
+T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN
+g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q
+uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1
+n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn
+FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo
+5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq
+3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5
+poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y
+eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km
+-----END CERTIFICATE-----
+
+China Internet Network Information Center EV Certificates Root
+==============================================================
+-----BEGIN CERTIFICATE-----
+MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV
+BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D
+aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg
+Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG
+A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM
+PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl
+cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y
+jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV
+98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H
+klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23
+KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC
+7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD
+glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5
+0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM
+7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws
+ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0
+5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8=
+-----END CERTIFICATE-----
+
+Swisscom Root CA 2
+==================
+-----BEGIN CERTIFICATE-----
+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
+5OfNeOI5wSsSnqaeG8XmDtkx2Q==
+-----END CERTIFICATE-----
+
+Swisscom Root EV CA 2
+=====================
+-----BEGIN CERTIFICATE-----
+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
+l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc=
+-----END CERTIFICATE-----
+
+CA Disig Root R1
+================
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw
+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
+ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx
+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
+c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy
+3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8
+u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2
+m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk
+CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa
+YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6
+vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL
+LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX
+ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is
+XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ
+04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR
+xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B
+LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM
+CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb
+VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85
+YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS
+ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix
+lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N
+UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ
+a7+h89n07eLw4+1knj0vllJPgFOL
+-----END CERTIFICATE-----
+
+CA Disig Root R2
+================
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
+ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
+c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
+w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
+xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
+A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
+GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
+g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
+5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
+koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
+Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
+Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
+Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
+tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
+sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
+dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
+1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
+mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
+utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
+sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
+UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
+7+ZtsH8tZ/3zbBt1RqPlShfppNcL
+-----END CERTIFICATE-----
+
+ACCVRAIZ1
+=========
+-----BEGIN CERTIFICATE-----
+MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
+SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
+MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
+UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
+jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
+RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
+aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
+0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
+WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
+8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
+5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
+9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
+Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
+Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
+Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
+VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
+Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
+QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
+AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
+YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
+AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
+IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
+aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
+dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
+MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
+hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
+R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
+YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
+nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
+TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
+sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
+I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
+Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
+3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
+EfbRD0tVNEYqi4Y7
+-----END CERTIFICATE-----
+
+TWCA Global Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
+CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
+QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
+EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
+Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
+nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
+r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
+Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
+tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
+KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
+sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
+yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
+kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
+zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
+cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
+LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
+8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
+/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
+lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
+A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
+i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
+EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
+zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
+-----END CERTIFICATE-----
+
+TeliaSonera Root CA v1
+======================
+-----BEGIN CERTIFICATE-----
+MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE
+CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4
+MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW
+VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+
+6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA
+3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k
+B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn
+Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH
+oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3
+F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ
+oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7
+gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc
+TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB
+AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW
+DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm
+zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
+0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW
+pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV
+G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc
+c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT
+JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2
+qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6
+Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems
+WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
+-----END CERTIFICATE-----
+
+E-Tugra Certification Authority
+===============================
+-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w
+DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls
+ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
+ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw
+NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx
+QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl
+cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD
+DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd
+hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K
+CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g
+ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ
+BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0
+E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz
+rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq
+jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
+rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5
+dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB
+/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK
+kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO
+XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807
+VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo
+a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc
+dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV
+KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT
+Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0
+8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G
+C7TbO6Orb1wdtn7os4I07QZcJA==
+-----END CERTIFICATE-----
+
+T-TeleSec GlobalRoot Class 2
+============================
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
+MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
+SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
+vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
+2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
+WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
+YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
+r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
+vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
+3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
+9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
+-----END CERTIFICATE-----
+
+Atos TrustedRoot 2011
+=====================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
+cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
+MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
+A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
+hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
+54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
+HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
+z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
+l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
+bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
+k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
+TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
+61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
+3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 1 G3
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG
+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
+b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN
+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg
+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE
+PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm
+PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6
+Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN
+ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l
+g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV
+7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX
+9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f
+iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg
+t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI
+hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
+MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3
+GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct
+Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP
++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh
+3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa
+wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6
+O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0
+FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV
+hMJKzRwuJIczYOXD
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 2 G3
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG
+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
+b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN
+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg
+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh
+ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY
+NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t
+oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o
+MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l
+V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo
+L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ
+sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD
+6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh
+lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI
+hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
+AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K
+pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9
+x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz
+dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X
+U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw
+mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD
+zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN
+JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr
+O3jtZsSOeWmD3n+M
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 3 G3
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG
+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
+b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN
+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg
+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286
+IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL
+Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe
+6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3
+I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U
+VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7
+5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi
+Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM
+dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt
+rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI
+hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
+KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS
+t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ
+TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du
+DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib
+Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD
+hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX
+0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW
+dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2
+PpxxVJkES/1Y+Zj0
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root G2
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw
+MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH
+35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq
+bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw
+VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP
+YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn
+lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO
+w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv
+0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz
+d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW
+hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M
+jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
+IhNzbM8m9Yop5w==
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root G3
+===========================
+-----BEGIN CERTIFICATE-----
+MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
+VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
+MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ
+BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb
+RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs
+KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF
+UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy
+YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy
+1vUhZscv6pZjamVFkpUBtA==
+-----END CERTIFICATE-----
+
+DigiCert Global Root G2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx
+MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ
+kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO
+3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV
+BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM
+UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB
+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu
+5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr
+F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U
+WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH
+QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/
+iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
+MrY=
+-----END CERTIFICATE-----
+
+DigiCert Global Root G3
+=======================
+-----BEGIN CERTIFICATE-----
+MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD
+VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw
+MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
+aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C
+AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O
+YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp
+Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y
+3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34
+VOKa5Vt8sycX
+-----END CERTIFICATE-----
+
+DigiCert Trusted Root G4
+========================
+-----BEGIN CERTIFICATE-----
+MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw
+HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
+MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp
+pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o
+k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa
+vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
+QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
+MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
+mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7
+f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
+dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8
+oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
+DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
+ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
+ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr
+yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy
+7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah
+ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN
+5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb
+/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa
+5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK
+G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP
+82Z+
+-----END CERTIFICATE-----
+
+WoSign
+======
+-----BEGIN CERTIFICATE-----
+MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG
+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g
+QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ
+BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
+vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO
+CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX
+2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5
+KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR
++ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez
+EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk
+lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2
+8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY
+yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C
+AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R
+8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1
+LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq
+T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj
+y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC
+2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes
+5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/
+EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh
+mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx
+kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi
+kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w==
+-----END CERTIFICATE-----
+
+WoSign China
+============
+-----BEGIN CERTIFICATE-----
+MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG
+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv
+geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD
+VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k
+8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5
+uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85
+dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5
+Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy
+b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc
+76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m
++Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6
+yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX
+GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA
+A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6
+yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY
+r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115
+j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A
+kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97
+qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y
+jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB
+ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv
+T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO
+kI26oQ==
+-----END CERTIFICATE-----
+
+COMODO RSA Certification Authority
+==================================
+-----BEGIN CERTIFICATE-----
+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
+LaZRfyHBNVOFBkpdn627G190
+-----END CERTIFICATE-----
+
+USERTrust RSA Certification Authority
+=====================================
+-----BEGIN CERTIFICATE-----
+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
+Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
+-----END CERTIFICATE-----
+
+USERTrust ECC Certification Authority
+=====================================
+-----BEGIN CERTIFICATE-----
+MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
+0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
+nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
+HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
+HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
+9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
+-----END CERTIFICATE-----
+
+GlobalSign ECC Root CA - R4
+===========================
+-----BEGIN CERTIFICATE-----
+MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl
+OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P
+AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV
+MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF
+JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=
+-----END CERTIFICATE-----
+
+GlobalSign ECC Root CA - R5
+===========================
+-----BEGIN CERTIFICATE-----
+MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
+SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
+h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
+BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
+uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
+yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA - G3
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC
+TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
+ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y
+olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t
+x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy
+EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K
+Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur
+mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5
+1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp
+07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo
+FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE
+41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB
+AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu
+yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD
+U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq
+KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1
+v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA
+8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b
+8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r
+mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq
+1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI
+JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV
+tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk=
+-----END CERTIFICATE-----
+
+Staat der Nederlanden EV Root CA
+================================
+-----BEGIN CERTIFICATE-----
+MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M
+MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl
+cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk
+SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW
+O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r
+0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8
+Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV
+XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr
+08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV
+0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd
+74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx
+fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa
+ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI
+eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu
+c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq
+5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN
+b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN
+f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi
+5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4
+WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK
+DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy
+eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==
+-----END CERTIFICATE-----
+
+IdenTrust Commercial Root CA 1
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
+EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS
+b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES
+MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB
+IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld
+hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/
+mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi
+1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C
+XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl
+3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy
+NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV
+WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg
+xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix
+uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI
+hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
+6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg
+ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt
+ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV
+YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX
+feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro
+kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe
+2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz
+Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R
+cGzM7vRX+Bi6hG6H
+-----END CERTIFICATE-----
+
+IdenTrust Public Sector Root CA 1
+=================================
+-----BEGIN CERTIFICATE-----
+MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG
+EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv
+ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV
+UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS
+b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy
+P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6
+Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI
+rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf
+qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS
+mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn
+ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh
+LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v
+iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL
+4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B
+Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw
+DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
+t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A
+mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt
+GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt
+m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx
+NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4
+Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI
+ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC
+ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ
+3Wl9af0AVqW3rLatt8o+Ae+c
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority - G2
+=========================================
+-----BEGIN CERTIFICATE-----
+MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV
+BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy
+bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug
+b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw
+HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
+DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx
+OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP
+/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz
+HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU
+s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y
+TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx
+AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6
+0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z
+iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
+Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi
+nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+
+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO
+e4pIb4tF9g==
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority - EC1
+==========================================
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn
+YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl
+ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw
+FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs
+LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg
+dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
+IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy
+AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef
+9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h
+vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8
+kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
+-----END CERTIFICATE-----
+
+CFCA EV ROOT
+============
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE
+CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB
+IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw
+MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD
+DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV
+BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD
+7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN
+uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW
+ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7
+xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f
+py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K
+gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol
+hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ
+tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf
+BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
+/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
+ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q
+ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua
+4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG
+E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX
+BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn
+aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy
+PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX
+kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C
+ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
+-----END CERTIFICATE-----
+
+TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5
+=========================================================
+-----BEGIN CERTIFICATE-----
+MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVFIxDzAN
+BgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp
+bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1Qg
+RWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAw
+ODA3MDFaFw0yMzA0MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0w
+SwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnE
+n2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRp
+ZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEApCUZ4WWe60ghUEoI5RHwWrom/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537
+jVJp45wnEFPzpALFp/kRGml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1m
+ep5Fimh34khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z5UNP
+9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0hO8EuPbJbKoCPrZV
+4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QIDAQABo0IwQDAdBgNVHQ4EFgQUVpkH
+HtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAJ5FdnsXSDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPo
+BP5yCccLqh0lVX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq
+URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nfpeYVhDfwwvJl
+lpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CFYv4HAqGEVka+lgqaE9chTLd8
+B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW+qtB4Uu2NQvAmxU=
+-----END CERTIFICATE-----
+
+TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H6
+=========================================================
+-----BEGIN CERTIFICATE-----
+MIIEJjCCAw6gAwIBAgIGfaHyZeyKMA0GCSqGSIb3DQEBCwUAMIGxMQswCQYDVQQGEwJUUjEPMA0G
+A1UEBwwGQW5rYXJhMU0wSwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls
+acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg2MB4XDTEzMTIxODA5
+MDQxMFoXDTIzMTIxNjA5MDQxMFowgbExCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExTTBL
+BgNVBAoMRFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSf
+aSBIaXptZXRsZXJpIEEuxZ4uMUIwQAYDVQQDDDlUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2VydGlm
+aWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLEgSDYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCdsGjW6L0UlqMACprx9MfMkU1xeHe59yEmFXNRFpQJRwXiM/VomjX/3EsvMsew7eKC5W/a
+2uqsxgbPJQ1BgfbBOCK9+bGlprMBvD9QFyv26WZV1DOzXPhDIHiTVRZwGTLmiddk671IUP320EED
+wnS3/faAz1vFq6TWlRKb55cTMgPp1KtDWxbtMyJkKbbSk60vbNg9tvYdDjTu0n2pVQ8g9P0pu5Fb
+HH3GQjhtQiht1AH7zYiXSX6484P4tZgvsycLSF5W506jM7NE1qXyGJTtHB6plVxiSvgNZ1GpryHV
++DKdeboaX+UEVU0TRv/yz3THGmNtwx8XEsMeED5gCLMxAgMBAAGjQjBAMB0GA1UdDgQWBBTdVRcT
+9qzoSCHK77Wv0QAy7Z6MtTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQsFAAOCAQEAb1gNl0OqFlQ+v6nfkkU/hQu7VtMMUszIv3ZnXuaqs6fvuay0EBQNdH49ba3R
+fdCaqaXKGDsCQC4qnFAUi/5XfldcEQlLNkVS9z2sFP1E34uXI9TDwe7UU5X+LEr+DXCqu4svLcsy
+o4LyVN/Y8t3XSHLuSqMplsNEzm61kod2pLv0kmzOLBQJZo6NrRa1xxsJYTvjIKIDgI6tflEATseW
+hvtDmHd9KMeP2Cpu54Rvl0EpABZeTeIT6lnAY2c6RPuY/ATTMHKm9ocJV612ph1jmv3XZch4gyt1
+O6VbuA1df74jrlZVlFjvH4GMKrLN5ptjnhi85WsGtAuYSyher4hYyw==
+-----END CERTIFICATE-----
+
+Certinomis - Root CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
+Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg
+LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx
+EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD
+ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos
+P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo
+d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap
+z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00
+8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x
+RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE
+6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t
+FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV
+PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH
+i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj
+YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I
+6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF
+AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV
+WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw
+Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX
+lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ
+y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9
+Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng
+DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi
+I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM
+cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr
+hkIGuUE=
+-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GB CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG
+EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
+ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw
+MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD
+VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds
+b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX
+scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP
+rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk
+9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o
+Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg
+GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
+hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD
+dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0
+VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui
+HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
+Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
+-----END CERTIFICATE-----
+
+Certification Authority of WoSign G2
+====================================
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQG
+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNVBAMTJENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgx
+CzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPXJYY1kBai
+XW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgOgHzKtB0TiGsOqCR3A9Du
+W/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg9
+5k4ot+vElbGs/V6r+kHLXZ1L3PR8du9nfwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BK
+v0mUYQs4kI9dJGwlezt52eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJKoZI
+hvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8fHulwqZm46qwtyeY
+P0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G3CE4Q3RM+zD4F3LBMvzIkRfEzFg3
+TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yySrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu
++sif/a+RZQp4OBXllxcU3fngLDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS+
+7Q9LGOHSJDy7XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg=
+-----END CERTIFICATE-----
+
+CA WoSign ECC Root
+==================
+-----BEGIN CERTIFICATE-----
+MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQswCQYDVQQGEwJD
+TjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMTEkNBIFdvU2lnbiBFQ0MgUm9v
+dDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQK
+ExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZI
+zj0CAQYFK4EEACIDYgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiU
+t5v8KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES1ns2o0Iw
+QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqv3VWqP2h4syhf3R
+MluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0
+Daupn75OcsqF1NnstTJFGG+rrQIwfcf3aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYu
+a/GRspBl9JrmkO5K
+-----END CERTIFICATE-----
+
+SZAFIR ROOT CA2
+===============
+-----BEGIN CERTIFICATE-----
+MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG
+A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV
+BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ
+BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD
+VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q
+qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK
+DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE
+2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ
+ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi
+ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
+AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC
+AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5
+O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67
+oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul
+4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6
++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
+-----END CERTIFICATE-----
+
+Certum Trusted Network CA 2
+===========================
+-----BEGIN CERTIFICATE-----
+MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE
+BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1
+bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y
+ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ
+TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB
+IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9
+7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o
+CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b
+Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p
+uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130
+GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ
+9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB
+Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye
+hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM
+BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI
+hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW
+Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA
+L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo
+clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM
+pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb
+w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo
+J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm
+ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX
+is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7
+zAYspsbiDrW5viSP
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions RootCA 2015
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT
+BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0
+aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
+YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx
+MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg
+QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV
+BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw
+MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv
+bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh
+iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+
+6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd
+FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr
+i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F
+GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2
+fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu
+iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
+Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI
+hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+
+D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM
+d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y
+d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn
+82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb
+davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F
+Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt
+J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa
+JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q
+p/UsQu0yrbYhnr68
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions ECC RootCA 2015
+===========================================================
+-----BEGIN CERTIFICATE-----
+MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0
+aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
+cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
+aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw
+MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj
+IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD
+VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290
+Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP
+dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK
+Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
+BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA
+GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn
+dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
+-----END CERTIFICATE-----
+
+Certplus Root CA G1
+===================
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUAMD4xCzAJBgNV
+BAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTAe
+Fw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhD
+ZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHN
+r49aiZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt6kuJPKNx
+Qv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP0FG7Yn2ksYyy/yARujVj
+BYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTv
+LRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDEEW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2
+z4QTd28n6v+WZxcIbekN1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc
+4nBvCGrch2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCTmehd
+4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV4EJQeIQEQWGw9CEj
+jy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPOWftwenMGE9nTdDckQQoRb5fc5+R+
+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G
+A1UdDgQWBBSowcCbkahDFXxdBie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHY
+lwuBsTANBgkqhkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh
+66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7/SMNkPX0XtPG
+YX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BSS7CTKtQ+FjPlnsZlFT5kOwQ/
+2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F
+6ALEUz65noe8zDUa3qHpimOHZR4RKttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilX
+CNQ314cnrUlZp5GrRHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWe
+tUNy6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEVV/xuZDDC
+VRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5g4VCXA9DO2pJNdWY9BW/
++mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl++O/QmueD6i9a5jc2NvLi6Td11n0bt3+
+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=
+-----END CERTIFICATE-----
+
+Certplus Root CA G2
+===================
+-----BEGIN CERTIFICATE-----
+MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT
+AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x
+NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0
+cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA
+BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN
+Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD
+AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud
+IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV
+HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl
+vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw==
+-----END CERTIFICATE-----
+
+OpenTrust Root CA G1
+====================
+-----BEGIN CERTIFICATE-----
+MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV
+BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcx
+MB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM
+CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7fa
+Yp6bwiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX/uMftk87
+ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR077F9jAHiOH3BX2pfJLKO
+YheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGPuY4zbGneWK2gDqdkVBFpRGZPTBKnjix9
+xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLxp2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO
+9z0M+Yo0FMT7MzUj8czxKselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq
+3ywgsNw2TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+WG+Oi
+n6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPwvFEVVJSmdz7QdFG9
+URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYYEQRVzXR7z2FwefR7LFxckvzluFqr
+TJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUl0YhVyE12jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/Px
+N3DlCPaTKbYwDQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E
+PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kfgLMtMrpkZ2Cv
+uVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbSFXJfLkur1J1juONI5f6ELlgK
+n0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLh
+X4SPgPL0DTatdrOjteFkdjpY3H1PXlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80
+nR14SohWZ25g/4/Ii+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcm
+GS3tTAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L9109S5zvE/
+bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/KyPu1svf0OnWZzsD2097+o
+4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJAwSQiumPv+i2tCqjI40cHLI5kqiPAlxA
+OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx
+-----END CERTIFICATE-----
+
+OpenTrust Root CA G2
+====================
+-----BEGIN CERTIFICATE-----
+MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUAMEAxCzAJBgNV
+BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcy
+MB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM
+CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+
+Ntmh/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78eCbY2albz
+4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/61UWY0jUJ9gNDlP7ZvyCV
+eYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fEFY8ElggGQgT4hNYdvJGmQr5J1WqIP7wt
+UdGejeBSzFfdNTVY27SPJIjki9/ca1TSgSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz
+3GIZ38i1MH/1PCZ1Eb3XG7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj
+3CzMpSZyYhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaHvGOz
+9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4t/bQWVyJ98LVtZR0
+0dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/gh7PU3+06yzbXfZqfUAkBXKJOAGT
+y3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUajn6QiL35okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59
+M4PLuG53hq8wDQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz
+Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0nXGEL8pZ0keI
+mUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qTRmTFAHneIWv2V6CG1wZy7HBG
+S4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpTwm+bREx50B1ws9efAvSyB7DH5fitIw6mVskp
+EndI2S9G/Tvw/HRwkqWOOAgfZDC2t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ
+6e18CL13zSdkzJTaTkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97kr
+gCf2o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU3jg9CcCo
+SmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eAiN1nE28daCSLT7d0geX0
+YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14fWKGVyasvc0rQLW6aWQ9VGHgtPFGml4vm
+u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK
+-----END CERTIFICATE-----
+
+OpenTrust Root CA G3
+====================
+-----BEGIN CERTIFICATE-----
+MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT
+AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X
+DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w
+ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B
+ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB
+/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf
+BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM
+BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta
+3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB
+-----END CERTIFICATE-----
diff --git a/inst/doc/bignum.R b/inst/doc/bignum.R
new file mode 100644
index 0000000..220cb0a
--- /dev/null
+++ b/inst/doc/bignum.R
@@ -0,0 +1,52 @@
+## ----setup, include=FALSE------------------------------------------------
+library(openssl)
+knitr::opts_chunk$set(echo = TRUE)
+
+## ------------------------------------------------------------------------
+# create a bignum
+y <- bignum("123456789123456789")
+z <- bignum("D41D8CD98F00B204E9800998ECF8427E", hex = TRUE)
+
+# size grows
+print(y * z)
+
+# Basic arithmetic
+div <- z %/% y
+mod <- z %% y
+z2 <- div * y + mod
+stopifnot(z2 == z)
+stopifnot(div < z)
+
+## ------------------------------------------------------------------------
+(key <- rsa_keygen(512))
+(pubkey <- key$pubkey)
+
+## ------------------------------------------------------------------------
+msg <- charToRaw("hello world")
+ciphertext <- rsa_encrypt(msg, pubkey)
+rawToChar(rsa_decrypt(ciphertext, key))
+
+## ------------------------------------------------------------------------
+key$data
+
+## ------------------------------------------------------------------------
+pubkey$data
+
+## ------------------------------------------------------------------------
+m <- bignum(charToRaw("hello world"))
+print(m)
+
+## ------------------------------------------------------------------------
+e <- pubkey$data$e
+n <- pubkey$data$n
+c <- (m ^ e) %% n
+print(c)
+
+## ------------------------------------------------------------------------
+base64_encode(c)
+
+## ------------------------------------------------------------------------
+d <- key$data$d
+out <- bignum_mod_exp(c, d, n)
+rawToChar(out)
+
diff --git a/inst/doc/bignum.Rmd b/inst/doc/bignum.Rmd
new file mode 100644
index 0000000..3693f4d
--- /dev/null
+++ b/inst/doc/bignum.Rmd
@@ -0,0 +1,111 @@
+---
+title: "Fun with bignum: how RSA encryption works"
+date: "`r Sys.Date()`"
+vignette: >
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteIndexEntry{Fun with bignum: how RSA encryption works}
+ \usepackage[utf8]{inputenc}
+output:
+ html_document
+---
+
+```{r setup, include=FALSE}
+library(openssl)
+knitr::opts_chunk$set(echo = TRUE)
+```
+
+
+Primitive types such as `int` or `double` store numbers in exactly one or two bytes, with finite precision. This suffices for most applications, but cryptographic methods require arithmetic on much larger numbers and without loss of precision. Therefore OpenSSL provides a __bignum__ data type which holds arbitrary sized integers and implements all basic arithmetic and comparison operators such as `+`, `-`, `*`, `^`, `%%`, `%/%`, `==`, `!=`, `<`, `<=`, `>` and `>=`.
+
+One special case, the [__modular exponenent__](https://en.wikipedia.org/wiki/Modular_exponentiation) `a^b %% m` can be calculated using `bignum_mod_exp` when `b` is too large for calculating `a^b`.
+
+```{r}
+# create a bignum
+y <- bignum("123456789123456789")
+z <- bignum("D41D8CD98F00B204E9800998ECF8427E", hex = TRUE)
+
+# size grows
+print(y * z)
+
+# Basic arithmetic
+div <- z %/% y
+mod <- z %% y
+z2 <- div * y + mod
+stopifnot(z2 == z)
+stopifnot(div < z)
+```
+
+RSA involves a public key and a private key. The public key should be known by everyone and is used for encrypting messages. Messages encrypted with the public key can only be decrypted in a reasonable amount of time using the private key. In RSA, this asymmetry is based on the practical difficulty of factoring the product of two large prime numbers.
+
+### RSA key generation
+
+An RSA key-pair is generated as follows (adapted from [wikipedia](https://en.wikipedia.org/wiki/RSA_(cryptosystem))):
+
+ - Choose two distinct prime numbers $p$ and $q$. Keep these secret.
+ - Compute the product $n = p*q$. This $n$ value is public and used as the modulus.
+ - Compute $\phi(n) = (p − 1)(q − 1)$.
+ - Choose an integer $e$ smaller than $\phi(n)$ such that $e$ and $\phi(n)$ are coprime. OpenSSL always uses $65537$.
+ - Compute a value for $d$ such that $(d * e)\pmod{\phi(n)} = 1$.
+
+OpenSSL has a key generator that does these things for us.
+
+```{r}
+(key <- rsa_keygen(512))
+(pubkey <- key$pubkey)
+```
+
+Usually we would use `rsa_encrypt` and `rsa_decrypt` to perform the encryption:
+
+```{r}
+msg <- charToRaw("hello world")
+ciphertext <- rsa_encrypt(msg, pubkey)
+rawToChar(rsa_decrypt(ciphertext, key))
+```
+
+Let's look at how this works under the hood.
+
+### How RSA encryption works
+
+The `data` field of the private key extracts the underlying bignum integers:
+
+```{r}
+key$data
+```
+
+You can verify that the equations above hold for this key. The public key is simply a subset of the key which only contains $n$ and $e$:
+
+```{r}
+pubkey$data
+```
+
+In order to encrypt a message into ciphertext we have to treat the message data as an integer. The message cannot be larger than the key size. For example convert the text `hello world` into an integer:
+
+```{r}
+m <- bignum(charToRaw("hello world"))
+print(m)
+```
+
+To encrypt this message $m$ into ciphertext $c$ we calculate $c = m^e\pmod n$. Using the public key from above:
+
+```{r}
+e <- pubkey$data$e
+n <- pubkey$data$n
+c <- (m ^ e) %% n
+print(c)
+```
+
+This is number represents out encrypted message! It is usually exchanged using base64 notation for human readability:
+
+```{r}
+base64_encode(c)
+```
+
+The ciphertext can be decrypted using $d$ from the corresponding private key via $m = c^d \pmod{n}$. Note that `c^d` is too large to calculate directly so we need to use `bignum_mod_exp` instead.
+
+```{r}
+d <- key$data$d
+out <- bignum_mod_exp(c, d, n)
+rawToChar(out)
+```
+
+The only difference with the actual `rsa_encrypt` and `rsa_decrypt` functions is that these add some additional padding to the data.
diff --git a/inst/doc/bignum.html b/inst/doc/bignum.html
new file mode 100644
index 0000000..e7cee61
--- /dev/null
+++ b/inst/doc/bignum.html
@@ -0,0 +1,241 @@
+<!DOCTYPE html>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="pandoc" />
+
+
+
+<meta name="date" content="2016-12-30" />
+
+<title>Fun with bignum: how RSA encryption works</title>
+
+<script src="data:application/x-javascript;base64,LyohIGpRdWVyeSB2MS4xMS4zIHwgKGMpIDIwMDUsIDIwMTUgalF1ZXJ5IEZvdW5kYXRpb24sIEluYy4gfCBqcXVlcnkub3JnL2xpY2Vuc2UgKi8KIWZ1bmN0aW9uKGEsYil7Im9iamVjdCI9PXR5cGVvZiBtb2R1bGUmJiJvYmplY3QiPT10eXBlb2YgbW9kdWxlLmV4cG9ydHM/bW9kdWxlLmV4cG9ydHM9YS5kb2N1bWVudD9iKGEsITApOmZ1bmN0aW9uKGEpe2lmKCFhLmRvY3VtZW50KXRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpO3JldHVybiBiKGEpfTpiKGEpfSgidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdz93aW5kb3c6dG [...]
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<link href="data:text/css;charset=utf-8,html%7Bfont%2Dfamily%3Asans%2Dserif%3B%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A100%25%3B%2Dms%2Dtext%2Dsize%2Dadjust%3A100%25%7Dbody%7Bmargin%3A0%7Darticle%2Caside%2Cdetails%2Cfigcaption%2Cfigure%2Cfooter%2Cheader%2Chgroup%2Cmain%2Cmenu%2Cnav%2Csection%2Csummary%7Bdisplay%3Ablock%7Daudio%2Ccanvas%2Cprogress%2Cvideo%7Bdisplay%3Ainline%2Dblock%3Bvertical%2Dalign%3Abaseline%7Daudio%3Anot%28%5Bcontrols%5D%29%7Bdisplay%3Anone%3Bheight%3A0%7D%5Bhidden%5D%2Ctem [...]
+<script src="data:application/x-javascript;base64,LyohCiAqIEJvb3RzdHJhcCB2My4zLjUgKGh0dHA6Ly9nZXRib290c3RyYXAuY29tKQogKiBDb3B5cmlnaHQgMjAxMS0yMDE1IFR3aXR0ZXIsIEluYy4KICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlCiAqLwppZigidW5kZWZpbmVkIj09dHlwZW9mIGpRdWVyeSl0aHJvdyBuZXcgRXJyb3IoIkJvb3RzdHJhcCdzIEphdmFTY3JpcHQgcmVxdWlyZXMgalF1ZXJ5Iik7K2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0Ijt2YXIgYj1hLmZuLmpxdWVyeS5zcGxpdCgiICIpWzBdLnNwbGl0KCIuIik7aWYoYlswXTwyJiZiWzFdPDl8fDE9PWJbMF0mJjk9PWJbMV0mJmJbMl08MSl0aHJvdy [...]
+<script src="data:application/x-javascript;base64,LyoqCiogQHByZXNlcnZlIEhUTUw1IFNoaXYgMy43LjIgfCBAYWZhcmthcyBAamRhbHRvbiBAam9uX25lYWwgQHJlbSB8IE1JVC9HUEwyIExpY2Vuc2VkCiovCi8vIE9ubHkgcnVuIHRoaXMgY29kZSBpbiBJRSA4CmlmICghIXdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKCJNU0lFIDgiKSkgewohZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYil7dmFyIGM9YS5jcmVhdGVFbGVtZW50KCJwIiksZD1hLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJoZWFkIilbMF18fGEuZG9jdW1lbnRFbGVtZW50O3JldHVybiBjLmlubmVySFRNTD0ieDxzdHlsZT4iK2IrIjwvc3R5bGU+IixkLm [...]
+<script src="data:application/x-javascript;base64,LyohIFJlc3BvbmQuanMgdjEuNC4yOiBtaW4vbWF4LXdpZHRoIG1lZGlhIHF1ZXJ5IHBvbHlmaWxsICogQ29weXJpZ2h0IDIwMTMgU2NvdHQgSmVobAogKiBMaWNlbnNlZCB1bmRlciBodHRwczovL2dpdGh1Yi5jb20vc2NvdHRqZWhsL1Jlc3BvbmQvYmxvYi9tYXN0ZXIvTElDRU5TRS1NSVQKICogICovCgovLyBPbmx5IHJ1biB0aGlzIGNvZGUgaW4gSUUgOAppZiAoISF3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgiTVNJRSA4IikpIHsKIWZ1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjthLm1hdGNoTWVkaWE9YS5tYXRjaE1lZGlhfHxmdW5jdGlvbihhKXt2YXIgYixjPWEuZG [...]
+<script src="data:application/x-javascript;base64,Cgp3aW5kb3cuYnVpbGRUYWJzZXRzID0gZnVuY3Rpb24odG9jSUQpIHsKCiAgLy8gYnVpbGQgYSB0YWJzZXQgZnJvbSBhIHNlY3Rpb24gZGl2IHdpdGggdGhlIC50YWJzZXQgY2xhc3MKICBmdW5jdGlvbiBidWlsZFRhYnNldCh0YWJzZXQpIHsKCiAgICAvLyBjaGVjayBmb3IgZmFkZSBhbmQgcGlsbHMgb3B0aW9ucwogICAgdmFyIGZhZGUgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1mYWRlIik7CiAgICB2YXIgcGlsbHMgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1waWxscyIpOwogICAgdmFyIG5hdkNsYXNzID0gcGlsbHMgPyAibmF2LXBpbGxzIiA6ICJuYXYtdGFicyI7CgogIC [...]
+<link href="data:text/css;charset=utf-8,pre%20%2Eoperator%2C%0Apre%20%2Eparen%20%7B%0Acolor%3A%20rgb%28104%2C%20118%2C%20135%29%0A%7D%0Apre%20%2Eliteral%20%7B%0Acolor%3A%20%23990073%0A%7D%0Apre%20%2Enumber%20%7B%0Acolor%3A%20%23099%3B%0A%7D%0Apre%20%2Ecomment%20%7B%0Acolor%3A%20%23998%3B%0Afont%2Dstyle%3A%20italic%0A%7D%0Apre%20%2Ekeyword%20%7B%0Acolor%3A%20%23900%3B%0Afont%2Dweight%3A%20bold%0A%7D%0Apre%20%2Eidentifier%20%7B%0Acolor%3A%20rgb%280%2C%200%2C%200%29%3B%0A%7D%0Apre%20%2Estri [...]
+<script src="data:application/x-javascript;base64,dmFyIGhsanM9bmV3IGZ1bmN0aW9uKCl7ZnVuY3Rpb24gbShwKXtyZXR1cm4gcC5yZXBsYWNlKC8mL2dtLCImYW1wOyIpLnJlcGxhY2UoLzwvZ20sIiZsdDsiKX1mdW5jdGlvbiBmKHIscSxwKXtyZXR1cm4gUmVnRXhwKHEsIm0iKyhyLmNJPyJpIjoiIikrKHA/ImciOiIiKSl9ZnVuY3Rpb24gYihyKXtmb3IodmFyIHA9MDtwPHIuY2hpbGROb2Rlcy5sZW5ndGg7cCsrKXt2YXIgcT1yLmNoaWxkTm9kZXNbcF07aWYocS5ub2RlTmFtZT09IkNPREUiKXtyZXR1cm4gcX1pZighKHEubm9kZVR5cGU9PTMmJnEubm9kZVZhbHVlLm1hdGNoKC9ccysvKSkpe2JyZWFrfX19ZnVuY3Rpb24gaCh0LH [...]
+
+<style type="text/css">code{white-space: pre;}</style>
+<style type="text/css">
+ pre:not([class]) {
+ background-color: white;
+ }
+</style>
+<script type="text/javascript">
+if (window.hljs && document.readyState && document.readyState === "complete") {
+ window.setTimeout(function() {
+ hljs.initHighlighting();
+ }, 0);
+}
+</script>
+
+
+
+<style type="text/css">
+h1 {
+ font-size: 34px;
+}
+h1.title {
+ font-size: 38px;
+}
+h2 {
+ font-size: 30px;
+}
+h3 {
+ font-size: 24px;
+}
+h4 {
+ font-size: 18px;
+}
+h5 {
+ font-size: 16px;
+}
+h6 {
+ font-size: 12px;
+}
+.table th:not([align]) {
+ text-align: left;
+}
+</style>
+
+
+</head>
+
+<body>
+
+<style type="text/css">
+.main-container {
+ max-width: 940px;
+ margin-left: auto;
+ margin-right: auto;
+}
+code {
+ color: inherit;
+ background-color: rgba(0, 0, 0, 0.04);
+}
+img {
+ max-width:100%;
+ height: auto;
+}
+.tabbed-pane {
+ padding-top: 12px;
+}
+button.code-folding-btn:focus {
+ outline: none;
+}
+</style>
+
+
+
+<div class="container-fluid main-container">
+
+<!-- tabsets -->
+<script>
+$(document).ready(function () {
+ window.buildTabsets("TOC");
+});
+</script>
+
+<!-- code folding -->
+
+
+
+
+
+
+<div class="fluid-row" id="header">
+
+
+
+<h1 class="title toc-ignore">Fun with bignum: how RSA encryption works</h1>
+<h4 class="date"><em>2016-12-30</em></h4>
+
+</div>
+
+
+<p>Primitive types such as <code>int</code> or <code>double</code> store numbers in exactly one or two bytes, with finite precision. This suffices for most applications, but cryptographic methods require arithmetic on much larger numbers and without loss of precision. Therefore OpenSSL provides a <strong>bignum</strong> data type which holds arbitrary sized integers and implements all basic arithmetic and comparison operators such as <code>+</code>, <code>-</code>, <code>*</code>, <code> [...]
+<p>One special case, the <a href="https://en.wikipedia.org/wiki/Modular_exponentiation"><strong>modular exponenent</strong></a> <code>a^b %% m</code> can be calculated using <code>bignum_mod_exp</code> when <code>b</code> is too large for calculating <code>a^b</code>.</p>
+<pre class="r"><code># create a bignum
+y <- bignum("123456789123456789")
+z <- bignum("D41D8CD98F00B204E9800998ECF8427E", hex = TRUE)
+
+# size grows
+print(y * z)</code></pre>
+<pre><code>## [b] 34808613111804879213872650915812112647840354642904626774</code></pre>
+<pre class="r"><code># Basic arithmetic
+div <- z %/% y
+mod <- z %% y
+z2 <- div * y + mod
+stopifnot(z2 == z)
+stopifnot(div < z)</code></pre>
+<p>RSA involves a public key and a private key. The public key should be known by everyone and is used for encrypting messages. Messages encrypted with the public key can only be decrypted in a reasonable amount of time using the private key. In RSA, this asymmetry is based on the practical difficulty of factoring the product of two large prime numbers.</p>
+<div id="rsa-key-generation" class="section level3">
+<h3>RSA key generation</h3>
+<p>An RSA key-pair is generated as follows (adapted from <a href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)">wikipedia</a>):</p>
+<ul>
+<li>Choose two distinct prime numbers <span class="math inline">\(p\)</span> and <span class="math inline">\(q\)</span>. Keep these secret.</li>
+<li>Compute the product <span class="math inline">\(n = p*q\)</span>. This <span class="math inline">\(n\)</span> value is public and used as the modulus.</li>
+<li>Compute <span class="math inline">\(\phi(n) = (p − 1)(q − 1)\)</span>.</li>
+<li>Choose an integer <span class="math inline">\(e\)</span> smaller than <span class="math inline">\(\phi(n)\)</span> such that <span class="math inline">\(e\)</span> and <span class="math inline">\(\phi(n)\)</span> are coprime. OpenSSL always uses <span class="math inline">\(65537\)</span>.</li>
+<li>Compute a value for <span class="math inline">\(d\)</span> such that <span class="math inline">\((d * e)\pmod{\phi(n)} = 1\)</span>.</li>
+</ul>
+<p>OpenSSL has a key generator that does these things for us.</p>
+<pre class="r"><code>(key <- rsa_keygen(512))</code></pre>
+<pre><code>## [512-bit rsa private key]
+## md5: c4c39ba29f28517eec49c6b2755be69c</code></pre>
+<pre class="r"><code>(pubkey <- key$pubkey)</code></pre>
+<pre><code>## [512-bit rsa public key]
+## md5: c4c39ba29f28517eec49c6b2755be69c</code></pre>
+<p>Usually we would use <code>rsa_encrypt</code> and <code>rsa_decrypt</code> to perform the encryption:</p>
+<pre class="r"><code>msg <- charToRaw("hello world")
+ciphertext <- rsa_encrypt(msg, pubkey)
+rawToChar(rsa_decrypt(ciphertext, key))</code></pre>
+<pre><code>## [1] "hello world"</code></pre>
+<p>Let’s look at how this works under the hood.</p>
+</div>
+<div id="how-rsa-encryption-works" class="section level3">
+<h3>How RSA encryption works</h3>
+<p>The <code>data</code> field of the private key extracts the underlying bignum integers:</p>
+<pre class="r"><code>key$data</code></pre>
+<pre><code>## $e
+## [b] 65537
+## $n
+## [b] 10569026565286155820720744523231748863822088228516641890189557970400740945053483041322691870588364647828869510740348759232483548879935360746654051791408149
+## $p
+## [b] 104561422052657818321305572918830068873573672192479059216414484631900340164947
+## $q
+## [b] 101079598553695307281587615375424174526793348449800289774735773171041152946167
+## $d
+## [b] 9722046576564015802556572372599081133642287392711380691061194474046853958413366923679924705437273484878878791185414862207468314595922482404144058842071453
+## $dp
+## [b] 18054183925841522683734285413575248476026666990098616569158586876033145388201
+## $dq
+## [b] 87431531544194570687987529798465685117946523901342429875493561034529820989857
+## $qi
+## [b] 35189962504388150911189634866142836821114269709182565183863384271658676836525</code></pre>
+<p>You can verify that the equations above hold for this key. The public key is simply a subset of the key which only contains <span class="math inline">\(n\)</span> and <span class="math inline">\(e\)</span>:</p>
+<pre class="r"><code>pubkey$data</code></pre>
+<pre><code>## $e
+## [b] 65537
+## $n
+## [b] 10569026565286155820720744523231748863822088228516641890189557970400740945053483041322691870588364647828869510740348759232483548879935360746654051791408149</code></pre>
+<p>In order to encrypt a message into ciphertext we have to treat the message data as an integer. The message cannot be larger than the key size. For example convert the text <code>hello world</code> into an integer:</p>
+<pre class="r"><code>m <- bignum(charToRaw("hello world"))
+print(m)</code></pre>
+<pre><code>## [b] 126207244316550804821666916</code></pre>
+<p>To encrypt this message <span class="math inline">\(m\)</span> into ciphertext <span class="math inline">\(c\)</span> we calculate <span class="math inline">\(c = m^e\pmod n\)</span>. Using the public key from above:</p>
+<pre class="r"><code>e <- pubkey$data$e
+n <- pubkey$data$n
+c <- (m ^ e) %% n
+print(c)</code></pre>
+<pre><code>## [b] 3325659323980215257106509330346053668176374408427813427001691391003696397464298082936759956359781182102881980395262788263285765465327517193833561164790947</code></pre>
+<p>This is number represents out encrypted message! It is usually exchanged using base64 notation for human readability:</p>
+<pre class="r"><code>base64_encode(c)</code></pre>
+<pre><code>## [1] "P3978g+Eg158DwmcpWl5VcPbXKv790cz5p/ozD5uNTGnMd21igOnEhOhaKGveZIAvKXwTVkaNYVefdobMxq8ow=="</code></pre>
+<p>The ciphertext can be decrypted using <span class="math inline">\(d\)</span> from the corresponding private key via <span class="math inline">\(m = c^d \pmod{n}\)</span>. Note that <code>c^d</code> is too large to calculate directly so we need to use <code>bignum_mod_exp</code> instead.</p>
+<pre class="r"><code>d <- key$data$d
+out <- bignum_mod_exp(c, d, n)
+rawToChar(out)</code></pre>
+<pre><code>## [1] "hello world"</code></pre>
+<p>The only difference with the actual <code>rsa_encrypt</code> and <code>rsa_decrypt</code> functions is that these add some additional padding to the data.</p>
+</div>
+
+
+
+
+</div>
+
+<script>
+
+// add bootstrap table styles to pandoc tables
+function bootstrapStylePandocTables() {
+ $('tr.header').parent('thead').parent('table').addClass('table table-condensed');
+}
+$(document).ready(function () {
+ bootstrapStylePandocTables();
+});
+
+
+</script>
+
+<!-- dynamically load mathjax for compatibility with self-contained -->
+<script>
+ (function () {
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.src = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+ document.getElementsByTagName("head")[0].appendChild(script);
+ })();
+</script>
+
+</body>
+</html>
diff --git a/inst/doc/crypto_hashing.R b/inst/doc/crypto_hashing.R
new file mode 100644
index 0000000..34dbafa
--- /dev/null
+++ b/inst/doc/crypto_hashing.R
@@ -0,0 +1,30 @@
+## ---- echo = FALSE, message = FALSE--------------------------------------
+knitr::opts_chunk$set(comment = "")
+library(openssl)
+
+## ------------------------------------------------------------------------
+md5("foo")
+md5(charToRaw("foo"))
+
+## ------------------------------------------------------------------------
+# Vectorized for strings
+md5(c("foo", "bar", "baz"))
+
+## ------------------------------------------------------------------------
+# Stream-hash a file
+myfile <- system.file("CITATION")
+md5(file(myfile))
+
+## ----eval=FALSE----------------------------------------------------------
+# # Stream-hash from a network connection
+# md5(url("http://cran.us.r-project.org/bin/windows/base/old/3.1.1/R-3.1.1-win.exe"))
+
+## ------------------------------------------------------------------------
+# Compare to digest
+library(digest)
+digest("foo", "md5", serialize = FALSE)
+
+# Other way around
+digest(cars, skip = 0)
+md5(serialize(cars, NULL))
+
diff --git a/inst/doc/crypto_hashing.Rmd b/inst/doc/crypto_hashing.Rmd
new file mode 100644
index 0000000..69603bb
--- /dev/null
+++ b/inst/doc/crypto_hashing.Rmd
@@ -0,0 +1,58 @@
+---
+title: "Cryptographic Hashing in R"
+date: "`r Sys.Date()`"
+vignette: >
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteIndexEntry{Cryptographic Hashing in R}
+ \usepackage[utf8]{inputenc}
+output:
+ html_document
+---
+
+```{r, echo = FALSE, message = FALSE}
+knitr::opts_chunk$set(comment = "")
+library(openssl)
+```
+
+The functions `sha1`, `sha256`, `sha512`, `md4`, `md5` and `ripemd160` bind to the respective [digest functions](https://www.openssl.org/docs/manmaster/man1/dgst.html) in OpenSSL's libcrypto. Both binary and string inputs are supported and the output type will match the input type.
+
+```{r}
+md5("foo")
+md5(charToRaw("foo"))
+```
+
+Functions are fully vectorized for the case of character vectors: a vector with n strings will return n hashes.
+
+```{r}
+# Vectorized for strings
+md5(c("foo", "bar", "baz"))
+```
+
+Besides character and raw vectors we can pass a connection object (e.g. a file, socket or url). In this case the function will stream-hash the binary contents of the conection.
+
+```{r}
+# Stream-hash a file
+myfile <- system.file("CITATION")
+md5(file(myfile))
+```
+
+Same for URLs. The hash of the [`R-3.1.1-win.exe`](http://cran.us.r-project.org/bin/windows/base/old/3.1.1/R-3.1.1-win.exe) below should match the one in [`md5sum.txt`](http://cran.us.r-project.org/bin/windows/base/old/3.1.1/md5sum.txt)
+
+```{r eval=FALSE}
+# Stream-hash from a network connection
+md5(url("http://cran.us.r-project.org/bin/windows/base/old/3.1.1/R-3.1.1-win.exe"))
+```
+
+## Compare to digest
+
+Similar functionality is also available in the **digest** package, but with a slightly different interface:
+
+```{r}
+# Compare to digest
+library(digest)
+digest("foo", "md5", serialize = FALSE)
+
+# Other way around
+digest(cars, skip = 0)
+md5(serialize(cars, NULL))
+```
diff --git a/inst/doc/crypto_hashing.html b/inst/doc/crypto_hashing.html
new file mode 100644
index 0000000..27d1fc6
--- /dev/null
+++ b/inst/doc/crypto_hashing.html
@@ -0,0 +1,191 @@
+<!DOCTYPE html>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="pandoc" />
+
+
+
+<meta name="date" content="2016-12-30" />
+
+<title>Cryptographic Hashing in R</title>
+
+<script src="data:application/x-javascript;base64,LyohIGpRdWVyeSB2MS4xMS4zIHwgKGMpIDIwMDUsIDIwMTUgalF1ZXJ5IEZvdW5kYXRpb24sIEluYy4gfCBqcXVlcnkub3JnL2xpY2Vuc2UgKi8KIWZ1bmN0aW9uKGEsYil7Im9iamVjdCI9PXR5cGVvZiBtb2R1bGUmJiJvYmplY3QiPT10eXBlb2YgbW9kdWxlLmV4cG9ydHM/bW9kdWxlLmV4cG9ydHM9YS5kb2N1bWVudD9iKGEsITApOmZ1bmN0aW9uKGEpe2lmKCFhLmRvY3VtZW50KXRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpO3JldHVybiBiKGEpfTpiKGEpfSgidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdz93aW5kb3c6dG [...]
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<link href="data:text/css;charset=utf-8,html%7Bfont%2Dfamily%3Asans%2Dserif%3B%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A100%25%3B%2Dms%2Dtext%2Dsize%2Dadjust%3A100%25%7Dbody%7Bmargin%3A0%7Darticle%2Caside%2Cdetails%2Cfigcaption%2Cfigure%2Cfooter%2Cheader%2Chgroup%2Cmain%2Cmenu%2Cnav%2Csection%2Csummary%7Bdisplay%3Ablock%7Daudio%2Ccanvas%2Cprogress%2Cvideo%7Bdisplay%3Ainline%2Dblock%3Bvertical%2Dalign%3Abaseline%7Daudio%3Anot%28%5Bcontrols%5D%29%7Bdisplay%3Anone%3Bheight%3A0%7D%5Bhidden%5D%2Ctem [...]
+<script src="data:application/x-javascript;base64,LyohCiAqIEJvb3RzdHJhcCB2My4zLjUgKGh0dHA6Ly9nZXRib290c3RyYXAuY29tKQogKiBDb3B5cmlnaHQgMjAxMS0yMDE1IFR3aXR0ZXIsIEluYy4KICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlCiAqLwppZigidW5kZWZpbmVkIj09dHlwZW9mIGpRdWVyeSl0aHJvdyBuZXcgRXJyb3IoIkJvb3RzdHJhcCdzIEphdmFTY3JpcHQgcmVxdWlyZXMgalF1ZXJ5Iik7K2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0Ijt2YXIgYj1hLmZuLmpxdWVyeS5zcGxpdCgiICIpWzBdLnNwbGl0KCIuIik7aWYoYlswXTwyJiZiWzFdPDl8fDE9PWJbMF0mJjk9PWJbMV0mJmJbMl08MSl0aHJvdy [...]
+<script src="data:application/x-javascript;base64,LyoqCiogQHByZXNlcnZlIEhUTUw1IFNoaXYgMy43LjIgfCBAYWZhcmthcyBAamRhbHRvbiBAam9uX25lYWwgQHJlbSB8IE1JVC9HUEwyIExpY2Vuc2VkCiovCi8vIE9ubHkgcnVuIHRoaXMgY29kZSBpbiBJRSA4CmlmICghIXdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKCJNU0lFIDgiKSkgewohZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYil7dmFyIGM9YS5jcmVhdGVFbGVtZW50KCJwIiksZD1hLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJoZWFkIilbMF18fGEuZG9jdW1lbnRFbGVtZW50O3JldHVybiBjLmlubmVySFRNTD0ieDxzdHlsZT4iK2IrIjwvc3R5bGU+IixkLm [...]
+<script src="data:application/x-javascript;base64,LyohIFJlc3BvbmQuanMgdjEuNC4yOiBtaW4vbWF4LXdpZHRoIG1lZGlhIHF1ZXJ5IHBvbHlmaWxsICogQ29weXJpZ2h0IDIwMTMgU2NvdHQgSmVobAogKiBMaWNlbnNlZCB1bmRlciBodHRwczovL2dpdGh1Yi5jb20vc2NvdHRqZWhsL1Jlc3BvbmQvYmxvYi9tYXN0ZXIvTElDRU5TRS1NSVQKICogICovCgovLyBPbmx5IHJ1biB0aGlzIGNvZGUgaW4gSUUgOAppZiAoISF3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgiTVNJRSA4IikpIHsKIWZ1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjthLm1hdGNoTWVkaWE9YS5tYXRjaE1lZGlhfHxmdW5jdGlvbihhKXt2YXIgYixjPWEuZG [...]
+<script src="data:application/x-javascript;base64,Cgp3aW5kb3cuYnVpbGRUYWJzZXRzID0gZnVuY3Rpb24odG9jSUQpIHsKCiAgLy8gYnVpbGQgYSB0YWJzZXQgZnJvbSBhIHNlY3Rpb24gZGl2IHdpdGggdGhlIC50YWJzZXQgY2xhc3MKICBmdW5jdGlvbiBidWlsZFRhYnNldCh0YWJzZXQpIHsKCiAgICAvLyBjaGVjayBmb3IgZmFkZSBhbmQgcGlsbHMgb3B0aW9ucwogICAgdmFyIGZhZGUgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1mYWRlIik7CiAgICB2YXIgcGlsbHMgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1waWxscyIpOwogICAgdmFyIG5hdkNsYXNzID0gcGlsbHMgPyAibmF2LXBpbGxzIiA6ICJuYXYtdGFicyI7CgogIC [...]
+<link href="data:text/css;charset=utf-8,pre%20%2Eoperator%2C%0Apre%20%2Eparen%20%7B%0Acolor%3A%20rgb%28104%2C%20118%2C%20135%29%0A%7D%0Apre%20%2Eliteral%20%7B%0Acolor%3A%20%23990073%0A%7D%0Apre%20%2Enumber%20%7B%0Acolor%3A%20%23099%3B%0A%7D%0Apre%20%2Ecomment%20%7B%0Acolor%3A%20%23998%3B%0Afont%2Dstyle%3A%20italic%0A%7D%0Apre%20%2Ekeyword%20%7B%0Acolor%3A%20%23900%3B%0Afont%2Dweight%3A%20bold%0A%7D%0Apre%20%2Eidentifier%20%7B%0Acolor%3A%20rgb%280%2C%200%2C%200%29%3B%0A%7D%0Apre%20%2Estri [...]
+<script src="data:application/x-javascript;base64,dmFyIGhsanM9bmV3IGZ1bmN0aW9uKCl7ZnVuY3Rpb24gbShwKXtyZXR1cm4gcC5yZXBsYWNlKC8mL2dtLCImYW1wOyIpLnJlcGxhY2UoLzwvZ20sIiZsdDsiKX1mdW5jdGlvbiBmKHIscSxwKXtyZXR1cm4gUmVnRXhwKHEsIm0iKyhyLmNJPyJpIjoiIikrKHA/ImciOiIiKSl9ZnVuY3Rpb24gYihyKXtmb3IodmFyIHA9MDtwPHIuY2hpbGROb2Rlcy5sZW5ndGg7cCsrKXt2YXIgcT1yLmNoaWxkTm9kZXNbcF07aWYocS5ub2RlTmFtZT09IkNPREUiKXtyZXR1cm4gcX1pZighKHEubm9kZVR5cGU9PTMmJnEubm9kZVZhbHVlLm1hdGNoKC9ccysvKSkpe2JyZWFrfX19ZnVuY3Rpb24gaCh0LH [...]
+
+<style type="text/css">code{white-space: pre;}</style>
+<style type="text/css">
+ pre:not([class]) {
+ background-color: white;
+ }
+</style>
+<script type="text/javascript">
+if (window.hljs && document.readyState && document.readyState === "complete") {
+ window.setTimeout(function() {
+ hljs.initHighlighting();
+ }, 0);
+}
+</script>
+
+
+
+<style type="text/css">
+h1 {
+ font-size: 34px;
+}
+h1.title {
+ font-size: 38px;
+}
+h2 {
+ font-size: 30px;
+}
+h3 {
+ font-size: 24px;
+}
+h4 {
+ font-size: 18px;
+}
+h5 {
+ font-size: 16px;
+}
+h6 {
+ font-size: 12px;
+}
+.table th:not([align]) {
+ text-align: left;
+}
+</style>
+
+
+</head>
+
+<body>
+
+<style type="text/css">
+.main-container {
+ max-width: 940px;
+ margin-left: auto;
+ margin-right: auto;
+}
+code {
+ color: inherit;
+ background-color: rgba(0, 0, 0, 0.04);
+}
+img {
+ max-width:100%;
+ height: auto;
+}
+.tabbed-pane {
+ padding-top: 12px;
+}
+button.code-folding-btn:focus {
+ outline: none;
+}
+</style>
+
+
+
+<div class="container-fluid main-container">
+
+<!-- tabsets -->
+<script>
+$(document).ready(function () {
+ window.buildTabsets("TOC");
+});
+</script>
+
+<!-- code folding -->
+
+
+
+
+
+
+<div class="fluid-row" id="header">
+
+
+
+<h1 class="title toc-ignore">Cryptographic Hashing in R</h1>
+<h4 class="date"><em>2016-12-30</em></h4>
+
+</div>
+
+
+<p>The functions <code>sha1</code>, <code>sha256</code>, <code>sha512</code>, <code>md4</code>, <code>md5</code> and <code>ripemd160</code> bind to the respective <a href="https://www.openssl.org/docs/manmaster/man1/dgst.html">digest functions</a> in OpenSSL’s libcrypto. Both binary and string inputs are supported and the output type will match the input type.</p>
+<pre class="r"><code>md5("foo")</code></pre>
+<pre><code>[1] "acbd18db4cc2f85cedef654fccc4a4d8"</code></pre>
+<pre class="r"><code>md5(charToRaw("foo"))</code></pre>
+<pre><code>md5 ac:bd:18:db:4c:c2:f8:5c:ed:ef:65:4f:cc:c4:a4:d8 </code></pre>
+<p>Functions are fully vectorized for the case of character vectors: a vector with n strings will return n hashes.</p>
+<pre class="r"><code># Vectorized for strings
+md5(c("foo", "bar", "baz"))</code></pre>
+<pre><code>[1] "acbd18db4cc2f85cedef654fccc4a4d8" "37b51d194a7513e45b56f6524f2d51f2"
+[3] "73feffa4b7f6bb68e44cf984c85f6e88"</code></pre>
+<p>Besides character and raw vectors we can pass a connection object (e.g. a file, socket or url). In this case the function will stream-hash the binary contents of the conection.</p>
+<pre class="r"><code># Stream-hash a file
+myfile <- system.file("CITATION")
+md5(file(myfile))</code></pre>
+<pre><code>md5 16:a3:1a:bf:39:26:86:31:f2:0e:14:78:bf:64:d6:59 </code></pre>
+<p>Same for URLs. The hash of the <a href="http://cran.us.r-project.org/bin/windows/base/old/3.1.1/R-3.1.1-win.exe"><code>R-3.1.1-win.exe</code></a> below should match the one in <a href="http://cran.us.r-project.org/bin/windows/base/old/3.1.1/md5sum.txt"><code>md5sum.txt</code></a></p>
+<pre class="r"><code># Stream-hash from a network connection
+md5(url("http://cran.us.r-project.org/bin/windows/base/old/3.1.1/R-3.1.1-win.exe"))</code></pre>
+<div id="compare-to-digest" class="section level2">
+<h2>Compare to digest</h2>
+<p>Similar functionality is also available in the <strong>digest</strong> package, but with a slightly different interface:</p>
+<pre class="r"><code># Compare to digest
+library(digest)</code></pre>
+<pre><code>
+Attaching package: 'digest'</code></pre>
+<pre><code>The following object is masked from 'package:openssl':
+
+ sha1</code></pre>
+<pre class="r"><code>digest("foo", "md5", serialize = FALSE)</code></pre>
+<pre><code>[1] "acbd18db4cc2f85cedef654fccc4a4d8"</code></pre>
+<pre class="r"><code># Other way around
+digest(cars, skip = 0)</code></pre>
+<pre><code>[1] "ceb7f0b7e120fe0f6e6141ea36b67dcb"</code></pre>
+<pre class="r"><code>md5(serialize(cars, NULL))</code></pre>
+<pre><code>md5 ce:b7:f0:b7:e1:20:fe:0f:6e:61:41:ea:36:b6:7d:cb </code></pre>
+</div>
+
+
+
+
+</div>
+
+<script>
+
+// add bootstrap table styles to pandoc tables
+function bootstrapStylePandocTables() {
+ $('tr.header').parent('thead').parent('table').addClass('table table-condensed');
+}
+$(document).ready(function () {
+ bootstrapStylePandocTables();
+});
+
+
+</script>
+
+<!-- dynamically load mathjax for compatibility with self-contained -->
+<script>
+ (function () {
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.src = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+ document.getElementsByTagName("head")[0].appendChild(script);
+ })();
+</script>
+
+</body>
+</html>
diff --git a/inst/doc/keys.R b/inst/doc/keys.R
new file mode 100644
index 0000000..9a068ca
--- /dev/null
+++ b/inst/doc/keys.R
@@ -0,0 +1,38 @@
+## ----setup, include=FALSE------------------------------------------------
+knitr::opts_chunk$set(echo = TRUE)
+knitr::opts_chunk$set(comment = "")
+library(openssl)
+
+## ------------------------------------------------------------------------
+key <- ec_keygen()
+pubkey <- key$pubkey
+bin <- write_der(pubkey)
+print(bin)
+
+## ------------------------------------------------------------------------
+read_pubkey(bin, der = TRUE)
+
+## ------------------------------------------------------------------------
+cat(write_pem(pubkey))
+cat(write_pem(key, password = NULL))
+
+## ------------------------------------------------------------------------
+cat(write_pem(key, password = "supersecret"))
+
+## ------------------------------------------------------------------------
+str <- write_ssh(pubkey)
+print(str)
+
+## ------------------------------------------------------------------------
+read_pubkey(str)
+
+## ------------------------------------------------------------------------
+library(jose)
+json <- write_jwk(pubkey)
+jsonlite::prettify(json)
+
+## ------------------------------------------------------------------------
+mykey <- read_jwk(json)
+identical(mykey, pubkey)
+print(mykey)
+
diff --git a/inst/doc/keys.Rmd b/inst/doc/keys.Rmd
new file mode 100644
index 0000000..16484cd
--- /dev/null
+++ b/inst/doc/keys.Rmd
@@ -0,0 +1,99 @@
+---
+title: "Importing and exporting RSA/DSA/EC keys"
+date: "`r Sys.Date()`"
+output:
+ html_document
+vignette: >
+ %\VignetteIndexEntry{Importing and exporting RSA/DSA/EC keys}
+ %\VignetteEngine{knitr::rmarkdown}
+ \usepackage[utf8]{inputenc}
+---
+
+```{r setup, include=FALSE}
+knitr::opts_chunk$set(echo = TRUE)
+knitr::opts_chunk$set(comment = "")
+library(openssl)
+```
+
+The `openssl` package implements a modern interface to libssl and libcrypto for R. It builds on the new `EVP` api which was introduced in OpenSSL 1.0 and provides a unified API to the various methods and formats. OpenSSL supports three major public key crypto systems:
+
+ - __RSA__ : Most popular method. Supports both encryption and signatures.
+ - __DSA__ : Digital Signature Algorithm. Mostly for signatures, not very popular anymore.
+ - __ECDSA__ : Elliptic Curve DSA. Supports signatures and encryption via Diffie Hellman. Gaining popularity.
+
+For each type there are several common __formats__ for storing keys and certificates:
+
+ - [__DER__](#the-der-format): binary format, serialized ASN.1 structure
+ - [__PEM__](#the-pem-format): base64 encoded DER + header wrapped in `===`
+ - [__SSH__](#the-openssh-format): single line of base64 with a header. Only for pubkeys.
+ - [__JWK__](#the-json-web-key-jwk-format): JSON Web key. Stores key data in a JSON object
+
+The openssl package automatically detects the format when possible. However being able to recognize the various formats can be useful.
+
+### The DER format
+
+DER is the standard __binary__ format using by protocols for storing and exchanging keys and certificates. It consists of a [serialized ASN.1](https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One#Example_encoded_in_DER) structure which hold the key's (very large) prime numbers.
+
+
+```{r}
+key <- ec_keygen()
+pubkey <- key$pubkey
+bin <- write_der(pubkey)
+print(bin)
+```
+
+To read a DER key use `read_key` or `read_pubkey` with `der = TRUE`.
+
+```{r}
+read_pubkey(bin, der = TRUE)
+```
+
+Users typically don't need to worry about the key's underlying primes, but have a look at `key$data` if you are curious.
+
+### The PEM format
+
+In practice the user rarely encounters DER because it is mainly for internal use. When humans exchange keys and certificates they typically use the PEM format. PEM is simply **base64 encoded DER data, plus a header**. The header identifies the key (and possibly encryption) type.
+
+```{r}
+cat(write_pem(pubkey))
+cat(write_pem(key, password = NULL))
+```
+
+The PEM format allows for protecting private keys with a password. R will prompt you for the password when reading such a protected key.
+
+```{r}
+cat(write_pem(key, password = "supersecret"))
+```
+
+### The OpenSSH format
+
+For better or worse, OpenSSH uses a custom format for **public keys**. The advantage of this format is that it fits on a single line which is nice for e.g. your `~/.ssh/known_hosts` file. There is no special format for private keys, OpenSSH uses PEM as well.
+
+```{r}
+str <- write_ssh(pubkey)
+print(str)
+```
+
+The `read_pubkey` function will automatically detect if a file contains a `PEM` or `SSH` key.
+
+```{r}
+read_pubkey(str)
+```
+
+### The JSON Web Key (JWK) format
+
+Yet another recent format to store RSA or EC keys are JSON Web Keys (JWK). JWK is part of the **Javascript Object Signing and Encryption (JOSE)** specification. The `write_jwk` and `read_jwk` functions are implemented in a separate package which uses the `openssl` package.
+
+```{r}
+library(jose)
+json <- write_jwk(pubkey)
+jsonlite::prettify(json)
+```
+
+Keys from `jose` and `openssl` are the same.
+
+```{r}
+mykey <- read_jwk(json)
+identical(mykey, pubkey)
+print(mykey)
+```
diff --git a/inst/doc/keys.html b/inst/doc/keys.html
new file mode 100644
index 0000000..fb45483
--- /dev/null
+++ b/inst/doc/keys.html
@@ -0,0 +1,242 @@
+<!DOCTYPE html>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="pandoc" />
+
+
+
+<meta name="date" content="2016-12-30" />
+
+<title>Importing and exporting RSA/DSA/EC keys</title>
+
+<script src="data:application/x-javascript;base64,LyohIGpRdWVyeSB2MS4xMS4zIHwgKGMpIDIwMDUsIDIwMTUgalF1ZXJ5IEZvdW5kYXRpb24sIEluYy4gfCBqcXVlcnkub3JnL2xpY2Vuc2UgKi8KIWZ1bmN0aW9uKGEsYil7Im9iamVjdCI9PXR5cGVvZiBtb2R1bGUmJiJvYmplY3QiPT10eXBlb2YgbW9kdWxlLmV4cG9ydHM/bW9kdWxlLmV4cG9ydHM9YS5kb2N1bWVudD9iKGEsITApOmZ1bmN0aW9uKGEpe2lmKCFhLmRvY3VtZW50KXRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpO3JldHVybiBiKGEpfTpiKGEpfSgidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdz93aW5kb3c6dG [...]
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<link href="data:text/css;charset=utf-8,html%7Bfont%2Dfamily%3Asans%2Dserif%3B%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A100%25%3B%2Dms%2Dtext%2Dsize%2Dadjust%3A100%25%7Dbody%7Bmargin%3A0%7Darticle%2Caside%2Cdetails%2Cfigcaption%2Cfigure%2Cfooter%2Cheader%2Chgroup%2Cmain%2Cmenu%2Cnav%2Csection%2Csummary%7Bdisplay%3Ablock%7Daudio%2Ccanvas%2Cprogress%2Cvideo%7Bdisplay%3Ainline%2Dblock%3Bvertical%2Dalign%3Abaseline%7Daudio%3Anot%28%5Bcontrols%5D%29%7Bdisplay%3Anone%3Bheight%3A0%7D%5Bhidden%5D%2Ctem [...]
+<script src="data:application/x-javascript;base64,LyohCiAqIEJvb3RzdHJhcCB2My4zLjUgKGh0dHA6Ly9nZXRib290c3RyYXAuY29tKQogKiBDb3B5cmlnaHQgMjAxMS0yMDE1IFR3aXR0ZXIsIEluYy4KICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlCiAqLwppZigidW5kZWZpbmVkIj09dHlwZW9mIGpRdWVyeSl0aHJvdyBuZXcgRXJyb3IoIkJvb3RzdHJhcCdzIEphdmFTY3JpcHQgcmVxdWlyZXMgalF1ZXJ5Iik7K2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0Ijt2YXIgYj1hLmZuLmpxdWVyeS5zcGxpdCgiICIpWzBdLnNwbGl0KCIuIik7aWYoYlswXTwyJiZiWzFdPDl8fDE9PWJbMF0mJjk9PWJbMV0mJmJbMl08MSl0aHJvdy [...]
+<script src="data:application/x-javascript;base64,LyoqCiogQHByZXNlcnZlIEhUTUw1IFNoaXYgMy43LjIgfCBAYWZhcmthcyBAamRhbHRvbiBAam9uX25lYWwgQHJlbSB8IE1JVC9HUEwyIExpY2Vuc2VkCiovCi8vIE9ubHkgcnVuIHRoaXMgY29kZSBpbiBJRSA4CmlmICghIXdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKCJNU0lFIDgiKSkgewohZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYil7dmFyIGM9YS5jcmVhdGVFbGVtZW50KCJwIiksZD1hLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJoZWFkIilbMF18fGEuZG9jdW1lbnRFbGVtZW50O3JldHVybiBjLmlubmVySFRNTD0ieDxzdHlsZT4iK2IrIjwvc3R5bGU+IixkLm [...]
+<script src="data:application/x-javascript;base64,LyohIFJlc3BvbmQuanMgdjEuNC4yOiBtaW4vbWF4LXdpZHRoIG1lZGlhIHF1ZXJ5IHBvbHlmaWxsICogQ29weXJpZ2h0IDIwMTMgU2NvdHQgSmVobAogKiBMaWNlbnNlZCB1bmRlciBodHRwczovL2dpdGh1Yi5jb20vc2NvdHRqZWhsL1Jlc3BvbmQvYmxvYi9tYXN0ZXIvTElDRU5TRS1NSVQKICogICovCgovLyBPbmx5IHJ1biB0aGlzIGNvZGUgaW4gSUUgOAppZiAoISF3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgiTVNJRSA4IikpIHsKIWZ1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjthLm1hdGNoTWVkaWE9YS5tYXRjaE1lZGlhfHxmdW5jdGlvbihhKXt2YXIgYixjPWEuZG [...]
+<script src="data:application/x-javascript;base64,Cgp3aW5kb3cuYnVpbGRUYWJzZXRzID0gZnVuY3Rpb24odG9jSUQpIHsKCiAgLy8gYnVpbGQgYSB0YWJzZXQgZnJvbSBhIHNlY3Rpb24gZGl2IHdpdGggdGhlIC50YWJzZXQgY2xhc3MKICBmdW5jdGlvbiBidWlsZFRhYnNldCh0YWJzZXQpIHsKCiAgICAvLyBjaGVjayBmb3IgZmFkZSBhbmQgcGlsbHMgb3B0aW9ucwogICAgdmFyIGZhZGUgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1mYWRlIik7CiAgICB2YXIgcGlsbHMgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1waWxscyIpOwogICAgdmFyIG5hdkNsYXNzID0gcGlsbHMgPyAibmF2LXBpbGxzIiA6ICJuYXYtdGFicyI7CgogIC [...]
+<link href="data:text/css;charset=utf-8,pre%20%2Eoperator%2C%0Apre%20%2Eparen%20%7B%0Acolor%3A%20rgb%28104%2C%20118%2C%20135%29%0A%7D%0Apre%20%2Eliteral%20%7B%0Acolor%3A%20%23990073%0A%7D%0Apre%20%2Enumber%20%7B%0Acolor%3A%20%23099%3B%0A%7D%0Apre%20%2Ecomment%20%7B%0Acolor%3A%20%23998%3B%0Afont%2Dstyle%3A%20italic%0A%7D%0Apre%20%2Ekeyword%20%7B%0Acolor%3A%20%23900%3B%0Afont%2Dweight%3A%20bold%0A%7D%0Apre%20%2Eidentifier%20%7B%0Acolor%3A%20rgb%280%2C%200%2C%200%29%3B%0A%7D%0Apre%20%2Estri [...]
+<script src="data:application/x-javascript;base64,dmFyIGhsanM9bmV3IGZ1bmN0aW9uKCl7ZnVuY3Rpb24gbShwKXtyZXR1cm4gcC5yZXBsYWNlKC8mL2dtLCImYW1wOyIpLnJlcGxhY2UoLzwvZ20sIiZsdDsiKX1mdW5jdGlvbiBmKHIscSxwKXtyZXR1cm4gUmVnRXhwKHEsIm0iKyhyLmNJPyJpIjoiIikrKHA/ImciOiIiKSl9ZnVuY3Rpb24gYihyKXtmb3IodmFyIHA9MDtwPHIuY2hpbGROb2Rlcy5sZW5ndGg7cCsrKXt2YXIgcT1yLmNoaWxkTm9kZXNbcF07aWYocS5ub2RlTmFtZT09IkNPREUiKXtyZXR1cm4gcX1pZighKHEubm9kZVR5cGU9PTMmJnEubm9kZVZhbHVlLm1hdGNoKC9ccysvKSkpe2JyZWFrfX19ZnVuY3Rpb24gaCh0LH [...]
+
+<style type="text/css">code{white-space: pre;}</style>
+<style type="text/css">
+ pre:not([class]) {
+ background-color: white;
+ }
+</style>
+<script type="text/javascript">
+if (window.hljs && document.readyState && document.readyState === "complete") {
+ window.setTimeout(function() {
+ hljs.initHighlighting();
+ }, 0);
+}
+</script>
+
+
+
+<style type="text/css">
+h1 {
+ font-size: 34px;
+}
+h1.title {
+ font-size: 38px;
+}
+h2 {
+ font-size: 30px;
+}
+h3 {
+ font-size: 24px;
+}
+h4 {
+ font-size: 18px;
+}
+h5 {
+ font-size: 16px;
+}
+h6 {
+ font-size: 12px;
+}
+.table th:not([align]) {
+ text-align: left;
+}
+</style>
+
+
+</head>
+
+<body>
+
+<style type="text/css">
+.main-container {
+ max-width: 940px;
+ margin-left: auto;
+ margin-right: auto;
+}
+code {
+ color: inherit;
+ background-color: rgba(0, 0, 0, 0.04);
+}
+img {
+ max-width:100%;
+ height: auto;
+}
+.tabbed-pane {
+ padding-top: 12px;
+}
+button.code-folding-btn:focus {
+ outline: none;
+}
+</style>
+
+
+
+<div class="container-fluid main-container">
+
+<!-- tabsets -->
+<script>
+$(document).ready(function () {
+ window.buildTabsets("TOC");
+});
+</script>
+
+<!-- code folding -->
+
+
+
+
+
+
+<div class="fluid-row" id="header">
+
+
+
+<h1 class="title toc-ignore">Importing and exporting RSA/DSA/EC keys</h1>
+<h4 class="date"><em>2016-12-30</em></h4>
+
+</div>
+
+
+<p>The <code>openssl</code> package implements a modern interface to libssl and libcrypto for R. It builds on the new <code>EVP</code> api which was introduced in OpenSSL 1.0 and provides a unified API to the various methods and formats. OpenSSL supports three major public key crypto systems:</p>
+<ul>
+<li><strong>RSA</strong> : Most popular method. Supports both encryption and signatures.</li>
+<li><strong>DSA</strong> : Digital Signature Algorithm. Mostly for signatures, not very popular anymore.</li>
+<li><strong>ECDSA</strong> : Elliptic Curve DSA. Supports signatures and encryption via Diffie Hellman. Gaining popularity.</li>
+</ul>
+<p>For each type there are several common <strong>formats</strong> for storing keys and certificates:</p>
+<ul>
+<li><a href="#the-der-format"><strong>DER</strong></a>: binary format, serialized ASN.1 structure</li>
+<li><a href="#the-pem-format"><strong>PEM</strong></a>: base64 encoded DER + header wrapped in <code>===</code></li>
+<li><a href="#the-openssh-format"><strong>SSH</strong></a>: single line of base64 with a header. Only for pubkeys.</li>
+<li><a href="#the-json-web-key-jwk-format"><strong>JWK</strong></a>: JSON Web key. Stores key data in a JSON object</li>
+</ul>
+<p>The openssl package automatically detects the format when possible. However being able to recognize the various formats can be useful.</p>
+<div id="the-der-format" class="section level3">
+<h3>The DER format</h3>
+<p>DER is the standard <strong>binary</strong> format using by protocols for storing and exchanging keys and certificates. It consists of a <a href="https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One#Example_encoded_in_DER">serialized ASN.1</a> structure which hold the key’s (very large) prime numbers.</p>
+<pre class="r"><code>key <- ec_keygen()
+pubkey <- key$pubkey
+bin <- write_der(pubkey)
+print(bin)</code></pre>
+<pre><code> [1] 30 59 30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d 03 01 07
+[24] 03 42 00 04 36 52 16 0f 87 c1 2c 21 e0 68 38 aa f0 0e c0 b2 39 f7 a0
+[47] e0 f4 6b 45 70 46 00 f7 e9 84 1e f7 1d a0 f2 87 ea eb de 65 52 0c 56
+[70] c8 6a c1 a5 dd 70 54 15 31 0e 78 2b ad a5 83 a3 44 8f a0 51 3d 2e</code></pre>
+<p>To read a DER key use <code>read_key</code> or <code>read_pubkey</code> with <code>der = TRUE</code>.</p>
+<pre class="r"><code>read_pubkey(bin, der = TRUE)</code></pre>
+<pre><code>[256-bit ecdsa public key]
+md5: f159c220b15ae8a04217efd0b7c4ba3f</code></pre>
+<p>Users typically don’t need to worry about the key’s underlying primes, but have a look at <code>key$data</code> if you are curious.</p>
+</div>
+<div id="the-pem-format" class="section level3">
+<h3>The PEM format</h3>
+<p>In practice the user rarely encounters DER because it is mainly for internal use. When humans exchange keys and certificates they typically use the PEM format. PEM is simply <strong>base64 encoded DER data, plus a header</strong>. The header identifies the key (and possibly encryption) type.</p>
+<pre class="r"><code>cat(write_pem(pubkey))</code></pre>
+<pre><code>-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENlIWD4fBLCHgaDiq8A7Asjn3oOD0
+a0VwRgD36YQe9x2g8ofq695lUgxWyGrBpd1wVBUxDngrraWDo0SPoFE9Lg==
+-----END PUBLIC KEY-----</code></pre>
+<pre class="r"><code>cat(write_pem(key, password = NULL))</code></pre>
+<pre><code>-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgv0i+oeC3fRS5L6OZ
+8CK6cfu54oPVCwfnHQQzeYaq+t2hRANCAAQ2UhYPh8EsIeBoOKrwDsCyOfeg4PRr
+RXBGAPfphB73HaDyh+rr3mVSDFbIasGl3XBUFTEOeCutpYOjRI+gUT0u
+-----END PRIVATE KEY-----</code></pre>
+<p>The PEM format allows for protecting private keys with a password. R will prompt you for the password when reading such a protected key.</p>
+<pre class="r"><code>cat(write_pem(key, password = "supersecret"))</code></pre>
+<pre><code>-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHjME4GCSqGSIb3DQEFDTBBMCkGCSqGSIb3DQEFDDAcBAi+mtQXMC/b2QICCAAw
+DAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQItJD+GcKlpYUEgZDl1neZ41iwNxnt
+HmYdCeoPUo4CD3GZXTUz9d16TKxgqd9jhm601z5aNg4PQXTMtctTFc7KP1glUXJo
+ZcTOlRqRDeD1JkR9jt+CXf3cZmx3jP4cLxWgR+J0b+MOwu1qPvMLs7nQGyzHZFJK
+P9fessusSWJPp0KUnOmW0CqZ3Vb7Y1K2yOZDRS2edH3Dnrw2emc=
+-----END ENCRYPTED PRIVATE KEY-----</code></pre>
+</div>
+<div id="the-openssh-format" class="section level3">
+<h3>The OpenSSH format</h3>
+<p>For better or worse, OpenSSH uses a custom format for <strong>public keys</strong>. The advantage of this format is that it fits on a single line which is nice for e.g. your <code>~/.ssh/known_hosts</code> file. There is no special format for private keys, OpenSSH uses PEM as well.</p>
+<pre class="r"><code>str <- write_ssh(pubkey)
+print(str)</code></pre>
+<pre><code>[1] "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDZSFg+HwSwh4Gg4qvAOwLI596Dg9GtFcEYA9+mEHvcdoPKH6uveZVIMVshqwaXdcFQVMQ54K62lg6NEj6BRPS4="</code></pre>
+<p>The <code>read_pubkey</code> function will automatically detect if a file contains a <code>PEM</code> or <code>SSH</code> key.</p>
+<pre class="r"><code>read_pubkey(str)</code></pre>
+<pre><code>[256-bit ecdsa public key]
+md5: f159c220b15ae8a04217efd0b7c4ba3f</code></pre>
+</div>
+<div id="the-json-web-key-jwk-format" class="section level3">
+<h3>The JSON Web Key (JWK) format</h3>
+<p>Yet another recent format to store RSA or EC keys are JSON Web Keys (JWK). JWK is part of the <strong>Javascript Object Signing and Encryption (JOSE)</strong> specification. The <code>write_jwk</code> and <code>read_jwk</code> functions are implemented in a separate package which uses the <code>openssl</code> package.</p>
+<pre class="r"><code>library(jose)
+json <- write_jwk(pubkey)
+jsonlite::prettify(json)</code></pre>
+<pre><code>{
+ "kty": "EC",
+ "crv": "P-256",
+ "x": "NlIWD4fBLCHgaDiq8A7Asjn3oOD0a0VwRgD36YQe9x0",
+ "y": "oPKH6uveZVIMVshqwaXdcFQVMQ54K62lg6NEj6BRPS4"
+}
+ </code></pre>
+<p>Keys from <code>jose</code> and <code>openssl</code> are the same.</p>
+<pre class="r"><code>mykey <- read_jwk(json)
+identical(mykey, pubkey)</code></pre>
+<pre><code>[1] TRUE</code></pre>
+<pre class="r"><code>print(mykey)</code></pre>
+<pre><code>[256-bit ecdsa public key]
+md5: f159c220b15ae8a04217efd0b7c4ba3f</code></pre>
+</div>
+
+
+
+
+</div>
+
+<script>
+
+// add bootstrap table styles to pandoc tables
+function bootstrapStylePandocTables() {
+ $('tr.header').parent('thead').parent('table').addClass('table table-condensed');
+}
+$(document).ready(function () {
+ bootstrapStylePandocTables();
+});
+
+
+</script>
+
+<!-- dynamically load mathjax for compatibility with self-contained -->
+<script>
+ (function () {
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.src = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+ document.getElementsByTagName("head")[0].appendChild(script);
+ })();
+</script>
+
+</body>
+</html>
diff --git a/inst/doc/secure_rng.R b/inst/doc/secure_rng.R
new file mode 100644
index 0000000..cb54454
--- /dev/null
+++ b/inst/doc/secure_rng.R
@@ -0,0 +1,28 @@
+## ---- echo = FALSE, message = FALSE--------------------------------------
+knitr::opts_chunk$set(comment = "")
+library(openssl)
+
+## ------------------------------------------------------------------------
+rnd <- rand_bytes(10)
+print(rnd)
+
+## ------------------------------------------------------------------------
+as.numeric(rnd)
+
+## ------------------------------------------------------------------------
+x <- rand_bytes(1)
+as.logical(rawToBits(x))
+
+## ------------------------------------------------------------------------
+rand_num(10)
+
+## ------------------------------------------------------------------------
+# Secure rnorm
+x <- qnorm(rand_num(1000), mean = 100, sd = 15)
+hist(x)
+
+## ------------------------------------------------------------------------
+# Secure rbinom
+y <- qbinom(rand_num(1000), size = 20, prob = 0.1)
+hist(y, breaks = -.5:(max(y)+1))
+
diff --git a/inst/doc/secure_rng.Rmd b/inst/doc/secure_rng.Rmd
new file mode 100644
index 0000000..07c1b17
--- /dev/null
+++ b/inst/doc/secure_rng.Rmd
@@ -0,0 +1,59 @@
+---
+title: "Generating Secure Random Numbers in R"
+date: "`r Sys.Date()`"
+vignette: >
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteIndexEntry{Generating Secure Random Numbers in R}
+ \usepackage[utf8]{inputenc}
+output:
+ html_document
+---
+
+```{r, echo = FALSE, message = FALSE}
+knitr::opts_chunk$set(comment = "")
+library(openssl)
+```
+
+The `rand_bytes` function binds to [RAND_bytes](https://www.openssl.org/docs/manmaster/man3/RAND_bytes.html) in OpenSSL to generate cryptographically strong pseudo-random bytes. See the OpenSSL documentation for what this means.
+
+```{r}
+rnd <- rand_bytes(10)
+print(rnd)
+```
+
+Bytes are 8 bit and hence can have `2^8 = 256` possible values.
+
+```{r}
+as.numeric(rnd)
+```
+
+Each random byte can be decomposed into 8 random bits (booleans)
+
+```{r}
+x <- rand_bytes(1)
+as.logical(rawToBits(x))
+```
+
+## Secure Random Numbers
+
+`rand_num` is a simple (2 lines) wrapper to `rand_bytes` to generate random numbers (doubles) between 0 and 1.
+
+```{r}
+rand_num(10)
+```
+
+To map random draws from [0,1] into a probability density, we can use a [Cumulative Distribution Function](http://en.wikipedia.org/wiki/Cumulative_distribution_function). For example we can combine `qnorm` and `rand_num` to simulate `rnorm`:
+
+```{r}
+# Secure rnorm
+x <- qnorm(rand_num(1000), mean = 100, sd = 15)
+hist(x)
+```
+
+Same for discrete distributions:
+
+```{r}
+# Secure rbinom
+y <- qbinom(rand_num(1000), size = 20, prob = 0.1)
+hist(y, breaks = -.5:(max(y)+1))
+```
diff --git a/inst/doc/secure_rng.html b/inst/doc/secure_rng.html
new file mode 100644
index 0000000..470b181
--- /dev/null
+++ b/inst/doc/secure_rng.html
@@ -0,0 +1,183 @@
+<!DOCTYPE html>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="pandoc" />
+
+
+
+<meta name="date" content="2016-12-30" />
+
+<title>Generating Secure Random Numbers in R</title>
+
+<script src="data:application/x-javascript;base64,LyohIGpRdWVyeSB2MS4xMS4zIHwgKGMpIDIwMDUsIDIwMTUgalF1ZXJ5IEZvdW5kYXRpb24sIEluYy4gfCBqcXVlcnkub3JnL2xpY2Vuc2UgKi8KIWZ1bmN0aW9uKGEsYil7Im9iamVjdCI9PXR5cGVvZiBtb2R1bGUmJiJvYmplY3QiPT10eXBlb2YgbW9kdWxlLmV4cG9ydHM/bW9kdWxlLmV4cG9ydHM9YS5kb2N1bWVudD9iKGEsITApOmZ1bmN0aW9uKGEpe2lmKCFhLmRvY3VtZW50KXRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpO3JldHVybiBiKGEpfTpiKGEpfSgidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdz93aW5kb3c6dG [...]
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<link href="data:text/css;charset=utf-8,html%7Bfont%2Dfamily%3Asans%2Dserif%3B%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A100%25%3B%2Dms%2Dtext%2Dsize%2Dadjust%3A100%25%7Dbody%7Bmargin%3A0%7Darticle%2Caside%2Cdetails%2Cfigcaption%2Cfigure%2Cfooter%2Cheader%2Chgroup%2Cmain%2Cmenu%2Cnav%2Csection%2Csummary%7Bdisplay%3Ablock%7Daudio%2Ccanvas%2Cprogress%2Cvideo%7Bdisplay%3Ainline%2Dblock%3Bvertical%2Dalign%3Abaseline%7Daudio%3Anot%28%5Bcontrols%5D%29%7Bdisplay%3Anone%3Bheight%3A0%7D%5Bhidden%5D%2Ctem [...]
+<script src="data:application/x-javascript;base64,LyohCiAqIEJvb3RzdHJhcCB2My4zLjUgKGh0dHA6Ly9nZXRib290c3RyYXAuY29tKQogKiBDb3B5cmlnaHQgMjAxMS0yMDE1IFR3aXR0ZXIsIEluYy4KICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlCiAqLwppZigidW5kZWZpbmVkIj09dHlwZW9mIGpRdWVyeSl0aHJvdyBuZXcgRXJyb3IoIkJvb3RzdHJhcCdzIEphdmFTY3JpcHQgcmVxdWlyZXMgalF1ZXJ5Iik7K2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0Ijt2YXIgYj1hLmZuLmpxdWVyeS5zcGxpdCgiICIpWzBdLnNwbGl0KCIuIik7aWYoYlswXTwyJiZiWzFdPDl8fDE9PWJbMF0mJjk9PWJbMV0mJmJbMl08MSl0aHJvdy [...]
+<script src="data:application/x-javascript;base64,LyoqCiogQHByZXNlcnZlIEhUTUw1IFNoaXYgMy43LjIgfCBAYWZhcmthcyBAamRhbHRvbiBAam9uX25lYWwgQHJlbSB8IE1JVC9HUEwyIExpY2Vuc2VkCiovCi8vIE9ubHkgcnVuIHRoaXMgY29kZSBpbiBJRSA4CmlmICghIXdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKCJNU0lFIDgiKSkgewohZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYil7dmFyIGM9YS5jcmVhdGVFbGVtZW50KCJwIiksZD1hLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJoZWFkIilbMF18fGEuZG9jdW1lbnRFbGVtZW50O3JldHVybiBjLmlubmVySFRNTD0ieDxzdHlsZT4iK2IrIjwvc3R5bGU+IixkLm [...]
+<script src="data:application/x-javascript;base64,LyohIFJlc3BvbmQuanMgdjEuNC4yOiBtaW4vbWF4LXdpZHRoIG1lZGlhIHF1ZXJ5IHBvbHlmaWxsICogQ29weXJpZ2h0IDIwMTMgU2NvdHQgSmVobAogKiBMaWNlbnNlZCB1bmRlciBodHRwczovL2dpdGh1Yi5jb20vc2NvdHRqZWhsL1Jlc3BvbmQvYmxvYi9tYXN0ZXIvTElDRU5TRS1NSVQKICogICovCgovLyBPbmx5IHJ1biB0aGlzIGNvZGUgaW4gSUUgOAppZiAoISF3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgiTVNJRSA4IikpIHsKIWZ1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjthLm1hdGNoTWVkaWE9YS5tYXRjaE1lZGlhfHxmdW5jdGlvbihhKXt2YXIgYixjPWEuZG [...]
+<script src="data:application/x-javascript;base64,Cgp3aW5kb3cuYnVpbGRUYWJzZXRzID0gZnVuY3Rpb24odG9jSUQpIHsKCiAgLy8gYnVpbGQgYSB0YWJzZXQgZnJvbSBhIHNlY3Rpb24gZGl2IHdpdGggdGhlIC50YWJzZXQgY2xhc3MKICBmdW5jdGlvbiBidWlsZFRhYnNldCh0YWJzZXQpIHsKCiAgICAvLyBjaGVjayBmb3IgZmFkZSBhbmQgcGlsbHMgb3B0aW9ucwogICAgdmFyIGZhZGUgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1mYWRlIik7CiAgICB2YXIgcGlsbHMgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1waWxscyIpOwogICAgdmFyIG5hdkNsYXNzID0gcGlsbHMgPyAibmF2LXBpbGxzIiA6ICJuYXYtdGFicyI7CgogIC [...]
+<link href="data:text/css;charset=utf-8,pre%20%2Eoperator%2C%0Apre%20%2Eparen%20%7B%0Acolor%3A%20rgb%28104%2C%20118%2C%20135%29%0A%7D%0Apre%20%2Eliteral%20%7B%0Acolor%3A%20%23990073%0A%7D%0Apre%20%2Enumber%20%7B%0Acolor%3A%20%23099%3B%0A%7D%0Apre%20%2Ecomment%20%7B%0Acolor%3A%20%23998%3B%0Afont%2Dstyle%3A%20italic%0A%7D%0Apre%20%2Ekeyword%20%7B%0Acolor%3A%20%23900%3B%0Afont%2Dweight%3A%20bold%0A%7D%0Apre%20%2Eidentifier%20%7B%0Acolor%3A%20rgb%280%2C%200%2C%200%29%3B%0A%7D%0Apre%20%2Estri [...]
+<script src="data:application/x-javascript;base64,dmFyIGhsanM9bmV3IGZ1bmN0aW9uKCl7ZnVuY3Rpb24gbShwKXtyZXR1cm4gcC5yZXBsYWNlKC8mL2dtLCImYW1wOyIpLnJlcGxhY2UoLzwvZ20sIiZsdDsiKX1mdW5jdGlvbiBmKHIscSxwKXtyZXR1cm4gUmVnRXhwKHEsIm0iKyhyLmNJPyJpIjoiIikrKHA/ImciOiIiKSl9ZnVuY3Rpb24gYihyKXtmb3IodmFyIHA9MDtwPHIuY2hpbGROb2Rlcy5sZW5ndGg7cCsrKXt2YXIgcT1yLmNoaWxkTm9kZXNbcF07aWYocS5ub2RlTmFtZT09IkNPREUiKXtyZXR1cm4gcX1pZighKHEubm9kZVR5cGU9PTMmJnEubm9kZVZhbHVlLm1hdGNoKC9ccysvKSkpe2JyZWFrfX19ZnVuY3Rpb24gaCh0LH [...]
+
+<style type="text/css">code{white-space: pre;}</style>
+<style type="text/css">
+ pre:not([class]) {
+ background-color: white;
+ }
+</style>
+<script type="text/javascript">
+if (window.hljs && document.readyState && document.readyState === "complete") {
+ window.setTimeout(function() {
+ hljs.initHighlighting();
+ }, 0);
+}
+</script>
+
+
+
+<style type="text/css">
+h1 {
+ font-size: 34px;
+}
+h1.title {
+ font-size: 38px;
+}
+h2 {
+ font-size: 30px;
+}
+h3 {
+ font-size: 24px;
+}
+h4 {
+ font-size: 18px;
+}
+h5 {
+ font-size: 16px;
+}
+h6 {
+ font-size: 12px;
+}
+.table th:not([align]) {
+ text-align: left;
+}
+</style>
+
+
+</head>
+
+<body>
+
+<style type="text/css">
+.main-container {
+ max-width: 940px;
+ margin-left: auto;
+ margin-right: auto;
+}
+code {
+ color: inherit;
+ background-color: rgba(0, 0, 0, 0.04);
+}
+img {
+ max-width:100%;
+ height: auto;
+}
+.tabbed-pane {
+ padding-top: 12px;
+}
+button.code-folding-btn:focus {
+ outline: none;
+}
+</style>
+
+
+
+<div class="container-fluid main-container">
+
+<!-- tabsets -->
+<script>
+$(document).ready(function () {
+ window.buildTabsets("TOC");
+});
+</script>
+
+<!-- code folding -->
+
+
+
+
+
+
+<div class="fluid-row" id="header">
+
+
+
+<h1 class="title toc-ignore">Generating Secure Random Numbers in R</h1>
+<h4 class="date"><em>2016-12-30</em></h4>
+
+</div>
+
+
+<p>The <code>rand_bytes</code> function binds to <a href="https://www.openssl.org/docs/manmaster/man3/RAND_bytes.html">RAND_bytes</a> in OpenSSL to generate cryptographically strong pseudo-random bytes. See the OpenSSL documentation for what this means.</p>
+<pre class="r"><code>rnd <- rand_bytes(10)
+print(rnd)</code></pre>
+<pre><code> [1] 0a 10 91 01 64 e4 39 ff e4 0b</code></pre>
+<p>Bytes are 8 bit and hence can have <code>2^8 = 256</code> possible values.</p>
+<pre class="r"><code>as.numeric(rnd)</code></pre>
+<pre><code> [1] 10 16 145 1 100 228 57 255 228 11</code></pre>
+<p>Each random byte can be decomposed into 8 random bits (booleans)</p>
+<pre class="r"><code>x <- rand_bytes(1)
+as.logical(rawToBits(x))</code></pre>
+<pre><code>[1] TRUE FALSE TRUE FALSE FALSE FALSE TRUE TRUE</code></pre>
+<div id="secure-random-numbers" class="section level2">
+<h2>Secure Random Numbers</h2>
+<p><code>rand_num</code> is a simple (2 lines) wrapper to <code>rand_bytes</code> to generate random numbers (doubles) between 0 and 1.</p>
+<pre class="r"><code>rand_num(10)</code></pre>
+<pre><code> [1] 0.51264049 0.26298265 0.52894224 0.45853923 0.91369995 0.06634984
+ [7] 0.34697549 0.77925962 0.32352883 0.36852364</code></pre>
+<p>To map random draws from [0,1] into a probability density, we can use a <a href="http://en.wikipedia.org/wiki/Cumulative_distribution_function">Cumulative Distribution Function</a>. For example we can combine <code>qnorm</code> and <code>rand_num</code> to simulate <code>rnorm</code>:</p>
+<pre class="r"><code># Secure rnorm
+x <- qnorm(rand_num(1000), mean = 100, sd = 15)
+hist(x)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABUAAAAPACAYAAAD0ZtPZAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>Same for discrete distributions:</p>
+<pre class="r"><code># Secure rbinom
+y <- qbinom(rand_num(1000), size = 20, prob = 0.1)
+hist(y, breaks = -.5:(max(y)+1))</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABUAAAAPACAYAAAD0ZtPZAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+</div>
+
+
+
+
+</div>
+
+<script>
+
+// add bootstrap table styles to pandoc tables
+function bootstrapStylePandocTables() {
+ $('tr.header').parent('thead').parent('table').addClass('table table-condensed');
+}
+$(document).ready(function () {
+ bootstrapStylePandocTables();
+});
+
+
+</script>
+
+<!-- dynamically load mathjax for compatibility with self-contained -->
+<script>
+ (function () {
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.src = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+ document.getElementsByTagName("head")[0].appendChild(script);
+ })();
+</script>
+
+</body>
+</html>
diff --git a/man/aes_cbc.Rd b/man/aes_cbc.Rd
new file mode 100644
index 0000000..969a1e9
--- /dev/null
+++ b/man/aes_cbc.Rd
@@ -0,0 +1,56 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/aes.R
+\name{aes_cbc}
+\alias{aes_cbc}
+\alias{aes_ctr_encrypt}
+\alias{aes_ctr_decrypt}
+\alias{aes_cbc_encrypt}
+\alias{aes_cbc_decrypt}
+\alias{aes_gcm_encrypt}
+\alias{aes_gcm_decrypt}
+\alias{aes_keygen}
+\title{Symmetric AES encryption}
+\usage{
+aes_ctr_encrypt(data, key, iv = rand_bytes(16))
+
+aes_ctr_decrypt(data, key, iv = attr(data, "iv"))
+
+aes_cbc_encrypt(data, key, iv = rand_bytes(16))
+
+aes_cbc_decrypt(data, key, iv = attr(data, "iv"))
+
+aes_gcm_encrypt(data, key, iv = rand_bytes(16))
+
+aes_gcm_decrypt(data, key, iv = attr(data, "iv"))
+
+aes_keygen(length = 16)
+}
+\arguments{
+\item{data}{raw vector or path to file with data to encrypt or decrypt}
+
+\item{key}{raw vector of length 16, 24 or 32, e.g. the hash of a shared secret}
+
+\item{iv}{raw vector of length 16 (aes block size) or NULL. The initialization vector
+is not secret but should be random}
+
+\item{length}{how many bytes to generate. Usually 16 (128-bit) or 12 (92-bit) for \code{aes_gcm}}
+}
+\description{
+Low-level symmetric encryption/decryption using the AES block cipher in CBC mode.
+The key is a raw vector, for example a hash of some secret. When no shared
+secret is available, a random key can be used which is exchanged via an
+asymettric protocol such as RSA. See \code{\link{rsa_encrypt}} for a worked example
+or \code{\link{encrypt_envelope}} for a high-level wrapper combining AES and RSA.
+}
+\examples{
+# aes-256 requires 32 byte key
+passphrase <- charToRaw("This is super secret")
+key <- sha256(passphrase)
+
+# symmetric encryption uses same key for decryption
+x <- serialize(iris, NULL)
+y <- aes_cbc_encrypt(x, key = key)
+x2 <- aes_cbc_decrypt(y, key = key)
+stopifnot(identical(x, x2))
+}
+
diff --git a/man/askpass.Rd b/man/askpass.Rd
new file mode 100644
index 0000000..7469e5f
--- /dev/null
+++ b/man/askpass.Rd
@@ -0,0 +1,17 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/askpass.R
+\name{askpass}
+\alias{askpass}
+\title{Password Prompt Utility}
+\usage{
+askpass(prompt = "Please enter your password: ")
+}
+\arguments{
+\item{prompt}{the string printed when prompting the user for input.}
+}
+\description{
+Function to prompt the user for a password to read a protected private key.
+Frontends can provide a custom password entry widget by setting the \code{askpass}
+option. If no such option is specified we default to \code{\link{readline}}.
+}
+
diff --git a/man/base64_encode.Rd b/man/base64_encode.Rd
new file mode 100644
index 0000000..aeedb7a
--- /dev/null
+++ b/man/base64_encode.Rd
@@ -0,0 +1,29 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/base64.R
+\name{base64_encode}
+\alias{base64_encode}
+\alias{base64_decode}
+\title{Encode and decode base64}
+\usage{
+base64_encode(bin, linebreaks = FALSE)
+
+base64_decode(text)
+}
+\arguments{
+\item{bin}{raw or character vector with data to encode into base64}
+
+\item{linebreaks}{insert linebreaks in the base64 message to make it more readable}
+
+\item{text}{string with base64 data to decode}
+}
+\description{
+Encode and decode binary data into a base64 string. Character vectors are
+automatically collapsed into a single string.
+}
+\examples{
+input <- charToRaw("foo = bar + 5")
+message <- base64_encode(input)
+output <- base64_decode(message)
+identical(output, input)
+}
+
diff --git a/man/bignum.Rd b/man/bignum.Rd
new file mode 100644
index 0000000..887be6f
--- /dev/null
+++ b/man/bignum.Rd
@@ -0,0 +1,50 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/bignum.R
+\name{bignum}
+\alias{bignum}
+\alias{bignum_mod_exp}
+\alias{bignum_mod_inv}
+\title{Big number arithmetic}
+\usage{
+bignum(x, hex = FALSE)
+
+bignum_mod_exp(a, b, m)
+
+bignum_mod_inv(a, m)
+}
+\arguments{
+\item{x}{an integer, string (hex or dec) or raw vector}
+
+\item{hex}{set to TRUE to parse strings as hex rather than decimal notation}
+
+\item{a}{bignum value for \code{(a^b \%\% m)}}
+
+\item{b}{bignum value for \code{(a^b \%\% m)}}
+
+\item{m}{bignum value for \code{(a^b \%\% m)}}
+}
+\description{
+Basic operations for working with large integers. The \code{bignum}
+funtion converts a positive integer, string or raw vector into a bignum type.
+All basic \link{Arithmetic} and \link{Comparison} operators such as
+\code{+}, \code{-}, \code{*}, \code{^}, \code{\%\%}, \code{\%/\%}, \code{==},
+\code{!=}, \code{<}, \code{<=}, \code{>} and \code{>=} are implemented for
+bignum objects. The
+\href{https://en.wikipedia.org/wiki/Modular_exponentiation}{Modular exponenent}
+(\code{a^b \%\% m}) can be calculated using \code{\link{bignum_mod_exp}}
+when \code{b} is too large for calculating \code{a^b} directly.
+}
+\examples{
+# create a bignum
+x <- bignum(123L)
+y <- bignum("123456789123456789")
+z <- bignum("D41D8CD98F00B204E9800998ECF8427E", hex = TRUE)
+
+# Basic arithmetic
+div <- z \%/\% y
+mod <- z \%\% y
+z2 <- div * y + mod
+stopifnot(z2 == z)
+stopifnot(div < z)
+}
+
diff --git a/man/certificates.Rd b/man/certificates.Rd
new file mode 100644
index 0000000..3de6cf5
--- /dev/null
+++ b/man/certificates.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/cert.R
+\name{cert_verify}
+\alias{cert_verify}
+\alias{download_ssl_cert}
+\alias{ca_bundle}
+\title{X509 certificates}
+\usage{
+cert_verify(cert, root = ca_bundle())
+
+download_ssl_cert(host = "localhost", port = 443)
+
+ca_bundle()
+}
+\arguments{
+\item{cert}{certficate (or certificate-chain) to be verified. Must be cert or list or path.}
+
+\item{root}{trusted pubkey or certificate(s) e.g. CA bundle.}
+
+\item{host}{string: hostname of the server to connect to}
+
+\item{port}{string or integer: port or protocol to use, e.g: \code{443} or \code{"https"}}
+}
+\description{
+Read, download, analyize and verify X.509 certificates.
+}
+\details{
+If https verification fails and you can't figure out why, have a look
+at \url{https://ssldecoder.org}.
+}
+\examples{
+# Verify the r-project HTTPS cert
+chain <- download_ssl_cert("www.r-project.org", 443)
+print(chain)
+print(as.list(chain[[1]])$pubkey)
+cert_verify(chain, ca_bundle())
+
+# Another example
+chain <- download_ssl_cert("public.opencpu.org")
+ocpu <- chain[[1]]
+as.list(ocpu)$subject
+
+# Write PEM format
+write_pem(ocpu)
+}
+\seealso{
+\link{read_cert}
+}
+
diff --git a/man/ec_dh.Rd b/man/ec_dh.Rd
new file mode 100644
index 0000000..b3a7e27
--- /dev/null
+++ b/man/ec_dh.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/diffie.R
+\name{ec_dh}
+\alias{ec_dh}
+\title{Diffie-Hellman Key Agreement}
+\usage{
+ec_dh(key = my_key(), peerkey, password = askpass)
+}
+\arguments{
+\item{key}{your own private key}
+
+\item{peerkey}{the public key from your peer}
+
+\item{password}{passed to \link{read_key} for reading protected private keys}
+}
+\description{
+Key agreement is one-step method of creating a shared secret between two
+peers. Both peers can indendently derive the joined secret by combining
+his or her private key with the public key from the peer.
+}
+\details{
+Currently only Elliptic Curve Diffie Hellman (ECDH) is implemented.
+}
+\examples{
+\dontrun{
+# Need two EC keypairs from the same curve
+alice_key <- ec_keygen("P-521")
+bob_key <- ec_keygen("P-521")
+
+# Derive public keys
+alice_pub <- as.list(alice_key)$pubkey
+bob_pub <- as.list(bob_key)$pubkey
+
+# Both peers can derive the (same) shared secret via each other's pubkey
+ec_dh(alice_key, bob_pub)
+ec_dh(bob_key, alice_pub)
+}
+}
+\references{
+\url{https://wiki.openssl.org/index.php/EVP_Key_Agreement},
+\url{https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman}
+}
+
diff --git a/man/encrypt_envelope.Rd b/man/encrypt_envelope.Rd
new file mode 100644
index 0000000..163bab9
--- /dev/null
+++ b/man/encrypt_envelope.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/envelope.R
+\name{encrypt_envelope}
+\alias{encrypt_envelope}
+\alias{envelope}
+\alias{decrypt_envelope}
+\title{Envelope encryption}
+\usage{
+encrypt_envelope(data, pubkey = my_pubkey())
+
+decrypt_envelope(data, iv, session, key = my_key(), password)
+}
+\arguments{
+\item{data}{raw data vector or file path for message to be signed.
+If \code{hash == NULL} then \code{data} must be a hash string or raw vector.}
+
+\item{pubkey}{public key or file path. See \code{\link{read_pubkey}}.}
+
+\item{iv}{16 byte raw vector returned by \code{encrypt_envelope}.}
+
+\item{session}{raw vector with encrypted session key as returned by \code{encrypt_envelope}.}
+
+\item{key}{private key or file path. See \code{\link{read_key}}.}
+
+\item{password}{string or a function to read protected keys. See \code{\link{read_key}}.}
+}
+\description{
+An \href{https://wiki.openssl.org/index.php/EVP_Asymmetric_Encryption_and_Decryption_of_an_Envelope}{envelope}
+contains ciphertext along with an encrypted session key and optionally and initialiation
+vector. The \code{\link{encrypt_envelope}} generates a random IV and session-key which is
+used to encrypt the \code{data} with \code{\link[openssl:aes_cbc]{AES}} stream cipher. The
+session key itself is encrypted using the given RSA key (see \code{\link{rsa_encrypt}}) and
+stored or sent along with the encrypted data. Each of these outputs is required to decrypt
+the data with the corresponding private key.
+}
+\examples{
+# Requires RSA key
+key <- rsa_keygen()
+pubkey <- key$pubkey
+msg <- serialize(iris, NULL)
+
+# Encrypt
+out <- encrypt_envelope(msg, pubkey)
+str(out)
+
+# Decrypt
+orig <- decrypt_envelope(out$data, out$iv, out$session, key)
+stopifnot(identical(msg, orig))
+}
+\references{
+\url{https://wiki.openssl.org/index.php/EVP_Asymmetric_Encryption_and_Decryption_of_an_Envelope}
+}
+
diff --git a/man/fingerprint.Rd b/man/fingerprint.Rd
new file mode 100644
index 0000000..b0c7141
--- /dev/null
+++ b/man/fingerprint.Rd
@@ -0,0 +1,33 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/openssh.R
+\name{fingerprint}
+\alias{fingerprint}
+\title{OpenSSH fingerprint}
+\usage{
+fingerprint(key, hashfun = md5)
+}
+\arguments{
+\item{key}{a public or private key}
+
+\item{hashfun}{which hash function to use to calculate the fingerprint}
+}
+\description{
+Calculates the OpenSSH fingerprint of a public key. This value should
+match what you get to see when connecting with SSH to a server. Note
+that some other systems might use a different algorithm to derive a
+(different) fingerprint for the same keypair.
+}
+\examples{
+mykey <- rsa_keygen()
+pubkey <- as.list(mykey)$pubkey
+fingerprint(mykey)
+fingerprint(pubkey)
+
+# Some systems use other hash functions
+fingerprint(pubkey, sha1)
+fingerprint(pubkey, sha256)
+
+# Other key types
+fingerprint(dsa_keygen())
+}
+
diff --git a/man/hash.Rd b/man/hash.Rd
new file mode 100644
index 0000000..5d9f5ac
--- /dev/null
+++ b/man/hash.Rd
@@ -0,0 +1,108 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/hash.R
+\name{hashing}
+\alias{hashing}
+\alias{sha1}
+\alias{hmac}
+\alias{mac}
+\alias{sha224}
+\alias{sha256}
+\alias{sha384}
+\alias{sha512}
+\alias{sha2}
+\alias{md4}
+\alias{md5}
+\alias{blake2b}
+\alias{blake2s}
+\alias{ripemd160}
+\title{Vectorized hash/hmac functions}
+\usage{
+sha1(x, key = NULL)
+
+sha224(x, key = NULL)
+
+sha256(x, key = NULL)
+
+sha384(x, key = NULL)
+
+sha512(x, key = NULL)
+
+sha2(x, size = 256, key = NULL)
+
+md4(x, key = NULL)
+
+md5(x, key = NULL)
+
+blake2b(x, key = NULL)
+
+blake2s(x, key = NULL)
+
+ripemd160(x, key = NULL)
+}
+\arguments{
+\item{x}{character vector, raw vector or connection object.}
+
+\item{key}{string or raw vector used as the key for HMAC hashing}
+
+\item{size}{must be equal to 224 256 384 or 512}
+}
+\description{
+All hash functions either calculate a hash-digest for \code{key == NULL} or HMAC
+(hashed message authentication code) when \code{key} is not \code{NULL}. Supported
+inputs are binary (raw vector), strings (character vector) or a connection object.
+}
+\details{
+Functions are vectorized for the case of character vectors: a vector with \code{n}
+strings returns \code{n} hashes. When passing a connection object, the contents will
+be stream-hashed which minimizes the amount of required memory. This is recommended
+for hashing files from disk or network.
+
+The sha2 family of algorithms (sha224, sha256, sha384 and sha512) is generally
+recommended for sensitive information. While sha1 and md5 are usually sufficient for
+collision-resistant identifiers, they are no longer considered secure for cryptographic
+purposes.
+
+In applications where hashes should be irreversible (such as names or passwords) it is
+often recommended to use a random \emph{key} for HMAC hashing. This prevents attacks where
+we can lookup hashes of common and/or short strings. See examples. A common special case
+is adding a random salt to a large number of records to test for uniqueness within the
+dataset, while simultaneously rendering the results incomparable to other datasets.
+
+The \code{blake2b} and \code{blake2s} algorithms are only available if your system has
+libssl 1.1 or newer.
+}
+\examples{
+# Support both strings and binary
+md5(c("foo", "bar"))
+md5("foo", key = "secret")
+
+hash <- md5(charToRaw("foo"))
+as.character(hash, sep = ":")
+
+# Compare to digest
+digest::digest("foo", "md5", serialize = FALSE)
+
+# Other way around
+digest::digest(cars, skip = 0)
+md5(serialize(cars, NULL))
+
+# Stream-verify from connections (including files)
+myfile <- system.file("CITATION")
+md5(file(myfile))
+md5(file(myfile), key = "secret")
+
+\dontrun{check md5 from: http://cran.r-project.org/bin/windows/base/old/3.1.1/md5sum.txt
+md5(url("http://cran.r-project.org/bin/windows/base/old/3.1.1/R-3.1.1-win.exe"))}
+
+# Use a salt to prevent dictionary attacks
+sha1("admin") # googleable
+sha1("admin", key = "random_salt_value") #not googleable
+
+# Use a random salt to identify duplicates while anonymizing values
+sha256("john") # googleable
+sha256(c("john", "mary", "john"), key = "random_salt_value")
+}
+\references{
+Digest types: \url{https://www.openssl.org/docs/manmaster/man1/dgst.html}
+}
+
diff --git a/man/keygen.Rd b/man/keygen.Rd
new file mode 100644
index 0000000..4c9beed
--- /dev/null
+++ b/man/keygen.Rd
@@ -0,0 +1,35 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/keygen.R
+\name{keygen}
+\alias{keygen}
+\alias{rsa_keygen}
+\alias{dsa_keygen}
+\alias{ec_keygen}
+\title{Generate Key pair}
+\usage{
+rsa_keygen(bits = 2048)
+
+dsa_keygen(bits = 1024)
+
+ec_keygen(curve = c("P-256", "P-384", "P-521"))
+}
+\arguments{
+\item{bits}{bitsize of the generated RSA/DSA key}
+
+\item{curve}{which NIST curve to use}
+}
+\description{
+The \code{keygen} functions generate a random private key. Use \code{as.list(key)$pubkey}
+to derive the corresponding public key. Use \link{write_pem} to save a private key
+to a file, optionally with a password.
+}
+\examples{
+# Generate keypair
+key <- rsa_keygen()
+pubkey <- as.list(key)$pubkey
+
+# Write/read the key with a passphrase
+write_pem(key, "id_rsa", password = "supersecret")
+read_key("id_rsa", password = "supersecret")
+}
+
diff --git a/man/my_key.Rd b/man/my_key.Rd
new file mode 100644
index 0000000..dce3eca
--- /dev/null
+++ b/man/my_key.Rd
@@ -0,0 +1,34 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/mykey.R
+\name{my_key}
+\alias{my_key}
+\alias{my_pubkey}
+\title{Default keypair}
+\usage{
+my_key()
+
+my_pubkey()
+}
+\description{
+Set a default keypair via \code{USER_KEY} and \code{USER_PUKBEY} variables.
+}
+\details{
+The \code{my_key()} function checks environment variable \code{USER_KEY} for a
+path to a private keyfile. If unset it defaults to \code{"~/.ssh/id_rsa"}.
+
+The \code{my_pubkey()} function first tries \code{USER_PUBKEY} and if unset
+it checks for \code{USER_KEY} to derive the corresponding pubkey. If both are
+unset it defaults to \code{"~/.ssh/id_rsa.pub"}.
+}
+\examples{
+# Set random RSA key as default
+key <- rsa_keygen()
+write_pem(key, tmp <- tempfile(), password = "")
+rm(key)
+Sys.setenv("USER_KEY" = tmp)
+
+# Check the new keys
+print(my_key())
+print(my_pubkey())
+}
+
diff --git a/man/openssl.Rd b/man/openssl.Rd
new file mode 100644
index 0000000..92129ed
--- /dev/null
+++ b/man/openssl.Rd
@@ -0,0 +1,27 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/openssl.R
+\docType{package}
+\name{openssl}
+\alias{openssl}
+\alias{openssl-package}
+\alias{openssl-package}
+\title{Toolkit for Encryption, Signatures and Certificates based on OpenSSL}
+\description{
+Bindings to OpenSSL libssl and libcrypto, plus custom SSH \link[openssl:read_key]{pubkey}
+parsers. Supports RSA, DSA and NIST curves P-256, P-384 and P-521. Cryptographic
+\link[openssl:signature_verify]{signatures} can either be created and verified
+manually or via x509 \link[openssl:cert_verify]{certificates}. The
+\link[openssl:aes_cbc]{AES block cipher} is used in CBC mode for symmetric
+encryption; RSA for \link[openssl:rsa_encrypt]{asymmetric (public key)}
+encryption. High-level \link[openssl:encrypt_envelope]{envelope} methods
+combine RSA and AES for encrypting arbitrary sized data. Other utilities include
+\link[openssl:rsa_keygen]{key generators}, hash functions (\code{\link[openssl:md5]{md5}},
+\code{\link[openssl:sha1]{sha1}}, \code{\link[openssl:sha256]{sha256}}, etc),
+\code{\link[openssl:base64_encode]{base64}} encoder, a secure \link[openssl:rand_bytes]{random number generator},
+and \code{\link[openssl:bignum]{bignum}} math methods for manually performing crypto
+calculations on large multibyte integers.
+}
+\author{
+Jeroen Ooms, Oliver Keyes
+}
+
diff --git a/man/openssl_config.Rd b/man/openssl_config.Rd
new file mode 100644
index 0000000..edb9180
--- /dev/null
+++ b/man/openssl_config.Rd
@@ -0,0 +1,12 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/info.R
+\name{openssl_config}
+\alias{openssl_config}
+\title{OpenSSL Configuration Info}
+\usage{
+openssl_config()
+}
+\description{
+Shows libssl version and configuration information.
+}
+
diff --git a/man/pkcs12.Rd b/man/pkcs12.Rd
new file mode 100644
index 0000000..35301f4
--- /dev/null
+++ b/man/pkcs12.Rd
@@ -0,0 +1,55 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/pkcs12.R
+\name{write_p12}
+\alias{write_p12}
+\alias{pkcs12}
+\alias{pfx}
+\alias{write_p7b}
+\alias{read_p12}
+\alias{read_p7b}
+\title{PKCS7 / PKCS12 bundles}
+\usage{
+write_p12(key = NULL, cert = NULL, ca = NULL, name = NULL,
+ password = NULL, path = NULL)
+
+write_p7b(ca, path = NULL)
+
+read_p12(file, password = askpass)
+
+read_p7b(file, der = is.raw(file))
+}
+\arguments{
+\item{key}{a private key}
+
+\item{cert}{certificate that matches `key`}
+
+\item{ca}{a list of certificates (the CA chain)}
+
+\item{name}{a friendly title for the bundle}
+
+\item{password}{string or function to set/get the password.}
+
+\item{path}{a file where to write the output to. If `NULL` the output is returned
+as a raw vector.}
+
+\item{file}{path or raw vector with binary PKCS12 data to parse}
+
+\item{der}{set to TRUE for binary files and FALSE for PEM files}
+}
+\description{
+PKCS7 and PKCS12 are container formats for storing multiple certificates and/or keys.
+}
+\details{
+The PKCS#7 or P7B format is a container for one or more certificates. It can either
+be stored in binary form or in a PEM file. P7B files are typically used to import
+and export public certificates.
+
+The PKCS#12 or PFX format is a binary-only format for storing the server certificate,
+any intermediate certificates, and the private key into a single encryptable file.
+PFX files are usually found with the extensions .pfx and .p12. PFX files are typically
+used to import and export certificates with their private keys.
+
+The PKCS formats also allow for including signatures and CRLs but this is quite rare
+and these are currently ignored.
+}
+
diff --git a/man/rand_bytes.Rd b/man/rand_bytes.Rd
new file mode 100644
index 0000000..43afc11
--- /dev/null
+++ b/man/rand_bytes.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rand.R
+\name{rand_bytes}
+\alias{rand_bytes}
+\alias{rand_num}
+\alias{rand_num}
+\title{Generate random bytes and numbers with OpenSSL}
+\usage{
+rand_bytes(n = 1)
+
+rand_num(n = 1)
+}
+\arguments{
+\item{n}{number of random bytes or numbers to generate}
+}
+\description{
+this set of functions generates random bytes or numbers from OpenSSL. This
+provides a cryptographically secure alternative to R's default random number generator.
+\code{rand_bytes} generates \code{n} random cryptographically secure bytes
+}
+\examples{
+rnd <- rand_bytes(10)
+as.numeric(rnd)
+as.character(rnd)
+as.logical(rawToBits(rnd))
+
+# bytes range from 0 to 255
+rnd <- rand_bytes(100000)
+hist(as.numeric(rnd), breaks=-1:255)
+
+# Generate random doubles between 0 and 1
+rand_num(5)
+
+# Use CDF to map [0,1] into random draws from a distribution
+x <- qnorm(rand_num(1000), mean=100, sd=15)
+hist(x)
+
+y <- qbinom(rand_num(1000), size=10, prob=0.3)
+hist(y)
+}
+\references{
+OpenSSL manual: \url{https://www.openssl.org/docs/manmaster/man3/RAND_bytes.html}
+}
+
diff --git a/man/read_key.Rd b/man/read_key.Rd
new file mode 100644
index 0000000..934d237
--- /dev/null
+++ b/man/read_key.Rd
@@ -0,0 +1,71 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/read.R
+\name{read_key}
+\alias{read_key}
+\alias{read_pubkey}
+\alias{read_cert}
+\alias{read_cert_bundle}
+\alias{read_pem}
+\title{Parsing keys and certificates}
+\usage{
+read_key(file, password = askpass, der = is.raw(file))
+
+read_pubkey(file, der = is.raw(file))
+
+read_cert(file, der = is.raw(file))
+
+read_cert_bundle(file)
+
+read_pem(file)
+}
+\arguments{
+\item{file}{Either a path to a file, a connection, or literal data (a string for
+pem/ssh format, or a raw vector in der format)}
+
+\item{password}{A string or callback function to read protected keys}
+
+\item{der}{set to \code{TRUE} if \code{file} is in binary DER format}
+}
+\value{
+An object of class \code{cert}, \code{key} or \code{pubkey} which holds the data
+in binary DER format and can be decomposed using \code{as.list}.
+}
+\description{
+The \code{read_key} function (private keys) and \code{read_pubkey} (public keys)
+support both SSH pubkey format and OpenSSL PEM format (base64 data with a \code{--BEGIN}
+and \code{---END} header), and automatically convert where necessary. The functions assume
+a single key per file except for \code{read_cert_bundle} which supports PEM files
+with multiple certificates.
+
+The `read_pem` function parses the PEM file into a header and a data payload. It
+is mostly useful for debugging.
+}
+\details{
+Most versions of OpenSSL support at least RSA, DSA and ECDSA keys. Certificates must
+conform to the X509 standard.
+
+The \code{password} argument is needed when reading keys that are protected with a
+passphrase. It can either be a string containing the passphrase, or a custom calback
+function that will be called by OpenSSL to read the passphrase. The function should
+take one argument (a string with a message) and return a string. The default is to
+use \code{readline} which will prompt the user in an interactive R session.
+}
+\examples{
+\dontrun{# Read private key
+key <- read_key("~/.ssh/id_rsa")
+str(key)
+
+# Read public key
+pubkey <- read_pubkey("~/.ssh/id_rsa.pub")
+str(pubkey)
+
+# Read certificates
+txt <- readLines("https://curl.haxx.se/ca/cacert.pem")
+bundle <- read_cert_bundle(txt)
+print(bundle)
+}
+}
+\seealso{
+\link{download_ssl_cert}
+}
+
diff --git a/man/rsa_encrypt.Rd b/man/rsa_encrypt.Rd
new file mode 100644
index 0000000..5332ef1
--- /dev/null
+++ b/man/rsa_encrypt.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rsa.R
+\name{rsa_encrypt}
+\alias{rsa_encrypt}
+\alias{rsa}
+\alias{encrypt}
+\alias{rsa_decrypt}
+\title{Low-level RSA encryption}
+\usage{
+rsa_encrypt(data, pubkey = my_pubkey())
+
+rsa_decrypt(data, key = my_key(), password = askpass)
+}
+\arguments{
+\item{data}{raw vector of max 245 bytes (for 2048 bit keys) with data to encrypt/decrypt}
+
+\item{pubkey}{public key or file path. See \code{\link{read_pubkey}}.}
+
+\item{key}{private key or file path. See \code{\link{read_key}}.}
+
+\item{password}{string or a function to read protected keys. See \code{\link{read_key}}.}
+}
+\description{
+Asymmetric encryption and decryption with RSA. Because RSA can only encrypt messages
+smaller than the size of the key, it is typically used only for exchanging a random
+session-key. This session key is used to encipher arbitrary sized data via a stream
+cipher such as \link{aes_cbc}. See \code{\link{encrypt_envelope}} for a high-level
+wrappers combining RSA and AES in this way.
+}
+\examples{
+# Generate test keys
+key <- rsa_keygen()
+pubkey <- key$pubkey
+
+# Encrypt data with AES
+tempkey <- rand_bytes(32)
+iv <- rand_bytes(16)
+blob <- aes_cbc_encrypt(system.file("CITATION"), tempkey, iv = iv)
+
+# Encrypt tempkey using receivers public RSA key
+ciphertext <- rsa_encrypt(tempkey, pubkey)
+
+# Receiver decrypts tempkey from private RSA key
+tempkey <- rsa_decrypt(ciphertext, key)
+message <- aes_cbc_decrypt(blob, tempkey, iv)
+out <- rawToChar(message)
+}
+
diff --git a/man/signatures.Rd b/man/signatures.Rd
new file mode 100644
index 0000000..ef05720
--- /dev/null
+++ b/man/signatures.Rd
@@ -0,0 +1,51 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/signing.R
+\name{signature_create}
+\alias{signature_create}
+\alias{signature_verify}
+\title{Signatures}
+\usage{
+signature_create(data, hash = sha1, key = my_key(), password = askpass)
+
+signature_verify(data, sig, hash = sha1, pubkey = my_pubkey())
+}
+\arguments{
+\item{data}{raw data vector or file path for message to be signed.
+If \code{hash == NULL} then \code{data} must be a hash string or raw vector.}
+
+\item{hash}{the digest function to use. Must be one of \code{\link{md5}},
+\code{\link{sha1}}, \code{\link{sha256}}, \code{\link{sha512}} or \code{NULL}.}
+
+\item{key}{private key or file path. See \code{\link{read_key}}.}
+
+\item{password}{string or a function to read protected keys. See \code{\link{read_key}}.}
+
+\item{sig}{raw vector or file path for the signature data.}
+
+\item{pubkey}{public key or file path. See \code{\link{read_pubkey}}.}
+}
+\description{
+Sign and verify a message digest. RSA supports both MD5 and SHA signatures
+whereas DSA and EC keys only support SHA.
+}
+\examples{
+# Generate a keypair
+key <- rsa_keygen()
+pubkey <- key$pubkey
+
+# Sign a file
+data <- system.file("DESCRIPTION")
+sig <- signature_create(data, key = key)
+stopifnot(signature_verify(data, sig, pubkey = pubkey))
+
+# Sign raw data
+data <- serialize(iris, NULL)
+sig <- signature_create(data, sha256, key = key)
+stopifnot(signature_verify(data, sig, sha256, pubkey = pubkey))
+
+# Sign a hash
+md <- md5(data)
+sig <- signature_create(md, hash = NULL, key = key)
+stopifnot(signature_verify(md, sig, hash = NULL, pubkey = pubkey))
+}
+
diff --git a/man/write_pem.Rd b/man/write_pem.Rd
new file mode 100644
index 0000000..901c3d2
--- /dev/null
+++ b/man/write_pem.Rd
@@ -0,0 +1,39 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/write.R, R/writessh.R
+\name{write_pem}
+\alias{write_pem}
+\alias{write_der}
+\alias{write_ssh}
+\title{Export key or certificate}
+\usage{
+write_pem(x, path = NULL, password = NULL)
+
+write_der(x, path = NULL)
+
+write_ssh(pubkey, path = NULL)
+}
+\arguments{
+\item{x}{a public/private key or certificate object}
+
+\item{path}{file to write to. If \code{NULL} it returns the output as a string.}
+
+\item{password}{string or callback function to set password (only applicable for
+private keys).}
+
+\item{pubkey}{a public key}
+}
+\description{
+The \code{write_pem} functions exports a key or certificate to the standard
+base64 PEM format. For private keys it is possible to set a password.
+}
+\examples{
+# Generate RSA keypair
+key <- rsa_keygen()
+pubkey <- key$pubkey
+
+# Write to output formats
+write_ssh(pubkey)
+write_pem(pubkey)
+write_pem(key, password = "super secret")
+}
+
diff --git a/src/Makevars.in b/src/Makevars.in
new file mode 100644
index 0000000..b6b9431
--- /dev/null
+++ b/src/Makevars.in
@@ -0,0 +1,7 @@
+PKG_CPPFLAGS=@cflags@
+PKG_LIBS=@libs@
+
+all: clean
+
+clean:
+ rm -f $(OBJECTS) $(SHLIB)
diff --git a/src/Makevars.win b/src/Makevars.win
new file mode 100644
index 0000000..27959ca
--- /dev/null
+++ b/src/Makevars.win
@@ -0,0 +1,11 @@
+PKG_CPPFLAGS= -I../windows/openssl-1.1.0c/include
+PKG_LIBS= $(WIN32FIX) -L../windows/openssl-1.1.0c/lib${R_ARCH} -lssl -lcrypto -lws2_32 -lgdi32 -lcrypt32
+WIN32FIX=win32/ipv6.o
+
+all: clean winlibs $(WIN32FIX)
+
+clean:
+ rm -f $(SHLIB) $(OBJECTS) $(WIN32FIX)
+
+winlibs:
+ "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/winlibs.R"
diff --git a/src/aes.c b/src/aes.c
new file mode 100644
index 0000000..7bb1902
--- /dev/null
+++ b/src/aes.c
@@ -0,0 +1,61 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/evp.h>
+#include "utils.h"
+
+/*
+ * Adapted from example at: https://www.openssl.org/docs/crypto/EVP_EncryptInit.html
+ */
+
+SEXP R_aes_any(SEXP x, SEXP key, SEXP iv, SEXP encrypt, SEXP cipher) {
+ int strength = LENGTH(key);
+ if(strength != 16 && strength != 24 && strength != 32)
+ error("key must be of length 16 (aes-128), 24 (aes-192) or 32 (aes-256)");
+
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+ const EVP_CIPHER *cph = EVP_get_cipherbyname(CHAR(STRING_ELT(cipher, 0)));
+ if(!cph)
+ Rf_error("Invalid cipher: %s", CHAR(STRING_ELT(cipher, 0)));
+
+#ifdef EVP_CIPH_GCM_MODE //openssl 1.0.0 does not have GCM
+ if(EVP_CIPHER_mode(cph) == EVP_CIPH_GCM_MODE){
+ //GCM mode has shorter IV from the others
+ bail(EVP_CipherInit_ex(ctx, cph, NULL, NULL, NULL, asLogical(encrypt)));
+ bail(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, LENGTH(iv), NULL));
+ } else
+#endif //EVP_CIPH_GCM_MODE
+ if(LENGTH(iv) != 16){
+ Rf_error("aes requires an iv of length 16");
+ }
+ bail(EVP_CipherInit_ex(ctx, cph, NULL, RAW(key), RAW(iv), asLogical(encrypt)));
+
+ int blocksize = EVP_CIPHER_CTX_block_size(ctx);
+ int remainder = LENGTH(x) % blocksize;
+ int outlen = LENGTH(x) + blocksize - remainder;
+ unsigned char *buf = OPENSSL_malloc(outlen);
+ unsigned char *cur = buf;
+
+ int tmp;
+ bail(EVP_CipherUpdate(ctx, cur, &tmp, RAW(x), LENGTH(x)));
+ cur += tmp;
+
+
+#ifdef EVP_CIPH_GCM_MODE //openssl 1.0.0
+ //in GCM mode, res indicates if the security tag was verified successfully.
+ int res = EVP_CipherFinal_ex(ctx, cur, &tmp);
+ if(EVP_CIPHER_mode(cph) != EVP_CIPH_GCM_MODE)
+ bail(res);
+#else
+ EVP_CipherFinal_ex(ctx, cur, &tmp);
+#endif //EVP_CIPH_GCM_MODE
+ cur += tmp;
+
+ int total = cur - buf;
+ EVP_CIPHER_CTX_cleanup(ctx);
+ EVP_CIPHER_CTX_free(ctx);
+ SEXP out = allocVector(RAWSXP, total);
+ memcpy(RAW(out), buf, total);
+ OPENSSL_free(buf);
+ return out;
+}
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 0000000..dd59ec1
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,55 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+#include "utils.h"
+
+SEXP R_base64_encode(SEXP bin, SEXP linebreaks){
+ //setup encoder
+ BIO *bio = BIO_push(BIO_new(BIO_f_base64()), BIO_new(BIO_s_mem()));
+
+ //No linebreaks
+ if(!asLogical(linebreaks))
+ BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
+
+ bail(BIO_set_close(bio, BIO_NOCLOSE));
+ BIO_write(bio, RAW(bin), LENGTH(bin));
+ bail(BIO_flush(bio));
+
+ //Get the output
+ BUF_MEM *buf;
+ BIO_get_mem_ptr(bio, &buf);
+
+ //return a character vector
+ SEXP out = PROTECT(allocVector(STRSXP, 1));
+ SET_STRING_ELT(out, 0, mkCharLen(buf->data, buf->length));
+ UNPROTECT(1);
+
+ //Cleanup and return
+ BIO_free_all(bio);
+ BUF_MEM_free(buf);
+ return out;
+}
+
+SEXP R_base64_decode(SEXP text){
+ int len = LENGTH(STRING_ELT(text, 0));
+ BIO *bio = BIO_push(BIO_new(BIO_f_base64()), BIO_new_mem_buf((void*) CHAR(STRING_ELT(text, 0)), len));
+
+ //Assume on linebreaks
+ BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
+
+ //binary size is always smaller than base64 msg
+ unsigned char *bin = malloc(len);
+ int bin_len = BIO_read(bio, bin, len);
+
+ //create raw output vector
+ SEXP out = PROTECT(allocVector(RAWSXP, bin_len));
+ memcpy(RAW(out), bin, bin_len);
+ UNPROTECT(1);
+
+ //cleanup and return
+ BIO_free_all(bio);
+ free(bin);
+ return out;
+}
diff --git a/src/bignum.c b/src/bignum.c
new file mode 100644
index 0000000..2754039
--- /dev/null
+++ b/src/bignum.c
@@ -0,0 +1,173 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/bn.h>
+#include "utils.h"
+
+BIGNUM *r2bignum(SEXP x){
+ if(!inherits(x, "bignum"))
+ error("Argument is not valid bignum");
+ BIGNUM *val = BN_bin2bn(RAW(x), LENGTH(x), NULL);
+ bail(val != NULL);
+ return val;
+}
+
+SEXP bignum2r(BIGNUM *val){
+ SEXP out = PROTECT(allocVector(RAWSXP, BN_num_bytes(val)));
+ bail(BN_bn2bin(val, RAW(out)) >= 0);
+ setAttrib(out, R_ClassSymbol, mkString("bignum"));
+ UNPROTECT(1);
+ return out;
+}
+
+SEXP R_parse_bignum(SEXP x, SEXP hex){
+ BIGNUM *val = BN_new();
+ if(TYPEOF(x) == RAWSXP){
+ bail(NULL != BN_bin2bn(RAW(x), LENGTH(x), val));
+ } else if(asLogical(hex)){
+ bail(BN_hex2bn(&val, CHAR(STRING_ELT(x, 0))));
+ } else {
+ bail(BN_dec2bn(&val, CHAR(STRING_ELT(x, 0))));
+ }
+ SEXP res = bignum2r(val);
+ BN_free(val);
+ return res;
+}
+
+SEXP R_bignum_as_character(SEXP x, SEXP hex){
+ BIGNUM *val = r2bignum(x);
+ char *str;
+ if(asLogical(hex)){
+ bail(!!(str = BN_bn2hex(val)));
+ } else {
+ bail(!!(str = BN_bn2dec(val)));
+ }
+ SEXP res = mkString(str);
+ OPENSSL_free(str);
+ BN_free(val);
+ return res;
+}
+
+SEXP R_bignum_add(SEXP x, SEXP y){
+ BIGNUM *val1 = r2bignum(x);
+ BIGNUM *val2 = r2bignum(y);
+ BIGNUM *out = BN_new();
+ bail(BN_add(out, val1, val2));
+ SEXP res = bignum2r(out);
+ BN_free(val1);
+ BN_free(val2);
+ BN_free(out);
+ return res;
+}
+
+SEXP R_bignum_subtract(SEXP x, SEXP y){
+ BIGNUM *val1 = r2bignum(x);
+ BIGNUM *val2 = r2bignum(y);
+ BIGNUM *out = BN_new();
+ bail(BN_sub(out, val1, val2));
+ SEXP res = bignum2r(out);
+ BN_free(val1);
+ BN_free(val2);
+ BN_free(out);
+ return res;
+}
+
+SEXP R_bignum_multiply(SEXP x, SEXP y){
+ BIGNUM *val1 = r2bignum(x);
+ BIGNUM *val2 = r2bignum(y);
+ BIGNUM *out = BN_new();
+ BN_CTX *ctx = BN_CTX_new();
+ bail(BN_mul(out, val1, val2, ctx));
+ SEXP res = bignum2r(out);
+ BN_free(val1);
+ BN_free(val2);
+ BN_free(out);
+ BN_CTX_free(ctx);
+ return res;
+}
+
+SEXP R_bignum_devide(SEXP x, SEXP y){
+ BIGNUM *val1 = r2bignum(x);
+ BIGNUM *val2 = r2bignum(y);
+ BIGNUM *out = BN_new();
+ BN_CTX *ctx = BN_CTX_new();
+ bail(BN_div(out, NULL, val1, val2, ctx));
+ SEXP res = bignum2r(out);
+ BN_free(val1);
+ BN_free(val2);
+ BN_free(out);
+ BN_CTX_free(ctx);
+ return res;
+}
+
+SEXP R_bignum_mod(SEXP x, SEXP y){
+ BIGNUM *val1 = r2bignum(x);
+ BIGNUM *val2 = r2bignum(y);
+ BIGNUM *out = BN_new();
+ BN_CTX *ctx = BN_CTX_new();
+ bail(BN_mod(out, val1, val2, ctx));
+ SEXP res = bignum2r(out);
+ BN_free(val1);
+ BN_free(val2);
+ BN_free(out);
+ BN_CTX_free(ctx);
+ return res;
+}
+
+SEXP R_bignum_exp(SEXP x, SEXP y){
+ BIGNUM *val1 = r2bignum(x);
+ BIGNUM *val2 = r2bignum(y);
+ BIGNUM *out = BN_new();
+ BN_CTX *ctx = BN_CTX_new();
+ bail(BN_exp(out, val1, val2, ctx));
+ SEXP res = bignum2r(out);
+ BN_free(val1);
+ BN_free(val2);
+ BN_free(out);
+ BN_CTX_free(ctx);
+ return res;
+}
+
+SEXP R_bignum_mod_exp(SEXP x, SEXP y, SEXP m){
+ BIGNUM *val1 = r2bignum(x);
+ BIGNUM *val2 = r2bignum(y);
+ BIGNUM *val3 = r2bignum(m);
+ BIGNUM *out = BN_new();
+ BN_CTX *ctx = BN_CTX_new();
+ bail(BN_mod_exp(out, val1, val2, val3, ctx));
+ BN_free(val1);
+ BN_free(val2);
+ BN_free(val3);
+ SEXP res = bignum2r(out);
+ BN_free(out);
+ BN_CTX_free(ctx);
+ return res;
+}
+
+SEXP R_bignum_mod_inv(SEXP a, SEXP n){
+ BIGNUM *val1 = r2bignum(a);
+ BIGNUM *val2 = r2bignum(n);
+ BIGNUM *out = BN_new();
+ BN_CTX *ctx = BN_CTX_new();
+ bail(!!BN_mod_inverse(out, val1, val2, ctx));
+ BN_free(val1);
+ BN_free(val2);
+ SEXP res = bignum2r(out);
+ BN_free(out);
+ BN_CTX_free(ctx);
+ return res;
+}
+
+SEXP R_bignum_compare(SEXP x, SEXP y){
+ BIGNUM *val1 = r2bignum(x);
+ BIGNUM *val2 = r2bignum(y);
+ int out = BN_cmp(val1, val2);
+ BN_free(val1);
+ BN_free(val2);
+ return ScalarInteger(out);
+}
+
+SEXP R_bignum_bits(SEXP x){
+ BIGNUM *num = r2bignum(x);
+ return ScalarInteger(BN_num_bits(num));
+}
diff --git a/src/cert.c b/src/cert.c
new file mode 100644
index 0000000..30fb079
--- /dev/null
+++ b/src/cert.c
@@ -0,0 +1,149 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include <openssl/bn.h>
+#include <openssl/x509v3.h>
+#include "utils.h"
+#include "compatibility.h"
+
+SEXP R_cert_info(SEXP bin){
+ X509 *cert = X509_new();
+ const unsigned char *ptr = RAW(bin);
+ bail(!!d2i_X509(&cert, &ptr, LENGTH(bin)));
+
+ //out list
+ int bufsize = 8192;
+ char buf[bufsize];
+ int len;
+ X509_NAME *name;
+ BIO *b;
+ SEXP out = PROTECT(allocVector(VECSXP, 7));
+
+ //Note: for some reason XN_FLAG_MULTILINE messes up UTF8
+
+ //subject name
+ name = X509_get_subject_name(cert);
+ b = BIO_new(BIO_s_mem());
+ bail(X509_NAME_print_ex(b, name, 0, XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB));
+ len = BIO_read(b, buf, bufsize);
+ BIO_free(b);
+ SET_VECTOR_ELT(out, 0, allocVector(STRSXP, 1));
+ SET_STRING_ELT(VECTOR_ELT(out, 0), 0, mkCharLenCE(buf, len, CE_UTF8));
+ X509_NAME_free(name);
+
+ //issuer name name
+ name = X509_get_issuer_name(cert);
+ b = BIO_new(BIO_s_mem());
+ bail(X509_NAME_print_ex(b, name, 0, XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB));
+ len = BIO_read(b, buf, bufsize);
+ BIO_free(b);
+ SET_VECTOR_ELT(out, 1, allocVector(STRSXP, 1));
+ SET_STRING_ELT(VECTOR_ELT(out, 1), 0, mkCharLenCE(buf, len, CE_UTF8));
+ X509_NAME_free(name);
+
+ //sign algorithm
+ const ASN1_BIT_STRING *signature;
+ const X509_ALGOR *sig_alg;
+ MY_X509_get0_signature(&signature, &sig_alg, cert);
+ OBJ_obj2txt(buf, sizeof(buf), sig_alg->algorithm, 0);
+ SET_VECTOR_ELT(out, 2, mkString(buf));
+
+ //signature
+ SET_VECTOR_ELT(out, 3, allocVector(RAWSXP, signature->length));
+ memcpy(RAW(VECTOR_ELT(out, 3)), signature->data, signature->length);
+
+ //start date
+ SET_VECTOR_ELT(out, 4, allocVector(STRSXP, 2));
+ b = BIO_new(BIO_s_mem());
+ bail(ASN1_TIME_print(b, X509_get_notBefore(cert)));
+ len = BIO_read(b, buf, bufsize);
+ BIO_free(b);
+ SET_STRING_ELT(VECTOR_ELT(out, 4), 0, mkCharLen(buf, len));
+
+ //expiration date
+ b = BIO_new(BIO_s_mem());
+ bail(ASN1_TIME_print(b, X509_get_notAfter(cert)));
+ len = BIO_read(b, buf, bufsize);
+ BIO_free(b);
+ SET_STRING_ELT(VECTOR_ELT(out, 4), 1, mkCharLen(buf, len));
+
+ //test for self signed
+ SET_VECTOR_ELT(out, 5, ScalarLogical(X509_verify(cert, X509_get_pubkey(cert))));
+
+ //check for alternative names (requires x509v3 extensions !!)
+ GENERAL_NAMES *subjectAltNames = X509_get_ext_d2i (cert, NID_subject_alt_name, NULL, NULL);
+ int numalts = sk_GENERAL_NAME_num (subjectAltNames);
+ if(numalts > 0) {
+ SET_VECTOR_ELT(out, 6, allocVector(STRSXP, numalts));
+ unsigned char *tmpbuf;
+ for (int i = 0; i < numalts; i++) {
+ const GENERAL_NAME *name = sk_GENERAL_NAME_value(subjectAltNames, i);
+ len = ASN1_STRING_to_UTF8(&tmpbuf, name->d.ia5);
+ if(len > 0){
+ SET_STRING_ELT(VECTOR_ELT(out, 6), i, mkCharLenCE((char*) tmpbuf, len, CE_UTF8));
+ OPENSSL_free(tmpbuf);
+ }
+ }
+ }
+
+ //return
+ UNPROTECT(1);
+ return out;
+}
+
+SEXP R_pubkey_verify_cert(SEXP cert, SEXP pubkey){
+ const unsigned char *ptr = RAW(cert);
+ X509 *crt = d2i_X509(NULL, &ptr, LENGTH(cert));
+ bail(!!crt);
+ const unsigned char *ptr2 = RAW(pubkey);
+ EVP_PKEY *pkey = d2i_PUBKEY(NULL, &ptr2, LENGTH(pubkey));
+ bail(!!pkey);
+ int res = X509_verify(crt, pkey);
+ X509_free(crt);
+ EVP_PKEY_free(pkey);
+ return ScalarLogical(res);
+}
+
+SEXP R_cert_verify_cert(SEXP cert, SEXP chain, SEXP bundle) {
+ /* load cert */
+ const unsigned char *ptr = RAW(cert);
+ X509 *crt = d2i_X509(NULL, &ptr, LENGTH(cert));
+ bail(!!crt);
+
+ /* init ca bundle store */
+ X509_STORE *store = X509_STORE_new();
+ X509_STORE_CTX *ctx = X509_STORE_CTX_new();
+ STACK_OF(X509) *sk = sk_X509_new_null();
+ X509_STORE_CTX_init(ctx, store, crt, sk);
+
+ /* add chain certs */
+ for(int i = 0; i < LENGTH(chain); i++){
+ ptr = RAW(VECTOR_ELT(chain, i));
+ crt = d2i_X509(NULL, &ptr, LENGTH(VECTOR_ELT(chain, i)));
+ bail(!!crt);
+ sk_X509_push(sk, crt);
+ }
+
+ /* Add parent certs */
+ for(int i = 0; i < LENGTH(bundle); i++){
+ ptr = RAW(VECTOR_ELT(bundle, i));
+ crt = d2i_X509(NULL, &ptr, LENGTH(VECTOR_ELT(bundle, i)));
+ bail(!!crt);
+ bail(X509_STORE_add_cert(store, crt));
+ }
+
+ const char *err = NULL;
+ if(X509_verify_cert(ctx) < 1)
+ err = X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx));
+
+ sk_X509_free(sk);
+ X509_STORE_CTX_free(ctx);
+ X509_STORE_free(store);
+ X509_free(crt);
+
+ if(err)
+ error("Certificate validation failed: %s", err);
+
+ return ScalarLogical(TRUE);
+}
diff --git a/src/compatibility.c b/src/compatibility.c
new file mode 100644
index 0000000..543a296
--- /dev/null
+++ b/src/compatibility.c
@@ -0,0 +1,75 @@
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/x509.h>
+
+#include "compatibility.h"
+
+#if ! HAS_OPENSSL11
+
+int MY_RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d){
+ if(n) r->n = n;
+ if(e) r->e = e;
+ if(d) r->d = d;
+ return 1;
+}
+
+int MY_RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q){
+ if(p) r->p = p;
+ if(q) r->q = q;
+ return 1;
+}
+
+int MY_RSA_set0_crt_params(RSA *r,BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp){
+ if(dmp1) r->dmp1 = dmp1;
+ if(dmq1) r->dmq1 = dmq1;
+ if(iqmp) r->iqmp = iqmp;
+ return 1;
+}
+
+void MY_RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d){
+ if(n) *n = r->n;
+ if(e) *e = r->e;
+ if(d) *d = r->d;
+}
+
+void MY_RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q){
+ if(p) *p = r->p;
+ if(q) *q = r->q;
+}
+
+void MY_RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp){
+ if(dmp1) *dmp1 = r->dmp1;
+ if(dmq1) *dmq1 = r->dmq1;
+ if(iqmp) *iqmp = r->iqmp;
+}
+
+int MY_DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g){
+ if(p) d->p = p;
+ if(q) d->q = q;
+ if(g) d->g = g;
+ return 1;
+}
+
+int MY_DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key){
+ if(pub_key) d->pub_key = pub_key;
+ if(priv_key) d->priv_key = priv_key;
+ return 1;
+}
+
+void MY_DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g){
+ if(p) *p = d->p;
+ if(q) *q = d->q;
+ if(g) *g = d->g;
+}
+
+void MY_DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key){
+ if(pub_key) *pub_key = d->pub_key;
+ if(priv_key) *priv_key = d->priv_key;
+}
+
+void MY_X509_get0_signature(const ASN1_BIT_STRING **psig, const X509_ALGOR **palg, const X509 *x){
+ if(psig) *psig = x->signature;
+ if(palg) *palg = x->sig_alg;
+}
+
+#endif
diff --git a/src/compatibility.h b/src/compatibility.h
new file mode 100644
index 0000000..bebaa1f
--- /dev/null
+++ b/src/compatibility.h
@@ -0,0 +1,37 @@
+/* Compatibility stuff for API changes in OpenSSL 1.1 */
+#include <openssl/opensslv.h>
+#if !defined(LIBRESSL_VERSION_NUMBER) && defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100001L
+#define HAS_OPENSSL11 1
+#else
+#define HAS_OPENSSL11 0
+#endif
+
+#if HAS_OPENSSL11
+
+#define MY_RSA_set0_key RSA_set0_key
+#define MY_RSA_set0_factors RSA_set0_factors
+#define MY_RSA_set0_crt_params RSA_set0_crt_params
+#define MY_RSA_get0_key RSA_get0_key
+#define MY_RSA_get0_factors RSA_get0_factors
+#define MY_RSA_get0_crt_params RSA_get0_crt_params
+#define MY_DSA_set0_pqg DSA_set0_pqg
+#define MY_DSA_set0_key DSA_set0_key
+#define MY_DSA_get0_pqg DSA_get0_pqg
+#define MY_DSA_get0_key DSA_get0_key
+#define MY_X509_get0_signature X509_get0_signature
+
+#else
+
+int MY_RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
+int MY_RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
+int MY_RSA_set0_crt_params(RSA *r,BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
+void MY_RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
+void MY_RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
+void MY_RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
+int MY_DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+int MY_DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
+void MY_DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+void MY_DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key);
+void MY_X509_get0_signature(const ASN1_BIT_STRING **psig, const X509_ALGOR **palg, const X509 *x);
+
+#endif
diff --git a/src/diffie.c b/src/diffie.c
new file mode 100644
index 0000000..3bc0593
--- /dev/null
+++ b/src/diffie.c
@@ -0,0 +1,39 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include <openssl/hmac.h>
+#include "utils.h"
+
+/***
+ * example from: https://wiki.openssl.org/index.php/EVP_Key_Agreement
+ *
+ *
+ */
+
+
+SEXP R_diffie_hellman(SEXP key, SEXP peerkey){
+ BIO *mem = BIO_new_mem_buf(RAW(key), LENGTH(key));
+ EVP_PKEY *pkey = d2i_PrivateKey_bio(mem, NULL);
+ BIO_free(mem);
+ bail(!!pkey);
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
+ bail(!!ctx);
+ const unsigned char *ptr = RAW(peerkey);
+ EVP_PKEY *pubkey = d2i_PUBKEY(NULL, &ptr, LENGTH(peerkey));
+ bail(!!pubkey);
+ bail(EVP_PKEY_derive_init(ctx) > 0);
+ bail(EVP_PKEY_derive_set_peer(ctx, pubkey) > 0);
+
+ /* Determine buffer length */
+ size_t skeylen = 0;
+ bail(EVP_PKEY_derive(ctx, NULL, &skeylen) > 0);
+ SEXP out = allocVector(RAWSXP, skeylen);
+ bail(EVP_PKEY_derive(ctx, RAW(out), &skeylen) > 0);
+
+ /* cleanup */
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
+ EVP_PKEY_free(pubkey);
+ return out;
+}
diff --git a/src/envelope.c b/src/envelope.c
new file mode 100644
index 0000000..57bb683
--- /dev/null
+++ b/src/envelope.c
@@ -0,0 +1,96 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include "utils.h"
+
+SEXP R_envelope_encrypt(SEXP data, SEXP pubkey) {
+ /* Input arrays because OpenSSL supports multi-key encryption */
+ const unsigned char *ptr = RAW(pubkey);
+ EVP_PKEY *pkey[1];
+ pkey[0] = d2i_PUBKEY(NULL, &ptr, LENGTH(pubkey));
+ bail(!!pkey[0]);
+
+ /* Encryption context */
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+ bail(!!ctx);
+
+ /* Secret key arrays */
+ int keysize = EVP_PKEY_size(pkey[0]);
+ unsigned char buf[keysize];
+ unsigned char *ek[1];
+ int ekl[1];
+ ek[0] = buf;
+
+ /* Alloc buffers and init */
+ const EVP_CIPHER *cipher = EVP_aes_256_cbc();
+ int ivlen = EVP_CIPHER_iv_length(cipher);
+ unsigned char iv[ivlen];
+ bail(EVP_SealInit(ctx, cipher, ek, ekl, iv, pkey, 1));
+
+ /* This is an overestimate */
+ int len1;
+ unsigned char *out = malloc(LENGTH(data) + 16);
+ bail(EVP_SealUpdate(ctx, out, &len1, RAW(data), LENGTH(data)));
+
+ /* Finalize and cleanup */
+ int len2;
+ bail(EVP_SealFinal(ctx, out + len1, &len2));
+ EVP_PKEY_free(pkey[0]);
+ EVP_CIPHER_CTX_cleanup(ctx);
+ EVP_CIPHER_CTX_free(ctx);
+
+ /* Create output vector */
+ SEXP res = PROTECT(allocVector(VECSXP, 3));
+ SET_VECTOR_ELT(res, 0, allocVector(RAWSXP, ivlen));
+ SET_VECTOR_ELT(res, 1, allocVector(RAWSXP, ekl[0]));
+ SET_VECTOR_ELT(res, 2, allocVector(RAWSXP, len1 + len2));
+ memcpy(RAW(VECTOR_ELT(res, 0)), iv, ivlen);
+ memcpy(RAW(VECTOR_ELT(res, 1)), ek[0], ekl[0]);
+ memcpy(RAW(VECTOR_ELT(res, 2)), out, len1 + len2);
+ free(out);
+ UNPROTECT(1);
+ return res;
+}
+
+SEXP R_envelope_decrypt(SEXP data, SEXP iv, SEXP session, SEXP key) {
+ /* Decryption is done with a single key */
+ BIO *mem = BIO_new_mem_buf(RAW(key), LENGTH(key));
+ EVP_PKEY *pkey = d2i_PrivateKey_bio(mem, NULL);
+ BIO_free(mem);
+ bail(!!pkey);
+
+ /* Encryption context */
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+ bail(!!ctx);
+
+ /* Verify key size */
+ if(LENGTH(session) != EVP_PKEY_size(pkey))
+ error("Invalid Session key, must be %d bytes", EVP_PKEY_size(pkey));
+
+
+ /* Alloc buffers and init */
+ const EVP_CIPHER *cipher = EVP_aes_256_cbc();
+ int ivlen = EVP_CIPHER_iv_length(cipher);
+ if(ivlen != LENGTH(iv))
+ error("Invalid IV, must be %d bytes", ivlen);
+ bail(EVP_OpenInit(ctx, EVP_aes_256_cbc(), RAW(session), LENGTH(session), RAW(iv), pkey));
+
+ /* This is an overestimate */
+ int len1 = 0;
+ unsigned char *out = malloc(LENGTH(data) + 16);
+ bail(EVP_OpenUpdate(ctx, out, &len1, RAW(data), LENGTH(data)));
+
+ /* Finalize and cleanup */
+ int len2 = 0;
+ bail(EVP_OpenFinal(ctx, out + len1, &len2));
+ EVP_PKEY_free(pkey);
+ EVP_CIPHER_CTX_cleanup(ctx);
+ EVP_CIPHER_CTX_free(ctx);
+
+ /* Create RAW vector */
+ SEXP res = allocVector(RAWSXP, len1 + len2);
+ memcpy(RAW(res), out, len1 + len2);
+ free(out);
+ return res;
+}
diff --git a/src/error.c b/src/error.c
new file mode 100644
index 0000000..33f0adb
--- /dev/null
+++ b/src/error.c
@@ -0,0 +1,15 @@
+#include <Rinternals.h>
+#include <openssl/err.h>
+#include "utils.h"
+
+void raise_error(){
+ unsigned long err = ERR_get_error(); //Pops earliest error from the queue
+ ERR_clear_error(); //Removes additional errors (if any) from the queue
+ stop("OpenSSL error in %s: %s", ERR_func_error_string(err), ERR_reason_error_string(err));
+}
+
+void bail(int success){
+ if(!success)
+ raise_error();
+}
+
diff --git a/src/hash.c b/src/hash.c
new file mode 100644
index 0000000..89c730e
--- /dev/null
+++ b/src/hash.c
@@ -0,0 +1,74 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include "utils.h"
+
+/*
+ * Adapted from example at: https://www.openssl.org/docs/crypto/EVP_DigestInit.html
+ */
+
+unsigned int digest_string(unsigned char *x, int len, SEXP key, const char *algo, unsigned char *md_value) {
+
+ /* init openssl stuff */
+ unsigned int md_len;
+ const EVP_MD *md = EVP_get_digestbyname(algo);
+ if(!md)
+ error("Unknown cryptographic algorithm %s\n", algo);
+
+ if(key == R_NilValue){
+ EVP_Digest(x, len, md_value, &md_len, md, NULL);
+ } else {
+ HMAC(md, RAW(key), LENGTH(key), x, len, md_value, &md_len);
+ }
+ return md_len;
+}
+
+SEXP R_digest_raw(SEXP x, SEXP algo, SEXP key){
+ /* Check inputs */
+ if(TYPEOF(x) != RAWSXP)
+ error("Argument 'x' must be a raw vector.");
+
+ /* Convert the Raw vector to an unsigned char */
+ unsigned char md_value[EVP_MAX_MD_SIZE];
+ unsigned int md_len = digest_string(RAW(x), length(x), key, CHAR(asChar(algo)), md_value);
+
+ /* create raw output vector */
+ SEXP out = PROTECT(allocVector(RAWSXP, md_len));
+ memcpy(RAW(out), md_value, md_len);
+ UNPROTECT(1);
+ return out;
+}
+
+SEXP R_digest(SEXP x, SEXP algo, SEXP key){
+ if(!isString(x))
+ error("Argument 'x' must be a character vector.");
+ if(!isString(algo))
+ error("Argument 'algo' must be a character vector.");
+
+ int len = length(x);
+ SEXP out = PROTECT(allocVector(STRSXP, len));
+ for (int i = 0; i < len; i++) {
+ /* check for NA */
+ if(STRING_ELT(x, i) == NA_STRING) {
+ SET_STRING_ELT(out, i, NA_STRING);
+ continue;
+ }
+ /* create hash */
+ const char* str = CHAR(STRING_ELT(x, i));
+ int stringlen = LENGTH(STRING_ELT(x, i));
+ unsigned char md_value[EVP_MAX_MD_SIZE];
+ unsigned int md_len = digest_string( (unsigned char*) str, stringlen, key, CHAR(asChar(algo)), md_value);
+
+ /* create character vector */
+ char mdString[2*md_len+1];
+ for (int i = 0; i < md_len; i++) {
+ sprintf(&mdString[i*2], "%02x", (unsigned int) md_value[i]);
+ }
+ mdString[2*md_len] = '\0';
+ SET_STRING_ELT(out, i, mkChar(mdString));
+ }
+ UNPROTECT(1);
+ return out;
+}
diff --git a/src/info.c b/src/info.c
new file mode 100644
index 0000000..bbe40ed
--- /dev/null
+++ b/src/info.c
@@ -0,0 +1,15 @@
+#include <Rinternals.h>
+#include <openssl/opensslconf.h>
+#include <openssl/opensslv.h>
+
+SEXP R_openssl_config() {
+ int has_ec = 1;
+ #ifdef OPENSSL_NO_EC
+ has_ec = 0;
+ #endif
+ SEXP res = PROTECT(allocVector(VECSXP, 2));
+ SET_VECTOR_ELT(res, 0, mkString(OPENSSL_VERSION_TEXT));
+ SET_VECTOR_ELT(res, 1, ScalarLogical(has_ec));
+ UNPROTECT(1);
+ return res;
+}
diff --git a/src/keygen.c b/src/keygen.c
new file mode 100644
index 0000000..dbbb81f
--- /dev/null
+++ b/src/keygen.c
@@ -0,0 +1,72 @@
+#include <Rinternals.h>
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include "utils.h"
+
+#ifndef OPENSSL_NO_EC
+#include <openssl/ec.h>
+#endif
+
+SEXP R_keygen_rsa(SEXP bits){
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
+ bail(!!ctx);
+ bail(EVP_PKEY_keygen_init(ctx) > 0);
+ bail(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, asInteger(bits)) > 0);
+ EVP_PKEY *pkey = NULL;
+ bail(EVP_PKEY_keygen(ctx, &pkey) > 0);
+ unsigned char *buf = NULL;
+ int len = i2d_PrivateKey(pkey, &buf);
+ bail(len);
+ EVP_PKEY_free(pkey);
+ EVP_PKEY_CTX_free(ctx);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_keygen_dsa(SEXP bits){
+ DSA *dsa = DSA_new();
+ DSA_generate_parameters_ex(dsa, asInteger(bits), NULL, 0, NULL, NULL, NULL);
+ bail(DSA_generate_key(dsa));
+ unsigned char *buf = NULL;
+ int len = i2d_DSAPrivateKey(dsa, &buf);
+ bail(len);
+ DSA_free(dsa);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_keygen_ecdsa(SEXP curve){
+#ifndef OPENSSL_NO_EC
+ int nid = my_nist2nid(CHAR(STRING_ELT(curve, 0)));
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+ bail(!!pctx);
+ EVP_PKEY_paramgen_init(pctx);
+ bail(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid));
+ EVP_PKEY *params = EVP_PKEY_new();
+ bail(EVP_PKEY_paramgen(pctx, ¶ms));
+ EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL);
+ bail(EVP_PKEY_keygen_init(kctx) > 0);
+ EVP_PKEY *pkey = EVP_PKEY_new();
+ bail(EVP_PKEY_keygen(kctx, &pkey) > 0);
+ EC_KEY_set_asn1_flag(EVP_PKEY_get1_EC_KEY(pkey), OPENSSL_EC_NAMED_CURVE);
+ unsigned char *buf = NULL;
+ int len = i2d_PrivateKey(pkey, &buf);
+ bail(len);
+ EVP_PKEY_free(pkey);
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+ EVP_PKEY_CTX_free(pctx);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+#else //OPENSSL_NO_EC
+ Rf_error("OpenSSL has been configured without EC support");
+#endif //OPENSSL_NO_EC
+}
diff --git a/src/keys.c b/src/keys.c
new file mode 100644
index 0000000..0054e97
--- /dev/null
+++ b/src/keys.c
@@ -0,0 +1,142 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include "utils.h"
+#include "compatibility.h"
+
+SEXP R_parse_der_pubkey(SEXP input){
+ const unsigned char *ptr = RAW(input);
+ EVP_PKEY *pkey = d2i_PUBKEY(NULL, &ptr, LENGTH(input));
+ bail(!!pkey);
+ unsigned char *buf = NULL;
+ int len = i2d_PUBKEY(pkey, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_parse_der_key(SEXP input){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ EVP_PKEY *pkey = d2i_PrivateKey_bio(mem, NULL);
+ BIO_free(mem);
+ bail(!!pkey);
+ unsigned char *buf = NULL;
+ int len = i2d_PrivateKey(pkey, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_parse_der_cert(SEXP input){
+ const unsigned char *ptr = RAW(input);
+ X509 *cert = d2i_X509(NULL, &ptr, LENGTH(input));
+ bail(!!cert);
+ unsigned char *buf = NULL;
+ int len = i2d_X509(cert, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+/* Convert private to public key */
+SEXP R_derive_pubkey(SEXP input){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ EVP_PKEY *pkey = d2i_PrivateKey_bio(mem, NULL);
+ BIO_free(mem);
+ bail(!!pkey);
+ unsigned char *buf = NULL;
+ int len = i2d_PUBKEY(pkey, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+/* Convert cert to public key */
+SEXP R_cert_pubkey(SEXP input){
+ const unsigned char *ptr = RAW(input);
+ X509 *cert = d2i_X509(NULL, &ptr, LENGTH(input));
+ bail(!!cert);
+ EVP_PKEY *key = X509_get_pubkey(cert);
+ bail(!!key);
+ unsigned char *buf = NULL;
+ int len = i2d_PUBKEY(key, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_pubkey_type(SEXP input){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ EVP_PKEY *pkey = d2i_PUBKEY_bio(mem, NULL);
+ BIO_free(mem);
+ if(!pkey)
+ return R_NilValue;
+ char *keytype;
+ switch(EVP_PKEY_base_id(pkey)){
+ case EVP_PKEY_RSA:
+ keytype = "rsa";
+ break;
+ case EVP_PKEY_DSA:
+ keytype = "dsa";
+ break;
+ case EVP_PKEY_EC:
+ keytype = "ecdsa";
+ break;
+ default:
+ Rf_error("Unsupported key type: %d", EVP_PKEY_base_id(pkey));
+ }
+ EVP_PKEY_free(pkey);
+ return mkString(keytype);
+}
+
+int ec_bitsize(int nid){
+ switch(nid){
+ case NID_X9_62_prime256v1:
+ return 256;
+ case NID_secp384r1:
+ return 384;
+ case NID_secp521r1:
+ return 521;
+ }
+ return 0;
+}
+
+SEXP R_pubkey_bitsize(SEXP input){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ EVP_PKEY *pkey = d2i_PUBKEY_bio(mem, NULL);
+ BIO_free(mem);
+ if(!pkey)
+ return R_NilValue;
+ int size = 0;
+ const BIGNUM * val;
+ switch(EVP_PKEY_base_id(pkey)){
+ case EVP_PKEY_RSA:
+ MY_RSA_get0_key(EVP_PKEY_get1_RSA(pkey), &val, NULL, NULL);
+ size = BN_num_bits(val);
+ break;
+ case EVP_PKEY_DSA:
+ MY_DSA_get0_pqg(EVP_PKEY_get1_DSA(pkey), &val, NULL, NULL);
+ size = BN_num_bits(val);
+ break;
+#ifndef OPENSSL_NO_EC
+ case EVP_PKEY_EC:
+ size = ec_bitsize(EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get1_EC_KEY(pkey))));
+ break;
+#endif //OPENSSL_NO_EC
+ default:
+ Rf_error("Unsupported key type: %d", EVP_PKEY_base_id(pkey));
+ }
+ EVP_PKEY_free(pkey);
+ return ScalarInteger(size);
+}
diff --git a/src/onload.c b/src/onload.c
new file mode 100644
index 0000000..117cd31
--- /dev/null
+++ b/src/onload.c
@@ -0,0 +1,29 @@
+#include <R_ext/Rdynload.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/engine.h>
+#include <openssl/hmac.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+
+void R_init_openssl(DllInfo *info) {
+#ifdef _WIN32
+ WSADATA wsaData;
+ WSAStartup(MAKEWORD(2, 2), &wsaData);
+#endif
+ OpenSSL_add_all_digests();
+ OpenSSL_add_all_algorithms();
+ OpenSSL_add_all_ciphers();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ SSL_library_init();
+}
+
+void R_unload_curl(DllInfo *info) {
+ ERR_free_strings();
+ EVP_cleanup();
+}
diff --git a/src/openssh.c b/src/openssh.c
new file mode 100644
index 0000000..7860ab8
--- /dev/null
+++ b/src/openssh.c
@@ -0,0 +1,289 @@
+#include <Rinternals.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include <openssl/bn.h>
+#include "utils.h"
+#include "compatibility.h"
+
+#ifndef OPENSSL_NO_EC
+#include <openssl/ec.h>
+#endif
+
+/* BN_bn2bin() drops leading zeros which can alter openssh fingerprint */
+SEXP bignum_to_r_size(const BIGNUM *bn, int bytes){
+ int bits = BN_num_bits(bn);
+ if(bytes == 0)
+ bytes = (bits/8) + 1;
+ int numbytes = BN_num_bytes(bn);
+ int diff = bytes - numbytes;
+ SEXP res = PROTECT(allocVector(RAWSXP, bytes));
+ setAttrib(res, R_ClassSymbol, mkString("bignum"));
+ UNPROTECT(1);
+ unsigned char *ptr = RAW(res);
+ memset(ptr, 0, diff);
+ ptr += diff;
+ BN_bn2bin(bn, ptr);
+ return res;
+}
+
+SEXP bignum_to_r(const BIGNUM *bn){
+ return bignum_to_r_size(bn, 0);
+}
+
+BIGNUM* new_bignum_from_r(SEXP input){
+ BIGNUM *bn = BN_bin2bn(RAW(input), LENGTH(input), NULL);
+ bail(!!bn);
+ return bn;
+}
+
+/* Manuall compose public keys from bignum values */
+SEXP R_rsa_pubkey_build(SEXP expdata, SEXP moddata){
+ RSA *rsa = RSA_new();
+ MY_RSA_set0_key(rsa, new_bignum_from_r(moddata), new_bignum_from_r(expdata), NULL);
+ unsigned char *buf = NULL;
+ int len = i2d_RSA_PUBKEY(rsa, &buf);
+ bail(len);
+ RSA_free(rsa);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_rsa_key_build(SEXP e, SEXP n, SEXP p, SEXP q, SEXP d, SEXP dp, SEXP dq, SEXP qi){
+ RSA *rsa = RSA_new();
+ MY_RSA_set0_key(rsa, new_bignum_from_r(n), new_bignum_from_r(e), new_bignum_from_r(d));
+ MY_RSA_set0_factors(rsa, new_bignum_from_r(p), new_bignum_from_r(q));
+ MY_RSA_set0_crt_params(rsa, new_bignum_from_r(dp), new_bignum_from_r(dq), new_bignum_from_r(qi));
+ bail(RSA_check_key(rsa));
+ unsigned char *buf = NULL;
+ int len = i2d_RSAPrivateKey(rsa, &buf);
+ bail(len);
+ RSA_free(rsa);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_rsa_pubkey_decompose(SEXP bin){
+ RSA *rsa = RSA_new();
+ const unsigned char *ptr = RAW(bin);
+ bail(!!d2i_RSA_PUBKEY(&rsa, &ptr, LENGTH(bin)));
+ SEXP res = PROTECT(allocVector(VECSXP, 2));
+ const BIGNUM *e, *n;
+ MY_RSA_get0_key(rsa, &n, &e, NULL);
+ SET_VECTOR_ELT(res, 0, bignum_to_r(e));
+ SET_VECTOR_ELT(res, 1, bignum_to_r(n));
+ UNPROTECT(1);
+ return res;
+}
+
+SEXP R_rsa_priv_decompose(SEXP bin){
+ RSA *rsa = RSA_new();
+ const unsigned char *ptr = RAW(bin);
+ bail(!!d2i_RSAPrivateKey(&rsa, &ptr, LENGTH(bin)));
+ const BIGNUM *e, *n, *p, *q, *d, *dmp1, *dmq1, *iqmp;
+ MY_RSA_get0_key(rsa, &n, &e, &d);
+ MY_RSA_get0_factors(rsa, &p, &q);
+ MY_RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
+ SEXP res = PROTECT(allocVector(VECSXP, 8));
+ SET_VECTOR_ELT(res, 0, bignum_to_r(e));
+ SET_VECTOR_ELT(res, 1, bignum_to_r(n));
+ SET_VECTOR_ELT(res, 2, bignum_to_r(p));
+ SET_VECTOR_ELT(res, 3, bignum_to_r(q));
+ SET_VECTOR_ELT(res, 4, bignum_to_r(d));
+ SET_VECTOR_ELT(res, 5, bignum_to_r(dmp1));
+ SET_VECTOR_ELT(res, 6, bignum_to_r(dmq1));
+ SET_VECTOR_ELT(res, 7, bignum_to_r(iqmp));
+ UNPROTECT(1);
+ return res;
+}
+
+// See https://tools.ietf.org/html/rfc4253: ... the "ssh-dss" key format has ...
+SEXP R_dsa_pubkey_build(SEXP p, SEXP q, SEXP g, SEXP y){
+ DSA *dsa = DSA_new();
+ MY_DSA_set0_pqg(dsa, new_bignum_from_r(p), new_bignum_from_r(q), new_bignum_from_r(g));
+ MY_DSA_set0_key(dsa, new_bignum_from_r(y), NULL);
+ unsigned char *buf = NULL;
+ int len = i2d_DSA_PUBKEY(dsa, &buf);
+ bail(len);
+ DSA_free(dsa);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_dsa_pubkey_decompose(SEXP bin){
+ DSA *dsa = DSA_new();
+ const unsigned char *ptr = RAW(bin);
+ bail(!!d2i_DSA_PUBKEY(&dsa, &ptr, LENGTH(bin)));
+ const BIGNUM *p, *q, *g, *pub_key;
+ MY_DSA_get0_pqg(dsa, &p, &q, &g);
+ MY_DSA_get0_key(dsa, &pub_key, NULL);
+ SEXP res = PROTECT(allocVector(VECSXP, 4));
+ SET_VECTOR_ELT(res, 0, bignum_to_r(p));
+ SET_VECTOR_ELT(res, 1, bignum_to_r(q));
+ SET_VECTOR_ELT(res, 2, bignum_to_r(g));
+ SET_VECTOR_ELT(res, 3, bignum_to_r(pub_key));
+ UNPROTECT(1);
+ return res;
+}
+
+SEXP R_dsa_priv_decompose(SEXP bin){
+ DSA *dsa = DSA_new();
+ const unsigned char *ptr = RAW(bin);
+ bail(!!d2i_DSAPrivateKey(&dsa, &ptr, LENGTH(bin)));
+ const BIGNUM *p, *q, *g, *pub_key, *priv_key;
+ MY_DSA_get0_pqg(dsa, &p, &q, &g);
+ MY_DSA_get0_key(dsa, &pub_key, &priv_key);
+ SEXP res = PROTECT(allocVector(VECSXP, 5));
+ SET_VECTOR_ELT(res, 0, bignum_to_r(p));
+ SET_VECTOR_ELT(res, 1, bignum_to_r(q));
+ SET_VECTOR_ELT(res, 2, bignum_to_r(g));
+ SET_VECTOR_ELT(res, 3, bignum_to_r(pub_key));
+ SET_VECTOR_ELT(res, 4, bignum_to_r(priv_key));
+ UNPROTECT(1);
+ return res;
+}
+
+// EC_curve_nist2nid only available in recent openssl versions
+int my_nist2nid(const char *name){
+ if (!strcmp(name, "P-256")){
+ return NID_X9_62_prime256v1;
+ } else if (!strcmp(name, "P-384")){
+ return NID_secp384r1;
+ } else if (!strcmp(name, "P-521")){
+ return NID_secp521r1;
+ }
+ return 0;
+}
+
+const char *my_nid2nist(int nid){
+ switch(nid){
+ case NID_X9_62_prime256v1:
+ return "P-256";
+ case NID_secp384r1:
+ return "P-384";
+ case NID_secp521r1:
+ return "P-521";
+ }
+ return "";
+}
+
+int nid_keysize(int nid){
+ switch(nid){
+ case NID_X9_62_prime256v1:
+ return 32;
+ case NID_secp384r1:
+ return 48;
+ case NID_secp521r1:
+ return 66;
+ }
+ return 0;
+}
+
+SEXP R_ecdsa_pubkey_build(SEXP x, SEXP y, SEXP nist){
+#ifndef OPENSSL_NO_EC
+ int nid = my_nist2nid(CHAR(STRING_ELT(nist, 0)));
+ bail(nid);
+ EC_KEY *pubkey = EC_KEY_new_by_curve_name(nid);
+ EC_KEY_set_asn1_flag(pubkey, OPENSSL_EC_NAMED_CURVE);
+ if(!EC_KEY_set_public_key_affine_coordinates(pubkey, new_bignum_from_r(x), new_bignum_from_r(y)))
+ error("Failed to construct EC key. Perhaps invalid point or curve.");
+ unsigned char *buf = NULL;
+ int len = i2d_EC_PUBKEY(pubkey, &buf);
+ bail(len);
+ EC_KEY_free(pubkey);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+#else //OPENSSL_NO_EC
+ Rf_error("OpenSSL has been configured without EC support");
+#endif //OPENSSL_NO_EC
+}
+
+SEXP R_ecdsa_key_build(SEXP x, SEXP y, SEXP d, SEXP nist){
+#ifndef OPENSSL_NO_EC
+ int nid = my_nist2nid(CHAR(STRING_ELT(nist, 0)));
+ bail(nid);
+ EC_KEY *key = EC_KEY_new_by_curve_name(nid);
+ EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE);
+ if(!EC_KEY_set_public_key_affine_coordinates(key, new_bignum_from_r(x), new_bignum_from_r(y)))
+ error("Failed to construct EC key. Perhaps invalid point or curve.");
+ EC_KEY_set_private_key(key, new_bignum_from_r(d));
+ unsigned char *buf = NULL;
+ int len = i2d_ECPrivateKey(key, &buf);
+ bail(len);
+ EC_KEY_free(key);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+#else //OPENSSL_NO_EC
+ Rf_error("OpenSSL has been configured without EC support");
+#endif //OPENSSL_NO_EC
+}
+
+SEXP R_ecdsa_pubkey_decompose(SEXP input){
+#ifndef OPENSSL_NO_EC
+ const unsigned char *ptr = RAW(input);
+ EVP_PKEY *pkey = d2i_PUBKEY(NULL, &ptr, LENGTH(input));
+ bail(!!pkey);
+ EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
+ const EC_POINT *pubkey = EC_KEY_get0_public_key(ec);
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
+ int nid = EC_GROUP_get_curve_name(group);
+ int keysize = nid_keysize(nid);
+ BIGNUM *x = BN_new();
+ BIGNUM *y = BN_new();
+ BN_CTX *ctx = BN_CTX_new();
+ bail(EC_POINT_get_affine_coordinates_GFp(group, pubkey, x, y, ctx));
+ BN_CTX_free(ctx);
+ SEXP res = PROTECT(allocVector(VECSXP, 3));
+ SET_VECTOR_ELT(res, 0, mkString(my_nid2nist(nid)));
+ SET_VECTOR_ELT(res, 1, bignum_to_r_size(x, keysize));
+ SET_VECTOR_ELT(res, 2, bignum_to_r_size(y, keysize));
+ BN_free(x);
+ BN_free(y);
+ EVP_PKEY_free(pkey);
+ UNPROTECT(1);
+ return res;
+#else //OPENSSL_NO_EC
+ Rf_error("OpenSSL has been configured without EC support");
+#endif //OPENSSL_NO_EC
+}
+
+SEXP R_ecdsa_priv_decompose(SEXP input){
+#ifndef OPENSSL_NO_EC
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ EVP_PKEY *pkey = d2i_PrivateKey_bio(mem, NULL);
+ BIO_free(mem);
+ bail(!!pkey);
+ EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
+ const EC_POINT *pubkey = EC_KEY_get0_public_key(ec);
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
+ int nid = EC_GROUP_get_curve_name(group);
+ int keysize = nid_keysize(nid);
+ BIGNUM *x = BN_new();
+ BIGNUM *y = BN_new();
+ BIGNUM *z = (BIGNUM*) EC_KEY_get0_private_key(ec);
+ BN_CTX *ctx = BN_CTX_new();
+ bail(EC_POINT_get_affine_coordinates_GFp(group, pubkey, x, y, ctx));
+ BN_CTX_free(ctx);
+ SEXP res = PROTECT(allocVector(VECSXP, 4));
+ SET_VECTOR_ELT(res, 0, mkString(my_nid2nist(nid)));
+ SET_VECTOR_ELT(res, 1, bignum_to_r_size(x, keysize));
+ SET_VECTOR_ELT(res, 2, bignum_to_r_size(y, keysize));
+ SET_VECTOR_ELT(res, 3, bignum_to_r_size(z, keysize));
+ BN_free(x);
+ BN_free(y);
+ EVP_PKEY_free(pkey);
+ UNPROTECT(1);
+ return res;
+#else //OPENSSL_NO_EC
+ Rf_error("OpenSSL has been configured without EC support");
+#endif //OPENSSL_NO_EC
+}
diff --git a/src/password.c b/src/password.c
new file mode 100644
index 0000000..53f70a9
--- /dev/null
+++ b/src/password.c
@@ -0,0 +1,40 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
+int password_cb(char *buf, int max_size, int rwflag, void *ctx){
+ if(!ctx)
+ error("No password callback supplied.");
+
+ SEXP cb = (SEXP) ctx;
+
+ /* no password */
+ if(isNull(cb)){
+ return 0;
+ }
+
+ /* case where password is a hardcoded string */
+ if(isString(cb)){
+ strncpy(buf, CHAR(STRING_ELT(cb, 0)), max_size);
+ buf[max_size-1] = '\0'; //in case of max size
+ return strlen(buf);
+ }
+
+ /* case where password is an R function */
+ if(isFunction(cb)){
+ int err;
+ SEXP call = PROTECT(LCONS(cb, LCONS(mkString("Please enter private key passphrase: "), R_NilValue)));
+ SEXP res = PROTECT(R_tryEval(call, R_GlobalEnv, &err));
+ if(err || !isString(res)){
+ UNPROTECT(2);
+ error("Password callback did not return a string value");
+ }
+ strncpy(buf, CHAR(STRING_ELT(res, 0)), max_size);
+ buf[max_size-1] = '\0';
+ UNPROTECT(2);
+ return strlen(buf);
+ }
+ error("Callback must be string or function");
+}
diff --git a/src/pem.c b/src/pem.c
new file mode 100644
index 0000000..366bcb0
--- /dev/null
+++ b/src/pem.c
@@ -0,0 +1,90 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include "utils.h"
+
+/* parses any pem file, does not support passwords */
+SEXP R_parse_pem(SEXP input){
+ char *name = NULL;
+ char *header = NULL;
+ unsigned char *data = NULL;
+ long len = 0;
+ int count = 0;
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ while(PEM_read_bio(mem, &name, &header, &data, &len) && len)
+ count++;
+ ERR_clear_error();
+ BIO_free(mem);
+ mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ SEXP out = PROTECT(allocVector(VECSXP, count));
+ for(int i = 0; i < count; i++){
+ PEM_read_bio(mem, &name, &header, &data, &len);
+ SEXP res = PROTECT(allocVector(VECSXP, 3));
+ SET_VECTOR_ELT(res, 0, mkString(name));
+ SET_VECTOR_ELT(res, 1, mkString(header));
+ SET_VECTOR_ELT(res, 2, allocVector(RAWSXP, (int) len));
+ memcpy(RAW(VECTOR_ELT(res, 2)), data, (int) len);
+ SET_VECTOR_ELT(out, i, res);
+ UNPROTECT(1);
+ }
+ UNPROTECT(1);
+ BIO_free(mem);
+ ERR_clear_error();
+ return out;
+}
+
+SEXP R_parse_pem_key(SEXP input, SEXP password){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ EVP_PKEY *pkey = PEM_read_bio_PrivateKey(mem, NULL, password_cb, password);
+ BIO_free(mem);
+ bail(!!pkey);
+ unsigned char *buf = NULL;
+ int len = i2d_PrivateKey(pkey, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_parse_pem_pubkey(SEXP input){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ EVP_PKEY *pkey = PEM_read_bio_PUBKEY(mem, NULL, password_cb, NULL);
+ BIO_free(mem);
+ bail(!!pkey);
+ unsigned char *buf = NULL;
+ int len = i2d_PUBKEY(pkey, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_parse_pem_cert(SEXP input){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ X509 *cert = PEM_read_bio_X509(mem, NULL, password_cb, NULL);
+ unsigned char *buf = NULL;
+ int len = i2d_X509(cert, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+/* Legacy pubkey format */
+SEXP R_parse_pem_pkcs1(SEXP input){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ RSA *rsa = PEM_read_bio_RSAPublicKey(mem, NULL, password_cb, NULL);
+ bail(!!rsa);
+ unsigned char *buf = NULL;
+ int len = i2d_RSA_PUBKEY(rsa, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
diff --git a/src/pkcs12.c b/src/pkcs12.c
new file mode 100644
index 0000000..12df881
--- /dev/null
+++ b/src/pkcs12.c
@@ -0,0 +1,122 @@
+#include <stdlib.h>
+#include <string.h>
+#include <Rinternals.h>
+#include <openssl/pkcs12.h>
+#include "utils.h"
+
+SEXP R_write_pkcs12(SEXP keydata, SEXP certdata, SEXP cadata, SEXP namedata, SEXP pwdata){
+ EVP_PKEY * pkey = NULL;
+ X509 * cert = NULL;
+ STACK_OF(X509) * ca = sk_X509_new_null();
+ char * name = NULL;
+ char * pw = NULL;
+
+ //parse private key
+ if(Rf_length(keydata)){
+ BIO *mem = BIO_new_mem_buf(RAW(keydata), LENGTH(keydata));
+ pkey = d2i_PrivateKey_bio(mem, NULL);
+ BIO_free(mem);
+ bail(!!pkey);
+ }
+
+ //parse certificate
+ if(Rf_length(certdata)){
+ const unsigned char *ptr = RAW(certdata);
+ cert = d2i_X509(NULL, &ptr, LENGTH(certdata));
+ bail(!!cert);
+ }
+
+ //add other certs
+ for(int i = 0; i < Rf_length(cadata); i++){
+ const unsigned char *ptr = RAW(VECTOR_ELT(cadata, i));
+ X509 * crt = d2i_X509(NULL, &ptr, Rf_length(VECTOR_ELT(cadata, i)));
+ bail(!!crt);
+ sk_X509_push(ca, crt);
+ }
+
+ //get name
+ if(Rf_length(namedata)){
+ name = (char*) CHAR(STRING_ELT(namedata, 0));
+ }
+
+ //get password
+ if(Rf_length(pwdata)){
+ pw = (char*) CHAR(STRING_ELT(pwdata, 0));
+ }
+
+ // create the P12
+ PKCS12 *p12 = PKCS12_create(pw, name, pkey, cert, ca, 0, 0, 0, 0, 0);
+ bail(!!p12);
+
+ //serialize to R
+ unsigned char *buf = NULL;
+ int len = i2d_PKCS12(p12, &buf);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_parse_pkcs12(SEXP input, SEXP pass){
+ const unsigned char *ptr = RAW(input);
+ PKCS12 *p12 = d2i_PKCS12(NULL, &ptr, LENGTH(input));
+ bail(!!p12);
+ EVP_PKEY *pkey = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *ca = NULL;
+
+ int success = 0;
+ int max_size = 200;
+ char passwd[max_size];
+ if(PKCS12_verify_mac(p12, NULL, 0) || PKCS12_verify_mac(p12, "", 1)){
+ success = PKCS12_parse(p12, "", &pkey, &cert, &ca);
+ } else {
+ password_cb(passwd, max_size, 0, pass);
+ if(!PKCS12_verify_mac(p12, passwd, strlen(passwd)))
+ Rf_errorcall(R_NilValue, "PKCS12 read failure: invalid password");
+ success = PKCS12_parse(p12, passwd, &pkey, &cert, &ca);
+ }
+ PKCS12_free(p12);
+ bail(success);
+
+ unsigned char *buf = NULL;
+ int len = 0;
+ SEXP res = PROTECT(allocVector(VECSXP, 3));
+ if (cert != NULL) {
+ len = i2d_X509(cert, &buf);
+ X509_free(cert);
+ bail(len);
+ SET_VECTOR_ELT(res, 0, allocVector(RAWSXP, len));
+ memcpy(RAW(VECTOR_ELT(res, 0)), buf, len);
+ free(buf);
+ buf = NULL;
+ }
+ if(pkey != NULL){
+ len = i2d_PrivateKey(pkey, &buf);
+ EVP_PKEY_free(pkey);
+ bail(len);
+ SET_VECTOR_ELT(res, 1, allocVector(RAWSXP, len));
+ memcpy(RAW(VECTOR_ELT(res, 1)), buf, len);
+ free(buf);
+ buf = NULL;
+ }
+ if(ca && sk_X509_num(ca)){
+ int ncerts = sk_X509_num(ca);
+ SEXP bundle = PROTECT(allocVector(VECSXP, ncerts));
+ for(int i = 0; i < ncerts; i++){
+ cert = sk_X509_value(ca, (ncerts - i - 1)); //reverse order to match PEM/SSL
+ len = i2d_X509(cert, &buf);
+ bail(len);
+ SET_VECTOR_ELT(bundle, i, allocVector(RAWSXP, len));
+ memcpy(RAW(VECTOR_ELT(bundle, i)), buf, len);
+ free(buf);
+ buf = NULL;
+ }
+ sk_X509_pop_free(ca, X509_free);
+ SET_VECTOR_ELT(res, 2, bundle);
+ UNPROTECT(1);
+ }
+ UNPROTECT(1);
+ return res;
+}
diff --git a/src/pkcs7.c b/src/pkcs7.c
new file mode 100644
index 0000000..f39a6f5
--- /dev/null
+++ b/src/pkcs7.c
@@ -0,0 +1,107 @@
+/* Adapted from https://github.com/openssl/openssl/blob/master/apps/pkcs7.c
+ */
+
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs7.h>
+#include "utils.h"
+
+SEXP R_parse_pem_pkcs7(SEXP input){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ PKCS7 *p7 = PEM_read_bio_PKCS7(mem, NULL, password_cb, NULL);
+ unsigned char *buf = NULL;
+ int len = i2d_PKCS7(p7, &buf);
+ PKCS7_free(p7);
+ bail(len);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_write_pkcs7(SEXP cadata){
+ PKCS7 *p7 = PKCS7_new();
+ p7->type = OBJ_nid2obj(NID_pkcs7_signed);
+ p7->d.sign = PKCS7_SIGNED_new();
+ p7->d.sign->contents->type = OBJ_nid2obj(NID_pkcs7_data);
+ p7->d.sign->cert = sk_X509_new_null();
+ for(int i = 0; i < Rf_length(cadata); i++){
+ const unsigned char *ptr = RAW(VECTOR_ELT(cadata, i));
+ X509 * crt = d2i_X509(NULL, &ptr, Rf_length(VECTOR_ELT(cadata, i)));
+ bail(!!crt);
+ bail(sk_X509_push(p7->d.sign->cert, crt));
+ }
+ unsigned char *buf = NULL;
+ int len = i2d_PKCS7(p7, &buf);
+ bail(len);
+ PKCS7_free(p7);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ free(buf);
+ return res;
+}
+
+SEXP R_parse_der_pkcs7(SEXP input){
+ const unsigned char *ptr = RAW(input);
+ PKCS7 *p7 = d2i_PKCS7(NULL, &ptr, LENGTH(input));
+ bail(!!p7);
+
+ STACK_OF(X509) *certs = NULL;
+ STACK_OF(X509_CRL) *crls = NULL;
+
+ int p7type = OBJ_obj2nid(p7->type);
+ if(p7type == NID_pkcs7_signed){
+ if (p7->d.sign != NULL) {
+ certs = p7->d.sign->cert;
+ crls = p7->d.sign->crl;
+ }
+ } else if(p7type == NID_pkcs7_signedAndEnveloped){
+ if (p7->d.signed_and_enveloped != NULL) {
+ certs = p7->d.signed_and_enveloped->cert;
+ crls = p7->d.signed_and_enveloped->crl;
+ }
+ } else {
+ Rf_errorcall(R_NilValue, "Unsupported P7 type: %d\n", p7type);
+ }
+
+ unsigned char *buf = NULL;
+ int len = 0;
+ SEXP out = PROTECT(allocVector(VECSXP, 2));
+
+ if (certs != NULL) {
+ int n = sk_X509_num(certs);
+ SEXP bundle = PROTECT(allocVector(VECSXP, n));
+ for(int i = 0; i < n; i++){
+ X509 *x = sk_X509_value(certs, i);
+ len = i2d_X509(x, &buf);
+ bail(len);
+ SET_VECTOR_ELT(bundle, i, allocVector(RAWSXP, len));
+ memcpy(RAW(VECTOR_ELT(bundle, i)), buf, len);
+ free(buf);
+ buf = NULL;
+ }
+ SET_VECTOR_ELT(out, 0, bundle);
+ UNPROTECT(1);
+ }
+
+ if (crls != NULL) {
+ int n = sk_X509_CRL_num(crls);
+ SEXP bundle = PROTECT(allocVector(VECSXP, n));
+ for(int i = 0; i < n; i++){
+ X509_CRL *crl = sk_X509_CRL_value(crls, i);
+ len = i2d_X509_CRL(crl, &buf);
+ bail(len);
+ SET_VECTOR_ELT(bundle, i, allocVector(RAWSXP, len));
+ memcpy(RAW(VECTOR_ELT(bundle, i)), buf, len);
+ free(buf);
+ buf = NULL;
+ }
+ SET_VECTOR_ELT(out, 1, bundle);
+ UNPROTECT(1);
+ }
+ PKCS7_free(p7);
+ UNPROTECT(1);
+ return out;
+}
diff --git a/src/rand.c b/src/rand.c
new file mode 100644
index 0000000..fcb3381
--- /dev/null
+++ b/src/rand.c
@@ -0,0 +1,17 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/rand.h>
+#include "utils.h"
+
+SEXP R_RAND_bytes(SEXP n) {
+ int length = asInteger(n);
+ if(length <= 0)
+ return allocVector(RAWSXP, 0);
+ unsigned char buf[length];
+ bail(RAND_bytes(buf, length));
+ SEXP out = PROTECT(allocVector(RAWSXP, length));
+ memcpy(RAW(out), buf, length);
+ UNPROTECT(1);
+ return out;
+}
diff --git a/src/rsa.c b/src/rsa.c
new file mode 100644
index 0000000..d26e206
--- /dev/null
+++ b/src/rsa.c
@@ -0,0 +1,33 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include "utils.h"
+
+SEXP R_rsa_encrypt(SEXP data, SEXP keydata) {
+ const unsigned char *ptr = RAW(keydata);
+ RSA *rsa = d2i_RSA_PUBKEY(NULL, &ptr, LENGTH(keydata));
+ bail(!!rsa);
+ int keysize = RSA_size(rsa);
+ unsigned char* buf = OPENSSL_malloc(keysize);
+ int len = RSA_public_encrypt(LENGTH(data), RAW(data), buf, rsa, RSA_PKCS1_PADDING);
+ bail(len > 0);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ OPENSSL_free(buf);
+ return res;
+}
+
+SEXP R_rsa_decrypt(SEXP data, SEXP keydata){
+ const unsigned char *ptr = RAW(keydata);
+ RSA *rsa = d2i_RSAPrivateKey(NULL, &ptr, LENGTH(keydata));
+ bail(!!rsa);
+ int keysize = RSA_size(rsa);
+ unsigned char* buf = OPENSSL_malloc(keysize);
+ int len = RSA_private_decrypt(LENGTH(data), RAW(data), buf, rsa, RSA_PKCS1_PADDING);
+ bail(len > 0);
+ SEXP res = allocVector(RAWSXP, len);
+ memcpy(RAW(res), buf, len);
+ OPENSSL_free(buf);
+ return res;
+}
diff --git a/src/signing.c b/src/signing.c
new file mode 100644
index 0000000..06746f4
--- /dev/null
+++ b/src/signing.c
@@ -0,0 +1,68 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/pem.h>
+#include <openssl/hmac.h>
+#include "utils.h"
+
+const EVP_MD* guess_hashfun(int length){
+ switch(length){
+ case 16:
+ return EVP_md5();
+ case 20:
+ return EVP_sha1();
+ case 24:
+ return EVP_sha224();
+ case 32:
+ return EVP_sha256();
+ case 48:
+ return EVP_sha384();
+ case 64:
+ return EVP_sha512();
+ }
+ return EVP_md_null();
+}
+
+SEXP R_hash_sign(SEXP md, SEXP key){
+ BIO *mem = BIO_new_mem_buf(RAW(key), LENGTH(key));
+ EVP_PKEY *pkey = d2i_PrivateKey_bio(mem, NULL);
+ BIO_free(mem);
+ bail(!!pkey);
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
+ bail(!!ctx);
+ bail(EVP_PKEY_sign_init(ctx) > 0);
+ //bail(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) >= 0);
+ bail(EVP_PKEY_CTX_set_signature_md(ctx, guess_hashfun(LENGTH(md))) > 0);
+
+ //detemine buffer length (this is really required, over/under estimate can crash)
+ size_t siglen;
+ bail(EVP_PKEY_sign(ctx, NULL, &siglen, RAW(md), LENGTH(md)) > 0);
+
+ //calculate signature
+ unsigned char *sig = OPENSSL_malloc(siglen);
+ bail(EVP_PKEY_sign(ctx, sig, &siglen, RAW(md), LENGTH(md)) > 0);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
+ SEXP res = allocVector(RAWSXP, siglen);
+ memcpy(RAW(res), sig, siglen);
+ OPENSSL_free(sig);
+ return res;
+}
+
+SEXP R_hash_verify(SEXP md, SEXP sig, SEXP pubkey){
+ const unsigned char *ptr = RAW(pubkey);
+ EVP_PKEY *pkey = d2i_PUBKEY(NULL, &ptr, LENGTH(pubkey));
+ bail(!!pkey);
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
+ bail(!!ctx);
+ bail(EVP_PKEY_verify_init(ctx) > 0);
+ //bail(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) >= 0);
+ bail(EVP_PKEY_CTX_set_signature_md(ctx, guess_hashfun(LENGTH(md))) > 0);
+ int res = EVP_PKEY_verify(ctx, RAW(sig), LENGTH(sig), RAW(md), LENGTH(md));
+ bail(res >= 0);
+ if(res == 0)
+ error("Verification failed: incorrect signature");
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
+ return ScalarLogical(1);
+}
diff --git a/src/ssl.c b/src/ssl.c
new file mode 100644
index 0000000..aa95dd9
--- /dev/null
+++ b/src/ssl.c
@@ -0,0 +1,152 @@
+//getaddrinfo is an extension (not C99)
+#if !defined(_WIN32) && !defined(__sun) && !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
+#else
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+
+#include <openssl/ssl.h>
+#include "utils.h"
+
+void check_interrupt_fn(void *dummy) {
+ R_CheckUserInterrupt();
+}
+
+int pending_interrupt() {
+ return !(R_ToplevelExec(check_interrupt_fn, NULL));
+}
+
+SEXP R_download_cert(SEXP hostname, SEXP service) {
+ /* The 'hints' arg is only needed for solaris */
+ struct addrinfo hints;
+ memset(&hints,0,sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = PF_UNSPEC;
+
+ /* Because gethostbyname() is deprecated */
+ struct addrinfo *addr;
+ if(getaddrinfo(CHAR(STRING_ELT(hostname, 0)), CHAR(STRING_ELT(service, 0)), &hints, &addr))
+ error("Failed to resolve hostname or unknown port");
+ int sockfd = socket(addr->ai_family, SOCK_STREAM, 0);
+
+ /* For debugging */
+ struct sockaddr *sa = addr->ai_addr;
+
+ /* IPv4 vs v6 */
+ int port = 0;
+ char ip[INET6_ADDRSTRLEN];
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sa_in = (struct sockaddr_in*) sa;
+ port = ntohs(sa_in->sin_port);
+ inet_ntop(AF_INET, &(sa_in->sin_addr), ip, INET_ADDRSTRLEN);
+ } else {
+ struct sockaddr_in6 *sa_in = (struct sockaddr_in6*) sa;
+ port = ntohs(sa_in->sin6_port);
+ inet_ntop(AF_INET6, &(sa_in->sin6_addr), ip, INET6_ADDRSTRLEN);
+ }
+
+ /* Set to non-blocking mode */
+#ifdef _WIN32
+ u_long nonblocking = 1;
+ ioctlsocket(sockfd, FIONBIO, &nonblocking);
+#define NONBLOCK_OK (WSAGetLastError() == WSAEWOULDBLOCK)
+#else
+ long arg = fcntl(sockfd, F_GETFL, NULL);
+ arg |= O_NONBLOCK;
+ fcntl(sockfd, F_SETFL, arg);
+#define NONBLOCK_OK (errno == EINPROGRESS)
+#endif
+
+ /* Connect */
+ struct timeval tv;
+ fd_set myset;
+ tv.tv_sec = 5; // 5 sec timeout
+ tv.tv_usec = 0;
+ FD_ZERO(&myset);
+ FD_SET(sockfd, &myset);
+
+ /* Try to connect */
+ connect(sockfd, addr->ai_addr, (int)addr->ai_addrlen);
+ if(!NONBLOCK_OK || select(FD_SETSIZE, NULL, &myset, NULL, &tv) < 1){
+ close(sockfd);
+ error("Failed to connect to %s on port %d", ip, port);
+ }
+ freeaddrinfo(addr);
+
+ /* Set back in blocking mode */
+#ifdef _WIN32
+ nonblocking = 0;
+ ioctlsocket(sockfd, FIONBIO, &nonblocking);
+#else
+ arg = fcntl(sockfd, F_GETFL, NULL);
+ arg &= (~O_NONBLOCK);
+ fcntl(sockfd, F_SETFL, arg);
+#endif
+
+ int err = 0;
+ socklen_t errbuf = sizeof (err);
+ if(getsockopt (sockfd, SOL_SOCKET, SO_ERROR, (char*) &err, &errbuf) || err){
+ close(sockfd);
+ error("Failed to connect to %s on port %d", ip, port);
+ }
+
+ /* Setup SSL */
+ SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
+ bail(!!ctx);
+ SSL *ssl = SSL_new(ctx);
+ bail(!!ssl);
+
+ /* Required for SNI (e.g. cloudflare) */
+ bail(SSL_set_tlsext_host_name(ssl, CHAR(STRING_ELT(hostname, 0))));
+
+ /* SSL handshake to get cert */
+ SSL_set_fd(ssl, sockfd);
+ int con = SSL_connect(ssl);
+ close(sockfd);
+ bail(con > 0);
+
+ /* Convert certs to RAW. Not sure if I should free these */
+ STACK_OF(X509) *chain = SSL_get_peer_cert_chain(ssl);
+ int n = sk_X509_num(chain);
+ bail(n > 0);
+
+ int len;
+ unsigned char *buf = NULL;
+ SEXP res = PROTECT(allocVector(VECSXP, n));
+ for(int i = 0; i < n; i++){
+ len = i2d_X509(sk_X509_value(chain, i), &buf);
+ SET_VECTOR_ELT(res, i, allocVector(RAWSXP, len));
+ memcpy(RAW(VECTOR_ELT(res, i)), buf, len);
+ setAttrib(VECTOR_ELT(res, i), R_ClassSymbol, mkString("cert"));
+ free(buf);
+ buf = NULL;
+ }
+
+ /* Cleanup SSL */
+ SSL_free(ssl);
+ SSL_CTX_free(ctx);
+
+ /* Test for cert */
+ if(n < 1)
+ error("Server did not present a certificate");
+
+ UNPROTECT(1);
+ return res;
+}
diff --git a/src/stream.c b/src/stream.c
new file mode 100644
index 0000000..1f04c1d
--- /dev/null
+++ b/src/stream.c
@@ -0,0 +1,103 @@
+#include <Rinternals.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include "utils.h"
+#include "compatibility.h"
+
+void fin_md(SEXP ptr){
+ if(!R_ExternalPtrAddr(ptr)) return;
+ EVP_MD_CTX_destroy(R_ExternalPtrAddr(ptr));
+ R_ClearExternalPtr(ptr);
+}
+
+SEXP R_md_init(SEXP algo){
+ const EVP_MD *md = EVP_get_digestbyname(CHAR(asChar(algo)));
+ if(!md)
+ error("Unknown cryptographic algorithm %s\n", CHAR(asChar(algo)));
+ EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(mdctx, md, NULL);
+ SEXP ptr = PROTECT(R_MakeExternalPtr(mdctx, R_NilValue, R_NilValue));
+ R_RegisterCFinalizerEx(ptr, fin_md, TRUE);
+ setAttrib(ptr, R_ClassSymbol, mkString("md"));
+ UNPROTECT(1);
+ return ptr;
+}
+
+SEXP R_md_feed(SEXP md, SEXP data){
+ EVP_MD_CTX *mdctx = R_ExternalPtrAddr(md);
+ if(!mdctx)
+ error("mdctx is null");
+ EVP_DigestUpdate(mdctx, RAW(data), length(data));
+ return ScalarLogical(1);
+}
+
+SEXP R_md_final(SEXP md){
+ if(!R_ExternalPtrAddr(md))
+ error("md is null");
+
+ /* Calculates the hash */
+ unsigned char md_value[EVP_MAX_MD_SIZE];
+ unsigned int md_len;
+ EVP_DigestFinal_ex(R_ExternalPtrAddr(md), (unsigned char *) &md_value, &md_len);
+
+ /* create output raw vec */
+ SEXP out = allocVector(RAWSXP, md_len);
+ memcpy(RAW(out), md_value, md_len);
+ return out;
+}
+
+void fin_hmac(SEXP ptr){
+ if(!R_ExternalPtrAddr(ptr)) return;
+#if HAS_OPENSSL11
+ HMAC_CTX_free(R_ExternalPtrAddr(ptr));
+#else
+ HMAC_CTX_cleanup(R_ExternalPtrAddr(ptr));
+ free(R_ExternalPtrAddr(ptr));
+#endif
+ R_ClearExternalPtr(ptr);
+}
+
+SEXP R_hmac_init(SEXP algo, SEXP key){
+ const EVP_MD *md = EVP_get_digestbyname(CHAR(asChar(algo)));
+ if(!md)
+ error("Unknown cryptographic algorithm %s\n", CHAR(asChar(algo)));
+#if HAS_OPENSSL11
+ HMAC_CTX* ctx = HMAC_CTX_new();
+#else
+ HMAC_CTX* ctx = malloc(sizeof(HMAC_CTX));
+ HMAC_CTX_init(ctx);
+#endif
+ bail(HMAC_Init_ex(ctx, RAW(key), LENGTH(key), md, NULL));
+ SEXP ptr = PROTECT(R_MakeExternalPtr(ctx, R_NilValue, R_NilValue));
+ R_RegisterCFinalizerEx(ptr, fin_hmac, TRUE);
+ setAttrib(ptr, R_ClassSymbol, mkString("md"));
+ UNPROTECT(1);
+ return ptr;
+}
+
+SEXP R_hmac_feed(SEXP ptr, SEXP data){
+ HMAC_CTX *ctx = R_ExternalPtrAddr(ptr);
+ if(!ctx)
+ error("ctx is null");
+ bail(HMAC_Update(ctx, RAW(data), LENGTH(data)));
+ return ScalarLogical(1);
+}
+
+SEXP R_hmac_final(SEXP ptr){
+ HMAC_CTX *ctx = R_ExternalPtrAddr(ptr);
+ if(!ctx)
+ error("ctx is null");
+
+ /* Calculates the hash */
+ unsigned char md_value[EVP_MAX_MD_SIZE];
+ unsigned int md_len;
+ bail(HMAC_Final(ctx, (unsigned char *) &md_value, &md_len));
+
+ /* create output raw vec */
+ SEXP out = PROTECT(allocVector(RAWSXP, md_len));
+ memcpy(RAW(out), md_value, md_len);
+ UNPROTECT(1);
+ return out;
+}
diff --git a/src/utils.h b/src/utils.h
new file mode 100644
index 0000000..a87c00e
--- /dev/null
+++ b/src/utils.h
@@ -0,0 +1,5 @@
+#define stop(...) Rf_errorcall(R_NilValue, __VA_ARGS__)
+void bail(int out);
+void raise_error();
+int my_nist2nid(const char *name);
+int password_cb(char *buf, int max_size, int rwflag, void *ctx);
diff --git a/src/win32/ipv6.c b/src/win32/ipv6.c
new file mode 100644
index 0000000..eb3eebb
--- /dev/null
+++ b/src/win32/ipv6.c
@@ -0,0 +1,59 @@
+/* download_ssl_cert requires 'inet_ntop' but mingw-w64 does
+ * not have this for win32, only for win64.
+ */
+#include <_mingw.h>
+#if !defined(_WIN64)
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+int inet_pton(int af, const char *src, void *dst)
+{
+ struct sockaddr_storage ss;
+ int size = sizeof(ss);
+ char src_copy[INET6_ADDRSTRLEN+1];
+
+ ZeroMemory(&ss, sizeof(ss));
+ /* stupid non-const API */
+ strncpy (src_copy, src, INET6_ADDRSTRLEN+1);
+ src_copy[INET6_ADDRSTRLEN] = 0;
+
+ if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) {
+ switch(af) {
+ case AF_INET:
+ *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
+ return 1;
+ case AF_INET6:
+ *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
+{
+ struct sockaddr_storage ss;
+ unsigned long s = size;
+
+ ZeroMemory(&ss, sizeof(ss));
+ ss.ss_family = af;
+
+ switch(af) {
+ case AF_INET:
+ ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
+ break;
+ default:
+ return NULL;
+ }
+ /* cannot direclty use &size because of strict aliasing rules */
+ return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)?
+ dst : NULL;
+}
+#endif
diff --git a/src/write.c b/src/write.c
new file mode 100644
index 0000000..054aaa0
--- /dev/null
+++ b/src/write.c
@@ -0,0 +1,51 @@
+#include <Rinternals.h>
+#include <openssl/pem.h>
+#include "utils.h"
+
+SEXP R_pem_write_key(SEXP input, SEXP password){
+ BIO *mem = BIO_new_mem_buf(RAW(input), LENGTH(input));
+ EVP_PKEY *pkey = d2i_PrivateKey_bio(mem, NULL);
+ BIO_free(mem);
+ bail(!!pkey);
+ BIO *out = BIO_new(BIO_s_mem());
+ if(!isNull(password) && LENGTH(STRING_ELT(password, 0))){
+ char *pass = (char*) CHAR(STRING_ELT(password, 0));
+ PEM_write_bio_PrivateKey(out, pkey, EVP_des_ede3_cbc(), NULL, 0, NULL, pass);
+ } else {
+ PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, NULL);
+ }
+ int bufsize = 8192;
+ char buf[bufsize];
+ int len = BIO_read(out, buf, bufsize);
+ BIO_free(out);
+ bail(len);
+ return ScalarString(mkCharLen(buf, len));
+}
+
+SEXP R_pem_write_pubkey(SEXP input){
+ const unsigned char *ptr = RAW(input);
+ EVP_PKEY *pkey = d2i_PUBKEY(NULL, &ptr, LENGTH(input));
+ bail(!!pkey);
+ BIO *out = BIO_new(BIO_s_mem());
+ PEM_write_bio_PUBKEY(out, pkey);
+ int bufsize = 8192;
+ char buf[bufsize];
+ int len = BIO_read(out, buf, bufsize);
+ BIO_free(out);
+ bail(len);
+ return ScalarString(mkCharLen(buf, len));
+}
+
+SEXP R_pem_write_cert(SEXP input){
+ X509 *cert = X509_new();
+ const unsigned char *ptr = RAW(input);
+ bail(!!d2i_X509(&cert, &ptr, LENGTH(input)));
+ BIO *out = BIO_new(BIO_s_mem());
+ PEM_write_bio_X509(out, cert);
+ int bufsize = 100000;
+ char buf[bufsize];
+ int len = BIO_read(out, buf, bufsize);
+ BIO_free(out);
+ bail(len);
+ return ScalarString(mkCharLen(buf, len));
+}
diff --git a/tests/certigo/example-elliptic-sha1.crt b/tests/certigo/example-elliptic-sha1.crt
new file mode 100644
index 0000000..91975de
--- /dev/null
+++ b/tests/certigo/example-elliptic-sha1.crt
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICiDCCAeqgAwIBAgIJAJ/xjMI6FKOAMAkGByqGSM49BAEwXjELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFt
+cGxlMR4wHAYDVQQDExVleGFtcGxlLWVsbGlwdGljLXNoYTEwHhcNMTYwNjIyMDAy
+MzIwWhcNMjMwNDI3MDAyMzIwWjBeMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
+EDAOBgNVBAoTB2NlcnRpZ28xEDAOBgNVBAsTB2V4YW1wbGUxHjAcBgNVBAMTFWV4
+YW1wbGUtZWxsaXB0aWMtc2hhMTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEARBY
+2NPz8x6YNLA9UkPpPSoNM+JsLO6giyTuIwRy1j2PN94bmPRZcvffFMHo0jBbof/u
+EEazJm0WAojmcqqED6caAMu+QcYrPdugHCHO1lv5iwZ5sJyswQ8qygaroMWBg7Qa
+XjAs1p4Oncuh37CxRj70mse0YEPt+neBD5BM+8ZDchFXo08wTTAdBgNVHSUEFjAU
+BggrBgEFBQcDAgYIKwYBBQUHAwEwLAYDVR0RBCUwI4cEfwAAAYcQAAAAAAAAAAAA
+AAAAAAAAAYIJbG9jYWxob3N0MAkGByqGSM49BAEDgYwAMIGIAkIByNx56XB0CyNR
+3vKIRdn9uoo8Q9PqBlO8ZtldeF+MqI/UvcnbrVxn7d5+lNj6K2YY2GzwV+IdxRyP
+JSsHT03pww0CQgE5ssxuHZXCw1zLFXPilEHKpx1B3umRwR9q0lVc63d9zFT/Dz5L
+QqF02WtegKS3Kr6M7R8fn2QvsdzOPqlcN57E2Q==
+-----END CERTIFICATE-----
diff --git a/tests/certigo/example-elliptic-sha1.key b/tests/certigo/example-elliptic-sha1.key
new file mode 100644
index 0000000..b7eebe3
--- /dev/null
+++ b/tests/certigo/example-elliptic-sha1.key
@@ -0,0 +1,10 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIBc4MT0rgcDEaimeP7Bxlhp3hAI2/KySFbOu6cg40taVXhXnaDAPqV
+tKj3kru+1DhvxBCrUewzKo5u9g+OC7xdu8qgBwYFK4EEACOhgYkDgYYABAEQWNjT
+8/MemDSwPVJD6T0qDTPibCzuoIsk7iMEctY9jzfeG5j0WXL33xTB6NIwW6H/7hBG
+syZtFgKI5nKqhA+nGgDLvkHGKz3boBwhztZb+YsGebCcrMEPKsoGq6DFgYO0Gl4w
+LNaeDp3Lod+wsUY+9JrHtGBD7fp3gQ+QTPvGQ3IRVw==
+-----END EC PRIVATE KEY-----
diff --git a/tests/certigo/example-elliptic-sha1.p12 b/tests/certigo/example-elliptic-sha1.p12
new file mode 100644
index 0000000..162214d
Binary files /dev/null and b/tests/certigo/example-elliptic-sha1.p12 differ
diff --git a/tests/certigo/example-elliptic-sha1.p7b b/tests/certigo/example-elliptic-sha1.p7b
new file mode 100644
index 0000000..6385590
--- /dev/null
+++ b/tests/certigo/example-elliptic-sha1.p7b
@@ -0,0 +1,17 @@
+-----BEGIN PKCS7-----
+MIICuQYJKoZIhvcNAQcCoIICqjCCAqYCAQExADALBgkqhkiG9w0BBwGgggKMMIIC
+iDCCAeqgAwIBAgIJAJ/xjMI6FKOAMAkGByqGSM49BAEwXjELMAkGA1UEBhMCVVMx
+CzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxl
+MR4wHAYDVQQDExVleGFtcGxlLWVsbGlwdGljLXNoYTEwHhcNMTYwNjIyMDAyMzIw
+WhcNMjMwNDI3MDAyMzIwWjBeMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEDAO
+BgNVBAoTB2NlcnRpZ28xEDAOBgNVBAsTB2V4YW1wbGUxHjAcBgNVBAMTFWV4YW1w
+bGUtZWxsaXB0aWMtc2hhMTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEARBY2NPz
+8x6YNLA9UkPpPSoNM+JsLO6giyTuIwRy1j2PN94bmPRZcvffFMHo0jBbof/uEEaz
+Jm0WAojmcqqED6caAMu+QcYrPdugHCHO1lv5iwZ5sJyswQ8qygaroMWBg7QaXjAs
+1p4Oncuh37CxRj70mse0YEPt+neBD5BM+8ZDchFXo08wTTAdBgNVHSUEFjAUBggr
+BgEFBQcDAgYIKwYBBQUHAwEwLAYDVR0RBCUwI4cEfwAAAYcQAAAAAAAAAAAAAAAA
+AAAAAYIJbG9jYWxob3N0MAkGByqGSM49BAEDgYwAMIGIAkIByNx56XB0CyNR3vKI
+Rdn9uoo8Q9PqBlO8ZtldeF+MqI/UvcnbrVxn7d5+lNj6K2YY2GzwV+IdxRyPJSsH
+T03pww0CQgE5ssxuHZXCw1zLFXPilEHKpx1B3umRwR9q0lVc63d9zFT/Dz5LQqF0
+2WtegKS3Kr6M7R8fn2QvsdzOPqlcN57E2aEAMQA=
+-----END PKCS7-----
diff --git a/tests/certigo/example-leaf.crt b/tests/certigo/example-leaf.crt
new file mode 100644
index 0000000..b9ee9fe
--- /dev/null
+++ b/tests/certigo/example-leaf.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMH
+ZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoX
+DTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYD
+VQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxl
+LWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3
+v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69
+w8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhR
+pPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84c
+zKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF
+5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2
+Np6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAs
+BgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJ
+KoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sM
+lM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7
+LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7d
+vBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeL
+Fj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2Xl
+iJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU=
+-----END CERTIFICATE-----
diff --git a/tests/certigo/example-leaf.p12 b/tests/certigo/example-leaf.p12
new file mode 100644
index 0000000..4b857d2
Binary files /dev/null and b/tests/certigo/example-leaf.p12 differ
diff --git a/tests/certigo/example-leaf.p7b b/tests/certigo/example-leaf.p7b
new file mode 100644
index 0000000..78ae38b
--- /dev/null
+++ b/tests/certigo/example-leaf.p7b
@@ -0,0 +1,22 @@
+-----BEGIN PKCS7-----
+MIIDrQYJKoZIhvcNAQcCoIIDnjCCA5oCAQExADALBgkqhkiG9w0BBwGgggOAMIID
+fDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYT
+AlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhh
+bXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoXDTIz
+MDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQK
+EwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLWxl
+YWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3v34f
+isqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69w8v7
+SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZ
+K6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPy
+t9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5i
+SV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i
+464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNV
+HREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZI
+hvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05
+kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7LstA
+/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7dvBVC
+csX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeLFj2k
+leqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2XliJjA
+qaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIWhADEA
+-----END PKCS7-----
diff --git a/tests/certigo/example-root.crt b/tests/certigo/example-root.crt
new file mode 100644
index 0000000..2299ec9
--- /dev/null
+++ b/tests/certigo/example-root.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIJAKg+LQlirffwMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMH
+ZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1yb290MB4XDTE2MDYxMDIyMTQxMVoX
+DTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYD
+VQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxl
+LXJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOEoSiNjMQ8/z
+UFcQW89LWw+UeTXKGwNDSpGjyi8jBKZ1lWPbnMmrjI6DZ9ReevHHzqBdKZt+9NFP
+FEz7djDMRByIuJhRvzhfFBflaIdSeNk2+NpUaFuUUUd6IIePu0AdRveJ8ZGHXRwC
+eEDIVCZS4oBYPHOhX/zMWDg8vSO4pSxTjGc7I8fHxaUSkVzUBbeO9T/1eFk0m2ux
+s3UziUck2X/8YqRd+p/EaBED78nXvKRALAguKAzqxIgk3ccPK0SVQFNFq+eV1/qo
+8coueQuqMpCAvwVkfpVKhneyC2NlMrfzlcZZbfG/irlSjQn5+ExZX4Isy1pCUbOi
+VfSrsCdtAgMBAAGjJjAkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/
+AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQCLEJU65vTU+oLbNHLOCR6fALrbjK7xsi6S
+FDpSXBMm74MWsy3myDBmXpOcN8hCYgsgivUXTQz9ynXP/pzOj4b83zzlaOfPtLTA
+mMhKWVV4Q85mrDQz+HzG4lKXM78eTsD8PyrocA/tSE7mVEJ0Jal4E2KI/Z9/fqpY
+FLB6LFlx5n83ehXM/egA0l4OeCC9nBKCeNUN3sIQO85lljyzAJdtWnsdoWogJs6q
+jcV8n2U5xjZxN5ZFdclYLjq6g2cjEXXMQxb8b7ZhHjLWFdjHP85UvXHK3DpK3JmU
+g8bYS7t1DJffDQNjawhlsMycKZN+r0ND0Um4m7AjGqxbKT/M2yKF
+-----END CERTIFICATE-----
diff --git a/tests/certigo/example-root.p12 b/tests/certigo/example-root.p12
new file mode 100644
index 0000000..f8ac2af
Binary files /dev/null and b/tests/certigo/example-root.p12 differ
diff --git a/tests/certigo/example-root.p7b b/tests/certigo/example-root.p7b
new file mode 100644
index 0000000..bd94763
--- /dev/null
+++ b/tests/certigo/example-root.p7b
@@ -0,0 +1,21 @@
+-----BEGIN PKCS7-----
+MIIDhAYJKoZIhvcNAQcCoIIDdTCCA3ECAQExADALBgkqhkiG9w0BBwGgggNXMIID
+UzCCAjugAwIBAgIJAKg+LQlirffwMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYT
+AlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhh
+bXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1yb290MB4XDTE2MDYxMDIyMTQxMVoXDTIz
+MDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQK
+EwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJv
+b3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOEoSiNjMQ8/zUFcQ
+W89LWw+UeTXKGwNDSpGjyi8jBKZ1lWPbnMmrjI6DZ9ReevHHzqBdKZt+9NFPFEz7
+djDMRByIuJhRvzhfFBflaIdSeNk2+NpUaFuUUUd6IIePu0AdRveJ8ZGHXRwCeEDI
+VCZS4oBYPHOhX/zMWDg8vSO4pSxTjGc7I8fHxaUSkVzUBbeO9T/1eFk0m2uxs3Uz
+iUck2X/8YqRd+p/EaBED78nXvKRALAguKAzqxIgk3ccPK0SVQFNFq+eV1/qo8cou
+eQuqMpCAvwVkfpVKhneyC2NlMrfzlcZZbfG/irlSjQn5+ExZX4Isy1pCUbOiVfSr
+sCdtAgMBAAGjJjAkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEA
+MA0GCSqGSIb3DQEBCwUAA4IBAQCLEJU65vTU+oLbNHLOCR6fALrbjK7xsi6SFDpS
+XBMm74MWsy3myDBmXpOcN8hCYgsgivUXTQz9ynXP/pzOj4b83zzlaOfPtLTAmMhK
+WVV4Q85mrDQz+HzG4lKXM78eTsD8PyrocA/tSE7mVEJ0Jal4E2KI/Z9/fqpYFLB6
+LFlx5n83ehXM/egA0l4OeCC9nBKCeNUN3sIQO85lljyzAJdtWnsdoWogJs6qjcV8
+n2U5xjZxN5ZFdclYLjq6g2cjEXXMQxb8b7ZhHjLWFdjHP85UvXHK3DpK3JmUg8bY
+S7t1DJffDQNjawhlsMycKZN+r0ND0Um4m7AjGqxbKT/M2yKFoQAxAA==
+-----END PKCS7-----
diff --git a/tests/google.dk/generate.bash b/tests/google.dk/generate.bash
new file mode 100755
index 0000000..d46cc77
--- /dev/null
+++ b/tests/google.dk/generate.bash
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright (c) 2012 The libmumble Developers
+# The use of this source code is goverened by a BSD-style
+# license that can be found in the LICENSE-file.
+
+shopt -s expand_aliases
+
+# Generate test fixtures from the source file, '*.google.dk-chain.pem'.
+# This file was generated by visting www.google.dk in Google Chrome on Linux
+# on 29-12-2012. The file was exported as 'Base64-encoded ASCII, certificate chain'.
+
+# Generate PKCS12 file for testing X509Certificate::FromPKCS12
+echo "" | openssl pkcs12 -export -nodes -nokeys -password stdin -out wildcard-google.dk-chain.p12 -in wildcard-google.dk-chain.pem
+
+# Generate PKCS12 file with password 'password' for testing X509Certificate::FromPKCS12
+echo "password" | openssl pkcs12 -export -nodes -nokeys -password stdin -out wildcard-google.dk-chain-password.p12 -in wildcard-google.dk-chain.pem
+
+# Generate DER for leaf cert to test regular import, as well as other per-cert methods.
+openssl x509 -in wildcard-google.dk-chain.pem -inform PEM -out wildcard-google.dk-leaf.crt -outform DER
+
+# Generate SHA1 and SHA256 digests for leaf
+cat wildcard-google.dk-leaf.crt | openssl sha -sha1 -binary > wildcard-google.dk-leaf.sha1
+cat wildcard-google.dk-leaf.crt | openssl sha -sha256 -binary > wildcard-google.dk-leaf.sha256
+
+# Extract notBefore and notAfter dates
+alias mumble_tconv="python -c \"import sys; import time; import calendar; sys.stdout.write(str(int(calendar.timegm(time.strptime(sys.stdin.read()[:-1], '%b %d %H:%M:%S %Y %Z')))))\""
+openssl x509 -in wildcard-google.dk-leaf.crt -inform DER -noout -startdate | sed 's,notBefore=,,' | mumble_tconv > wildcard-google.dk-leaf.notBefore
+openssl x509 -in wildcard-google.dk-leaf.crt -inform DER -noout -enddate | sed 's,notAfter=,,' | mumble_tconv > wildcard-google.dk-leaf.notAfter
diff --git a/tests/google.dk/wildcard-google.dk-chain-password.p12 b/tests/google.dk/wildcard-google.dk-chain-password.p12
new file mode 100644
index 0000000..a932da5
Binary files /dev/null and b/tests/google.dk/wildcard-google.dk-chain-password.p12 differ
diff --git a/tests/google.dk/wildcard-google.dk-chain.p12 b/tests/google.dk/wildcard-google.dk-chain.p12
new file mode 100644
index 0000000..ee9548b
Binary files /dev/null and b/tests/google.dk/wildcard-google.dk-chain.p12 differ
diff --git a/tests/google.dk/wildcard-google.dk-chain.pem b/tests/google.dk/wildcard-google.dk-chain.pem
new file mode 100644
index 0000000..e665cf2
--- /dev/null
+++ b/tests/google.dk/wildcard-google.dk-chain.pem
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIIDhTCCAu6gAwIBAgIKUCbzKgAAAAB12jANBgkqhkiG9w0BAQUFADBGMQswCQYD
+VQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZR29vZ2xlIElu
+dGVybmV0IEF1dGhvcml0eTAeFw0xMjEyMDYwODU2MDRaFw0xMzA2MDcxOTQzMjda
+MGUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N
+b3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMRQwEgYDVQQDFAsqLmdv
+b2dsZS5kazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1VtV/MQPnCwnC8Ey
+2El3QtrRKCYqbRqtYJxxKj/GqsFGRoWWf59Ton57FgIlIDEj/vPVu8QSpSF+Evlh
+9OV5hzPViQ48qXwb6x+agP6C1EkRfyLv7zrgTY8yEyF6Vq37j1A6C3hekbPAXIlK
+AxpwPz+OWwjP4lH8GsT2jNOxz+0CAwEAAaOCAVkwggFVMB0GA1UdJQQWMBQGCCsG
+AQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUlqvdcZlgQFZxxP0iBs7t/UrIE8Aw
+HwYDVR0jBBgwFoAUv8Aw6/VDET5nup6R+/xq2uNrEiQwWwYDVR0fBFQwUjBQoE6g
+TIZKaHR0cDovL3d3dy5nc3RhdGljLmNvbS9Hb29nbGVJbnRlcm5ldEF1dGhvcml0
+eS9Hb29nbGVJbnRlcm5ldEF1dGhvcml0eS5jcmwwZgYIKwYBBQUHAQEEWjBYMFYG
+CCsGAQUFBzAChkpodHRwOi8vd3d3LmdzdGF0aWMuY29tL0dvb2dsZUludGVybmV0
+QXV0aG9yaXR5L0dvb2dsZUludGVybmV0QXV0aG9yaXR5LmNydDAMBgNVHRMBAf8E
+AjAAMCEGA1UdEQQaMBiCCyouZ29vZ2xlLmRrgglnb29nbGUuZGswDQYJKoZIhvcN
+AQEFBQADgYEAOHkCJyRXNS4tAQf4/2h6ODLR1X7HJ7Mb5nPFABYSalCDMbxh3ytG
+IOZYCudfLfAw5oB9+Cozt2B1F+pZBawXeSZmuNjYmsuBIJ9E+BjayHegoTuSlOPt
+sqCcsha50+UYEnKqbDoeK2XjbiXIKyKBR0NA28m3b3+Of6QWPI9zUmY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICsDCCAhmgAwIBAgIDC2dxMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
+MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
+aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDkwNjA4MjA0MzI3WhcNMTMwNjA3MTk0MzI3
+WjBGMQswCQYDVQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZ
+R29vZ2xlIEludGVybmV0IEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAye23pIucV+eEPkB9hPSP0XFjU5nneXQUr0SZMyCSjXvlKAy6rWxJfoNf
+NFlOCnowzdDXxFdF7dWq1nMmzq0yE7jXDx07393cCDaob1FEm8rWIFJztyaHNWrb
+qeXUWaUr/GcZOfqTGBhs3t0lig4zFEfC7wFQeeT9adGnwKziV28CAwEAAaOBozCB
+oDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFL/AMOv1QxE+Z7qekfv8atrjaxIk
+MB8GA1UdIwQYMBaAFEjmaPkr0rKV10fYIyAQTzOYkJ/UMBIGA1UdEwEB/wQIMAYB
+Af8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20v
+Y3Jscy9zZWN1cmVjYS5jcmwwDQYJKoZIhvcNAQEFBQADgYEAuIojxkiWsRF8YHde
+BZqrocb6ghwYB8TrgbCoZutJqOkM0ymt9e8kTP3kS8p/XmOrmSfLnzYhLLkQYGfN
+0rTw8Ktx5YtaiScRhKqOv5nwnQkhClIZmloJ0pC3+gz4fniisIWvXEyZ2VxVKfml
+UUIuOss4jHg7y/j7lYe8vJD5UDI=
+-----END CERTIFICATE-----
+-----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-----
diff --git a/tests/google.dk/wildcard-google.dk-leaf.crt b/tests/google.dk/wildcard-google.dk-leaf.crt
new file mode 100644
index 0000000..31fc2cd
Binary files /dev/null and b/tests/google.dk/wildcard-google.dk-leaf.crt differ
diff --git a/tests/google.dk/wildcard-google.dk-leaf.notAfter b/tests/google.dk/wildcard-google.dk-leaf.notAfter
new file mode 100644
index 0000000..2554c94
--- /dev/null
+++ b/tests/google.dk/wildcard-google.dk-leaf.notAfter
@@ -0,0 +1 @@
+1370634207
\ No newline at end of file
diff --git a/tests/google.dk/wildcard-google.dk-leaf.notBefore b/tests/google.dk/wildcard-google.dk-leaf.notBefore
new file mode 100644
index 0000000..2568d64
--- /dev/null
+++ b/tests/google.dk/wildcard-google.dk-leaf.notBefore
@@ -0,0 +1 @@
+1354784164
\ No newline at end of file
diff --git a/tests/google.dk/wildcard-google.dk-leaf.sha1 b/tests/google.dk/wildcard-google.dk-leaf.sha1
new file mode 100644
index 0000000..3fc4abd
--- /dev/null
+++ b/tests/google.dk/wildcard-google.dk-leaf.sha1
@@ -0,0 +1 @@
+��Q��K�;gfM����`:
\ No newline at end of file
diff --git a/tests/google.dk/wildcard-google.dk-leaf.sha256 b/tests/google.dk/wildcard-google.dk-leaf.sha256
new file mode 100644
index 0000000..4e8a1e2
--- /dev/null
+++ b/tests/google.dk/wildcard-google.dk-leaf.sha256
@@ -0,0 +1 @@
+H)��^�a����S at p��hk>ݤ�������
\ No newline at end of file
diff --git a/tests/keys/authorized_keys b/tests/keys/authorized_keys
new file mode 100755
index 0000000..72ecb78
--- /dev/null
+++ b/tests/keys/authorized_keys
@@ -0,0 +1,4 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBANpkYqVCRd2VhGthYvNOgLRkbRJ3ddpsn2bwQ2e3IgPyOt7NzmPU6QBAtNwz8vdKDZ9lK3AkOLlASCkbEcJn4g36M17cKqIrI5LiM3WUWJ2sfnumXR7l9rm9rTR0Gt1aoLxCGGY/j8ZyszjbgqL6pj7g/8DKQRifME1BIxc6QpzfAAAAFQCTKDNz3qaPpz0NSQDsvcLG7f0VPQAAAIEApH3XdJ9ZA+dUJe1PyBCmMXTzvIcWPuyni5/2Tj3/YmufHfkj/hl/ie2G6QvsNP0lL4HYJ3k14T1V3BHVzzHawePbIHOHybexeccNFkvUeKUYi4xsEQ2j8fiJ5cX+x8OAMX3z7O2mjyIss8zlXSl3r51CvJprZdinen8LidNdJrAAAACATeeFTetXwuvzPZTwjAF016a083d67SKRnRy7W7rMHXAP+hG9leBS/rlrvt7Rei17N7cb8jMr91PU [...]
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCb7huJavmyo6KFXtPmmhoy15AE2PZUrMabiD6MbQ1Vd7hdKOSs3seK3ytUyzb00UeRZi3RCi3Zl+CCeUP7z+bTC6JslF1oq4j6RyV18UCjzY5VAonpej7dhgEz/DK5/CB7/atlAINolplVbMOL+LvG6evHnoGIV6k1yU/WwxiYlbROc4Wb5K+TbT/gWt+cQFhgfehz3slnsG6BrYt02ievXtqYl65+IKKZjdRaQSZZ8/x3JclYPW9cL6QqiQOJsmt5zMZBlXaDXj1HbnxG/3HQwZd0m5Byf7oIl57GD/zGy4zOe+L1MWYEK1/fdKWYHCrUBZdz+yRkHp6QR9ECKFhf jeroen at Jeroens-MacBook-Pro.local
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBPiVelHbhF5vGIPnh4XqOUJJRvuJJqH3ExkhlmNNNQNufyohn1UR/88Bbry65B0ToKibTtHd7k2pxk3mAUfjWg= jeroen at Jeroens-MacBook-Pro.local
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGaRAow/S++YWvT9l4XgcBwPFBTECa9GEFMoh7e/x0mi jeroen at Jeroens-MacBook-Pro.local
diff --git a/tests/keys/blabla.pem b/tests/keys/blabla.pem
new file mode 100644
index 0000000..a6248cb
--- /dev/null
+++ b/tests/keys/blabla.pem
@@ -0,0 +1,12 @@
+-----BEGIN BLABLA KOEKJES-----
+MIIBuwIBAAKBgQDaZGKlQkXdlYRrYWLzToC0ZG0Sd3XabJ9m8ENntyID8jrezc5j
+1OkAQLTcM/L3Sg2fZStwJDi5QEgpGxHCZ+IN+jNe3CqiKyOS4jN1lFidrH57pl0e
+5fa5va00dBrdWqC8QhhmP4/GcrM424Ki+qY+4P/AykEYnzBNQSMXOkKc3wIVAJMo
+M3Pepo+nPQ1JAOy9wsbt/RU9AoGBAKR913SfWQPnVCXtT8gQpjF087yHFj7sp4uf
+9k49/2Jrnx35I/4Zf4nthukL7DT9JS+B2Cd5NeE9VdwR1c8x2sHj2yBzh8m3sXnH
+DRZL1HilGIuMbBENo/H4ieXF/sfDgDF98+ztpo8iLLPM5V0pd6+dQryaa2XYp3p/
+C4nTXSawAoGATeeFTetXwuvzPZTwjAF016a083d67SKRnRy7W7rMHXAP+hG9leBS
+/rlrvt7Rei17N7cb8jMr91PUgzbWxVvzS4NPsuOaOUvpS5Gga/96OV5fJf0XV4vp
+I16kJxF+bY+nZwlbieGSY2ckjYkOtDslII+zCIXLtydhLikbQ49A/y8CFCw8rQUB
+M4bNxYGVzGRuIodQzZys
+-----END BLABLA KOEKJES-----
diff --git a/tests/keys/fingerprints.txt b/tests/keys/fingerprints.txt
new file mode 100755
index 0000000..fb030e1
--- /dev/null
+++ b/tests/keys/fingerprints.txt
@@ -0,0 +1,17 @@
+$ ssh-keygen -E md5 -lf id_rsa
+2048 MD5:3a:d4:61:17:a0:61:92:f1:3e:55:be:b3:cd:4c:fa:6f
+
+$ ssh-keygen -E md5 -lf id_dsa.pub
+1024 MD5:6c:42:ea:84:54:e5:49:b8:55:ca:dd:7f:c8:66:09:ca
+
+$ ssh-keygen -E md5 -lf id_ecdsa.pub
+256 MD5:10:0b:0d:5f:53:a3:6e:63:dc:42:08:55:52:cd:c3:40
+
+$ ssh-keygen -E md5 -lf id_ecdsa384.pub
+384 MD5:8c:f3:73:6c:4a:28:cf:2b:d6:3b:bf:32:78:d0:06:30
+
+$ ssh-keygen -E md5 -lf id_ecdsa521.pub
+521 MD5:90:4d:4c:50:be:87:9b:f0:55:7a:f9:6b:99:35:f1:c2
+
+$ ssh-keygen -E md5 -lf id_ed25519.pub
+256 MD5:2c:9b:ea:2e:9a:4c:e1:fb:44:38:d8:54:b2:72:04:b3
diff --git a/tests/keys/id_dsa b/tests/keys/id_dsa
new file mode 100755
index 0000000..0fb424d
--- /dev/null
+++ b/tests/keys/id_dsa
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQDaZGKlQkXdlYRrYWLzToC0ZG0Sd3XabJ9m8ENntyID8jrezc5j
+1OkAQLTcM/L3Sg2fZStwJDi5QEgpGxHCZ+IN+jNe3CqiKyOS4jN1lFidrH57pl0e
+5fa5va00dBrdWqC8QhhmP4/GcrM424Ki+qY+4P/AykEYnzBNQSMXOkKc3wIVAJMo
+M3Pepo+nPQ1JAOy9wsbt/RU9AoGBAKR913SfWQPnVCXtT8gQpjF087yHFj7sp4uf
+9k49/2Jrnx35I/4Zf4nthukL7DT9JS+B2Cd5NeE9VdwR1c8x2sHj2yBzh8m3sXnH
+DRZL1HilGIuMbBENo/H4ieXF/sfDgDF98+ztpo8iLLPM5V0pd6+dQryaa2XYp3p/
+C4nTXSawAoGATeeFTetXwuvzPZTwjAF016a083d67SKRnRy7W7rMHXAP+hG9leBS
+/rlrvt7Rei17N7cb8jMr91PUgzbWxVvzS4NPsuOaOUvpS5Gga/96OV5fJf0XV4vp
+I16kJxF+bY+nZwlbieGSY2ckjYkOtDslII+zCIXLtydhLikbQ49A/y8CFCw8rQUB
+M4bNxYGVzGRuIodQzZys
+-----END DSA PRIVATE KEY-----
diff --git a/tests/keys/id_dsa.pem b/tests/keys/id_dsa.pem
new file mode 100755
index 0000000..eb2a1b3
--- /dev/null
+++ b/tests/keys/id_dsa.pem
@@ -0,0 +1,12 @@
+-----BEGIN PUBLIC KEY-----
+MIIBtzCCASwGByqGSM44BAEwggEfAoGBANpkYqVCRd2VhGthYvNOgLRkbRJ3ddps
+n2bwQ2e3IgPyOt7NzmPU6QBAtNwz8vdKDZ9lK3AkOLlASCkbEcJn4g36M17cKqIr
+I5LiM3WUWJ2sfnumXR7l9rm9rTR0Gt1aoLxCGGY/j8ZyszjbgqL6pj7g/8DKQRif
+ME1BIxc6QpzfAhUAkygzc96mj6c9DUkA7L3Cxu39FT0CgYEApH3XdJ9ZA+dUJe1P
+yBCmMXTzvIcWPuyni5/2Tj3/YmufHfkj/hl/ie2G6QvsNP0lL4HYJ3k14T1V3BHV
+zzHawePbIHOHybexeccNFkvUeKUYi4xsEQ2j8fiJ5cX+x8OAMX3z7O2mjyIss8zl
+XSl3r51CvJprZdinen8LidNdJrADgYQAAoGATeeFTetXwuvzPZTwjAF016a083d6
+7SKRnRy7W7rMHXAP+hG9leBS/rlrvt7Rei17N7cb8jMr91PUgzbWxVvzS4NPsuOa
+OUvpS5Gga/96OV5fJf0XV4vpI16kJxF+bY+nZwlbieGSY2ckjYkOtDslII+zCIXL
+tydhLikbQ49A/y8=
+-----END PUBLIC KEY-----
diff --git a/tests/keys/id_dsa.pub b/tests/keys/id_dsa.pub
new file mode 100755
index 0000000..f81a0ff
--- /dev/null
+++ b/tests/keys/id_dsa.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBANpkYqVCRd2VhGthYvNOgLRkbRJ3ddpsn2bwQ2e3IgPyOt7NzmPU6QBAtNwz8vdKDZ9lK3AkOLlASCkbEcJn4g36M17cKqIrI5LiM3WUWJ2sfnumXR7l9rm9rTR0Gt1aoLxCGGY/j8ZyszjbgqL6pj7g/8DKQRifME1BIxc6QpzfAAAAFQCTKDNz3qaPpz0NSQDsvcLG7f0VPQAAAIEApH3XdJ9ZA+dUJe1PyBCmMXTzvIcWPuyni5/2Tj3/YmufHfkj/hl/ie2G6QvsNP0lL4HYJ3k14T1V3BHVzzHawePbIHOHybexeccNFkvUeKUYi4xsEQ2j8fiJ5cX+x8OAMX3z7O2mjyIss8zlXSl3r51CvJprZdinen8LidNdJrAAAACATeeFTetXwuvzPZTwjAF016a083d67SKRnRy7W7rMHXAP+hG9leBS/rlrvt7Rei17N7cb8jMr91PU [...]
diff --git a/tests/keys/id_dsa.pw b/tests/keys/id_dsa.pw
new file mode 100644
index 0000000..65e842d
--- /dev/null
+++ b/tests/keys/id_dsa.pw
@@ -0,0 +1,15 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,B4514C2C80700700
+
+UrxpYhcK8SbCuvDbWvcTZD5MbqfSYleL1nNotXqnfgXUDX14gd0lWP6o2WLtR5NP
+bgiTCiFp70jIbaXHBtLhrFQZIpbspH6aJSulfoKkwhJIpfbsZsJXPa5B3phKxfzI
+w3vPnLkZsaQ4o1/Qrrlzh7CBGhGvcTgYccfvkWTAg5kLoo/3WxxSPMq1q4S74m5M
+KNpb/59hjDq4o/ESlAdqF2unI916RDFkdCzBLUTepbKZ339XIKgirza0trj23MZ0
+UpRALg3RIPZCSJk8Jol+NEa4aY1IJrkYktgO/AseGUtZT6Bkue+eljJow+L6LIye
+1+pKvyans6vEtw01sZteGf+vhzxBqDtNBunPY1szds44PgfVr5MuJ4nEO1SLZcQ5
+UdJM+gJKHri6v0lsnfN3nPTu5fGXf95uMPk/8NXktpZLEDqYYIsP8ybhdjQBZErG
+IiGjgpXIAkAHrtgw/ZGIIX5ju73wlDUria4sBlYTDCAzDzuAVeDgtKIcFu+Eafde
+TuIV9hhIzY+HDnePpTkj5DsnSZBuSLdanysVnV+cItPI4zW1bZz4cyd6JpO/IlWu
+z5yYEJFJd3zHs6Ioh62Hbg==
+-----END DSA PRIVATE KEY-----
diff --git a/tests/keys/id_ecdsa b/tests/keys/id_ecdsa
new file mode 100755
index 0000000..f1200b9
--- /dev/null
+++ b/tests/keys/id_ecdsa
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIJClObqzf27sgP6HEzqjecIXuI9EGfc0gyE91ex8H6tyoAoGCCqGSM49
+AwEHoUQDQgAEE+JV6UduEXm8Yg+eHheo5QklG+4kmofcTGSGWY001A25/KiGfVRH
+/zwFuvLrkHROgqJtO0d3uTanGTeYBR+NaA==
+-----END EC PRIVATE KEY-----
diff --git a/tests/keys/id_ecdsa.pem b/tests/keys/id_ecdsa.pem
new file mode 100755
index 0000000..9935d22
--- /dev/null
+++ b/tests/keys/id_ecdsa.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEE+JV6UduEXm8Yg+eHheo5QklG+4k
+mofcTGSGWY001A25/KiGfVRH/zwFuvLrkHROgqJtO0d3uTanGTeYBR+NaA==
+-----END PUBLIC KEY-----
diff --git a/tests/keys/id_ecdsa.pub b/tests/keys/id_ecdsa.pub
new file mode 100755
index 0000000..7e6416b
--- /dev/null
+++ b/tests/keys/id_ecdsa.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBPiVelHbhF5vGIPnh4XqOUJJRvuJJqH3ExkhlmNNNQNufyohn1UR/88Bbry65B0ToKibTtHd7k2pxk3mAUfjWg= jeroen at Jeroens-MacBook-Pro.local
diff --git a/tests/keys/id_ecdsa.pw b/tests/keys/id_ecdsa.pw
new file mode 100644
index 0000000..4aa7bc2
--- /dev/null
+++ b/tests/keys/id_ecdsa.pw
@@ -0,0 +1,8 @@
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,A54E61446DF4FA7A
+
+GLAbvF0nBeOJACJjQom5VLNJrNh8VICxAmxdagPwdu/MxEQ9qTWhY+0Lq4FtKNX2
+n5DwgAg4mdu+dmc8Of80Ui8ZaeeQnqIxc7pOE/keT4BYx5wzMjSvK7LjuQaSM8T3
+uxcF6W+Hmd2m/+ea37/EaZ67EBA/uFXfPmQffDgeLnU=
+-----END EC PRIVATE KEY-----
diff --git a/tests/keys/id_ecdsa384 b/tests/keys/id_ecdsa384
new file mode 100644
index 0000000..ca22a43
--- /dev/null
+++ b/tests/keys/id_ecdsa384
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDDsZOO1hvwae0x40zEy5VXU2hoMa+A1dR71QHeuX8x27Pp/7gQ8vHKF
+V27dTNP496OgBwYFK4EEACKhZANiAAQ9RyeJz+PEgO7621HyNOdGBSNWnmas0YlT
+Fz67bAJIMvUKaSsz28L98O6fpX0idzqRJiFxb9FCKtnwxGufUWuN4/WaPVb8R6EH
+Z8oHEqfHk547tzTXKnu1dtPOs3GFIfk=
+-----END EC PRIVATE KEY-----
diff --git a/tests/keys/id_ecdsa384.pem b/tests/keys/id_ecdsa384.pem
new file mode 100644
index 0000000..f66ce76
--- /dev/null
+++ b/tests/keys/id_ecdsa384.pem
@@ -0,0 +1,5 @@
+-----BEGIN PUBLIC KEY-----
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEPUcnic/jxIDu+ttR8jTnRgUjVp5mrNGJ
+Uxc+u2wCSDL1CmkrM9vC/fDun6V9Inc6kSYhcW/RQirZ8MRrn1FrjeP1mj1W/Eeh
+B2fKBxKnx5OeO7c01yp7tXbTzrNxhSH5
+-----END PUBLIC KEY-----
diff --git a/tests/keys/id_ecdsa384.pub b/tests/keys/id_ecdsa384.pub
new file mode 100644
index 0000000..09938de
--- /dev/null
+++ b/tests/keys/id_ecdsa384.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBD1HJ4nP48SA7vrbUfI050YFI1aeZqzRiVMXPrtsAkgy9QppKzPbwv3w7p+lfSJ3OpEmIXFv0UIq2fDEa59Ra43j9Zo9VvxHoQdnygcSp8eTnju3NNcqe7V2086zcYUh+Q== jeroen at Jeroens-MacBook-Pro.local
diff --git a/tests/keys/id_ecdsa384.pw b/tests/keys/id_ecdsa384.pw
new file mode 100644
index 0000000..63790d7
--- /dev/null
+++ b/tests/keys/id_ecdsa384.pw
@@ -0,0 +1,9 @@
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,562CF96492F36417
+
+JSxz7Uzweb8jPLb8KJPmJr5MMcLiSg5xX0MF1ZhDmpeiGwqLuUQiefyPkF0sh5hP
+N5qZ11ns5Qjb04gE3J55uIusuB/HH4ytvTTC39gSYyogys3kxR4tCMBJTt1y5GdG
+js/aRZkePbb2Xjcw6aXet0e2yDddSM40RVK75AWvx3r0TE10m6Z6nWtIyMnHx+Yv
+D7w+Wtv027Byr6tUeQL3v9FX31eqR8TM
+-----END EC PRIVATE KEY-----
diff --git a/tests/keys/id_ecdsa521 b/tests/keys/id_ecdsa521
new file mode 100644
index 0000000..2612a3f
--- /dev/null
+++ b/tests/keys/id_ecdsa521
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHbAgEBBEEY8wij7M3KRxa1mhqMHJVFgXepKhMMjfz9VdT9yak5Tx03w/ionYOR
+5AQoXLne/7IyTYNHOugH1oW550YlWytr5qAHBgUrgQQAI6GBiQOBhgAEASC3mN2u
+DnOqMoPaLhHNhHRDaqLFm39+kJtAkq6YaSlnS8w6CRG2qClsX2zQ0Vbar7b6W2Ru
+tLKpjfowTWAFHuObAP2WxygMnN0m7S/Z6ed9rRyealUSb+g4xStngm/mfpqFXke/
+9tTMRPWPs9AuZS3BeSXO2QE4mvxkH/Fos63G4CTe
+-----END EC PRIVATE KEY-----
diff --git a/tests/keys/id_ecdsa521.pem b/tests/keys/id_ecdsa521.pem
new file mode 100644
index 0000000..4cd362b
--- /dev/null
+++ b/tests/keys/id_ecdsa521.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBILeY3a4Oc6oyg9ouEc2EdENqosWb
+f36Qm0CSrphpKWdLzDoJEbaoKWxfbNDRVtqvtvpbZG60sqmN+jBNYAUe45sA/ZbH
+KAyc3SbtL9np532tHJ5qVRJv6DjFK2eCb+Z+moVeR7/21MxE9Y+z0C5lLcF5Jc7Z
+ATia/GQf8WizrcbgJN4=
+-----END PUBLIC KEY-----
diff --git a/tests/keys/id_ecdsa521.pub b/tests/keys/id_ecdsa521.pub
new file mode 100644
index 0000000..6fff7ee
--- /dev/null
+++ b/tests/keys/id_ecdsa521.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAEgt5jdrg5zqjKD2i4RzYR0Q2qixZt/fpCbQJKumGkpZ0vMOgkRtqgpbF9s0NFW2q+2+ltkbrSyqY36ME1gBR7jmwD9lscoDJzdJu0v2ennfa0cnmpVEm/oOMUrZ4Jv5n6ahV5Hv/bUzET1j7PQLmUtwXklztkBOJr8ZB/xaLOtxuAk3g== jeroen at Jeroens-MacBook-Pro.local
diff --git a/tests/keys/id_ecdsa521.pw b/tests/keys/id_ecdsa521.pw
new file mode 100644
index 0000000..840bf49
--- /dev/null
+++ b/tests/keys/id_ecdsa521.pw
@@ -0,0 +1,10 @@
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,BD8E2ACC5CED7A39
+
+JuBN1vD5jjjRpz4ngBrnTVYI+bqvn9DvKONweO7vSYcHUpdf6YwqX8EGo1xKLMgs
+nEUC+bKp6xnN2v0J93uDfn0ctAHqRU5fINbpgZbT8R1xPj9EN9ILKmEm/j79GAdM
+AW+L8sxFwBnFRZBYlnviW7rn2xF0ewEqREU9ihxZvWORldiorR21um7By084x3Zp
+Gk4mR9CBK4bsc4+2wOzWzBRKxUXwuC8vcm0L3UZpB0nAWw2OtZpLLwjS/Js8otzw
+D0jknaOpCG0UkwQkuqcBq7dGYQ+5bznV2J2PI9IRcMA=
+-----END EC PRIVATE KEY-----
diff --git a/tests/keys/id_ed25519 b/tests/keys/id_ed25519
new file mode 100755
index 0000000..64fc324
--- /dev/null
+++ b/tests/keys/id_ed25519
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACBmkQKMP0vvmFr0/ZeF4HAcDxQUxAmvRhBTKIe3v8dJogAAAKhUZsrjVGbK
+4wAAAAtzc2gtZWQyNTUxOQAAACBmkQKMP0vvmFr0/ZeF4HAcDxQUxAmvRhBTKIe3v8dJog
+AAAEB5OFvaHkUXC3KoASk6WwFzL07SiF83lWJXX39kIP/jwGaRAow/S++YWvT9l4XgcBwP
+FBTECa9GEFMoh7e/x0miAAAAIGplcm9lbkBKZXJvZW5zLU1hY0Jvb2stUHJvLmxvY2FsAQ
+IDBAU=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/tests/keys/id_ed25519.pub b/tests/keys/id_ed25519.pub
new file mode 100755
index 0000000..6945559
--- /dev/null
+++ b/tests/keys/id_ed25519.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGaRAow/S++YWvT9l4XgcBwPFBTECa9GEFMoh7e/x0mi jeroen at Jeroens-MacBook-Pro.local
diff --git a/tests/keys/id_rsa b/tests/keys/id_rsa
new file mode 100644
index 0000000..8ea2e8a
--- /dev/null
+++ b/tests/keys/id_rsa
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAm+4biWr5sqOihV7T5poaMteQBNj2VKzGm4g+jG0NVXe4XSjk
+rN7Hit8rVMs29NFHkWYt0Qot2ZfggnlD+8/m0wuibJRdaKuI+kcldfFAo82OVQKJ
+6Xo+3YYBM/wyufwge/2rZQCDaJaZVWzDi/i7xunrx56BiFepNclP1sMYmJW0TnOF
+m+Svk20/4FrfnEBYYH3oc97JZ7Buga2LdNonr17amJeufiCimY3UWkEmWfP8dyXJ
+WD1vXC+kKokDibJreczGQZV2g149R258Rv9x0MGXdJuQcn+6CJeexg/8xsuMznvi
+9TFmBCtf33SlmBwq1AWXc/skZB6ekEfRAihYXwIDAQABAoIBAHRTwn9WK0o2AXz2
+LaePt5POdUbohXzOGKzXi7I/eP8V/ZiidVbyLHNR4oWzxSAHMRkr3Wph6aq3P2qX
+BTzK8SzpNRdD6Bu6PMpaYXwHq22IYHLTHgfshxHEcwlRUJannaRirob/RwmzsFim
+d4vo2E2hHaEigwgwPbA+qy1RBvxtKI76+smGy06CWI8CONb0R6SDRyzqFK34EJfb
+z7Rngda9xlzK26UiCEGFDRTx2JAN8C5sSyw1aqT8LR5zYCQaSkzjtXjWv9khNiw4
+wgZxddmh8HdUBzGDT2UHAPG2JazNZX8Tw9o/PVa2mK0PJD4KnMzC697YjIunVFFJ
+HkDTakECgYEAzOBRvKkiiUOtkEqZH+cx3gP5qYA/15Gs+Im9TIaB9EeVtkqlF9LX
+QImK3RgLUCfl3Ss7dkz2Dw76P5ESoNGBc4tayy9zUvwRnuWJAL/tmXewW/LsZ0GD
+7n5Un9cB5OloNOtmAtQOXCxMmw8YEAMf+8jj2ForewEF0Z9MQIeS9ukCgYEAwtcQ
+fy4whVQDQanDzVtOHRJ2vRN9wsY3vq/Yv7HB34MuwcUXouvj9t90zfJFrvpqG4uw
+DKtPTI9Fwp/z2SlG3Qsgz1Yt/VO6tGMd5OwwzIpJf5F+lApJY2d2AWFqKrL1yyPb
+6GRPNjavP/I6sJ1ZCP3FW9EB2NMQlzIMbUL32AcCgYEAjyXhFn/a2KvH9ryYtvjU
+F/sRE0S/1sA7akDbWj/VRzhJO+B17+pqafZwZ0Dojq4B5wHQ/zyQ5D6jzYxwxpr7
+5x6kZrmVy5LCQRLCIhr4SbWeLPDUCuV06Euulywkb6xCGk+rrCg8jFyLfgAS4QU9
+8LARutZt8Pjq9udl4OSZZBkCgYAsoJwLtWWxtDuGt768c7RhnlAKIMPGcCZmi9qG
+lc2FR4PXKDCwxX0Sl74mSd7CJGNXadhqHnbsX0ioOoDc9cJgcOMT+nZQNvRlyuoW
+/C51Oxt4l7e5at3CYfk6ebiajSEVZWJCSW+HSGE9sVrWB0RUdePVkvrsUfPT3cfQ
+4uzn0wKBgD5rst/mreOpf0axXINoQS8wSDUUnxDHVus4IAqhSt3j2U8U8adDpoVx
+k0v1Fq35oHzOTIrd7JNs3tBiLgzJcQLJ2kd1M+6VYeFb+6ne7H3jo+WaR0wkqYfn
+esjTUy2n5AqFUV5XPWfP6TCBz0zCDFO+sbfrJu47AYTm8WA1Hbm3
+-----END RSA PRIVATE KEY-----
diff --git a/tests/keys/id_rsa.pem b/tests/keys/id_rsa.pem
new file mode 100644
index 0000000..d3442ad
--- /dev/null
+++ b/tests/keys/id_rsa.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm+4biWr5sqOihV7T5poa
+MteQBNj2VKzGm4g+jG0NVXe4XSjkrN7Hit8rVMs29NFHkWYt0Qot2ZfggnlD+8/m
+0wuibJRdaKuI+kcldfFAo82OVQKJ6Xo+3YYBM/wyufwge/2rZQCDaJaZVWzDi/i7
+xunrx56BiFepNclP1sMYmJW0TnOFm+Svk20/4FrfnEBYYH3oc97JZ7Buga2LdNon
+r17amJeufiCimY3UWkEmWfP8dyXJWD1vXC+kKokDibJreczGQZV2g149R258Rv9x
+0MGXdJuQcn+6CJeexg/8xsuMznvi9TFmBCtf33SlmBwq1AWXc/skZB6ekEfRAihY
+XwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/tests/keys/id_rsa.pub b/tests/keys/id_rsa.pub
new file mode 100644
index 0000000..ca964b3
--- /dev/null
+++ b/tests/keys/id_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCb7huJavmyo6KFXtPmmhoy15AE2PZUrMabiD6MbQ1Vd7hdKOSs3seK3ytUyzb00UeRZi3RCi3Zl+CCeUP7z+bTC6JslF1oq4j6RyV18UCjzY5VAonpej7dhgEz/DK5/CB7/atlAINolplVbMOL+LvG6evHnoGIV6k1yU/WwxiYlbROc4Wb5K+TbT/gWt+cQFhgfehz3slnsG6BrYt02ievXtqYl65+IKKZjdRaQSZZ8/x3JclYPW9cL6QqiQOJsmt5zMZBlXaDXj1HbnxG/3HQwZd0m5Byf7oIl57GD/zGy4zOe+L1MWYEK1/fdKWYHCrUBZdz+yRkHp6QR9ECKFhf
diff --git a/tests/keys/id_rsa.pw b/tests/keys/id_rsa.pw
new file mode 100644
index 0000000..089ab24
--- /dev/null
+++ b/tests/keys/id_rsa.pw
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,403B381F3B13AEFF
+
+9ruofASuP7/Ai/cw3X83kQY6+Ve7CaqiHPwQ/hmhZtzN7R5oamQXtf44zSwKBfQt
+S0RUarhFf43eX3BGIYMEwxctu/J+uecFhqQ3n+3Z7gK7i+FyompcG2DP+Lg6ZbDy
+eta+EXGdNGXv3K1hjwMB194x2YEOlGXbprD7SGYaEwBopDVfyk3+4SECZ8HvYLDK
+YxwdOo3st429+ca+xuTeGVQ77psKKUPG/iBjJZvbdxvk3RSqsFCT7YGhWKCQcBUy
+8vRTYPWL2eS27T11LBn2LpYHlUMdIkbG3ETaMLd9dfFMHWJ8qxy//Kdk4BrQhI+x
++UTHF4XIxpzib7Y4DPrh/gotMd2ykAlJDfeblTMWrt50I98QO9f3jkYMiqtc71wM
+QE7Mw8vAVSkRnn4WBvSiJhTT/J1m3dhjApF01Sijf4wqnFKdFXELcepyILROCCKm
+5dFA8NnR7ROJJICSXRr8kQ5g6R4N+4CD8F+bpKNpTOplFjByNrLsJsX5Ec/n2WwX
+SProhVZEEVEuHa1ypryR3RNNQ7EIOuQqYJ9tW+Pgm0jP/m2vw7vjRLI9oM5L3gtL
+1+79V7RL2iHFdQqBW7GV38YrIRpW+Ph4NJoDUOUR6otZzB1hWWF7vWMwsaAIMqzS
+sOIOVHt9pVslvxSs9076lj2tCzOmFSE9+n0N4rWjUFvwzfK1EVMaD/s++ikvMMW+
+IKPAXdxnOMuG5e6dnZut+QpLaqwikXOxNWBU71ZBVHlSngMkJDB8sfFeG/3os3kl
+iq+ajQuSobTPnQX+eRCiEwVW/+L1iAm6Su/Lk0Qh3sNCkTaHknkNGFp0uMf8oVB9
+WHMZaAi+mOAMZLevjbwbBPay0bnl4BWJW+P0fZXWdcYsCNxemcj1ZwJj2cTaF9h3
+QJJZ0OUrY+wa+lOg4PGBaqmWYatm3kAlK1rpilOTjyu/CLPl/iQ3yMmKCsib3rXo
+XJm0Y4IsMJZXulQ3q7rGfZAryO0l1i4hdCVdogVoakh+3vNeCFhKHDPdilb0vxM9
+dFiG0CgtORtX//D3dZ9bkkO7yUjO5pEQlLzj7O9uduxuKy1FSS6ytKbJx0/HEj4e
+Wsd0oi+eXzIUyN9Ik7tgBOjEodyqo8/VAIZV0HFLr9kY0BowcXSpIbyBp5hCd7cB
+pTkCYWNHnjOROIvncHXTUwdrUQ1f/J0E9k0Tvbse1y4Z1F4zm0mePefs+pR88s7q
+8OAj71wr46AV5z4eXQz/reVXnYFBCso+cceBrotQUIPUFYfKXZ7yEZ0LFbXYCH0x
+y/mXk7at/WlnmNM22hWS17suJBHDi/WpGSzPMCJiTrR+V4LfH1WasIxN82raYwxh
+xlRs04Ygk7Jn4G4NaXKFixlF5ip3KxhBb5AMJHIhJVEQF/BiuXZRoqMI+sSxlgUa
+VGVXF/eKng3wk/u3ZORpl4qsy43EitPpppEm1v0VV1rTgQKaNQ+xjzJaTt+JOE0d
+kqzRdJ34xntCSAr11gmrzIoDx6CcDZd5TwUDgGC50vdj7y2D3Fjv8Vuun+qJ3jEZ
+FXytaWKUp2YdmgBHxW3a3K71jsifuYvlnUVBpS54GuzbyDbZ1Q7ljA==
+-----END RSA PRIVATE KEY-----
diff --git a/tests/keys/id_rsa.sshpem1 b/tests/keys/id_rsa.sshpem1
new file mode 100644
index 0000000..0b90881
--- /dev/null
+++ b/tests/keys/id_rsa.sshpem1
@@ -0,0 +1,9 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+Comment: "2048-bit RSA, converted by jeroen at Jeroens-MacBook-Pro.local "
+AAAAB3NzaC1yc2EAAAADAQABAAABAQCb7huJavmyo6KFXtPmmhoy15AE2PZUrMabiD6MbQ
+1Vd7hdKOSs3seK3ytUyzb00UeRZi3RCi3Zl+CCeUP7z+bTC6JslF1oq4j6RyV18UCjzY5V
+Aonpej7dhgEz/DK5/CB7/atlAINolplVbMOL+LvG6evHnoGIV6k1yU/WwxiYlbROc4Wb5K
++TbT/gWt+cQFhgfehz3slnsG6BrYt02ievXtqYl65+IKKZjdRaQSZZ8/x3JclYPW9cL6Qq
+iQOJsmt5zMZBlXaDXj1HbnxG/3HQwZd0m5Byf7oIl57GD/zGy4zOe+L1MWYEK1/fdKWYHC
+rUBZdz+yRkHp6QR9ECKFhf
+---- END SSH2 PUBLIC KEY ----
diff --git a/tests/keys/id_rsa.sshpem2 b/tests/keys/id_rsa.sshpem2
new file mode 100644
index 0000000..a97232b
--- /dev/null
+++ b/tests/keys/id_rsa.sshpem2
@@ -0,0 +1,8 @@
+-----BEGIN RSA PUBLIC KEY-----
+MIIBCgKCAQEAm+4biWr5sqOihV7T5poaMteQBNj2VKzGm4g+jG0NVXe4XSjkrN7H
+it8rVMs29NFHkWYt0Qot2ZfggnlD+8/m0wuibJRdaKuI+kcldfFAo82OVQKJ6Xo+
+3YYBM/wyufwge/2rZQCDaJaZVWzDi/i7xunrx56BiFepNclP1sMYmJW0TnOFm+Sv
+k20/4FrfnEBYYH3oc97JZ7Buga2LdNonr17amJeufiCimY3UWkEmWfP8dyXJWD1v
+XC+kKokDibJreczGQZV2g149R258Rv9x0MGXdJuQcn+6CJeexg/8xsuMznvi9TFm
+BCtf33SlmBwq1AWXc/skZB6ekEfRAihYXwIDAQAB
+-----END RSA PUBLIC KEY-----
diff --git a/tests/keys/message b/tests/keys/message
new file mode 100644
index 0000000..3211ff2
--- /dev/null
+++ b/tests/keys/message
@@ -0,0 +1 @@
+This is a test message
diff --git a/tests/keys/message.rsa.crypt b/tests/keys/message.rsa.crypt
new file mode 100644
index 0000000..c4d78c9
Binary files /dev/null and b/tests/keys/message.rsa.crypt differ
diff --git a/tests/keys/message.sig.dsa.sha1 b/tests/keys/message.sig.dsa.sha1
new file mode 100644
index 0000000..b7f99be
--- /dev/null
+++ b/tests/keys/message.sig.dsa.sha1
@@ -0,0 +1 @@
+0,{�$��8"���{���[&�5�]�����0F�D�2)����P
\ No newline at end of file
diff --git a/tests/keys/message.sig.dsa.sha256 b/tests/keys/message.sig.dsa.sha256
new file mode 100644
index 0000000..f087339
Binary files /dev/null and b/tests/keys/message.sig.dsa.sha256 differ
diff --git a/tests/keys/message.sig.ecdsa.sha1 b/tests/keys/message.sig.ecdsa.sha1
new file mode 100644
index 0000000..891b13a
Binary files /dev/null and b/tests/keys/message.sig.ecdsa.sha1 differ
diff --git a/tests/keys/message.sig.ecdsa.sha256 b/tests/keys/message.sig.ecdsa.sha256
new file mode 100644
index 0000000..e9bc80d
Binary files /dev/null and b/tests/keys/message.sig.ecdsa.sha256 differ
diff --git a/tests/keys/message.sig.ecdsa384.sha1 b/tests/keys/message.sig.ecdsa384.sha1
new file mode 100644
index 0000000..2bd4e2a
Binary files /dev/null and b/tests/keys/message.sig.ecdsa384.sha1 differ
diff --git a/tests/keys/message.sig.ecdsa384.sha256 b/tests/keys/message.sig.ecdsa384.sha256
new file mode 100644
index 0000000..064c97c
Binary files /dev/null and b/tests/keys/message.sig.ecdsa384.sha256 differ
diff --git a/tests/keys/message.sig.ecdsa521.sha1 b/tests/keys/message.sig.ecdsa521.sha1
new file mode 100644
index 0000000..b7c9f97
Binary files /dev/null and b/tests/keys/message.sig.ecdsa521.sha1 differ
diff --git a/tests/keys/message.sig.ecdsa521.sha256 b/tests/keys/message.sig.ecdsa521.sha256
new file mode 100644
index 0000000..91d40f3
--- /dev/null
+++ b/tests/keys/message.sig.ecdsa521.sha256
@@ -0,0 +1,3 @@
+0��AF���M�c��b���J��U
+��
،�9�o//��R
}K�9���mQE�`6V-�^��BR�d(Hz
̓�J�g���?*[�⃘]���^c��<&�c
+�cȘ����ۊx5
ނ)[�6D�v� ��
\ No newline at end of file
diff --git a/tests/keys/message.sig.rsa.md5 b/tests/keys/message.sig.rsa.md5
new file mode 100644
index 0000000..f2ad846
Binary files /dev/null and b/tests/keys/message.sig.rsa.md5 differ
diff --git a/tests/keys/message.sig.rsa.sha1 b/tests/keys/message.sig.rsa.sha1
new file mode 100644
index 0000000..73434db
--- /dev/null
+++ b/tests/keys/message.sig.rsa.sha1
@@ -0,0 +1 @@
+h�SVp
�'�S�+�� �״��=
�SBV��=��ok�o��B��^��;��7��1���)O���J��d��f-�,���ԨOBlO^`�3�
q�v���h0ZX�H��jp��CpHd_:ɚ��_���&l��xk�"XV��1
yl�tyV�<c7y�7�9Ĺ���]��ǘ�i�
`Q�������͂��H�%GL���
0]�f�Q;��0myN#�h0�k�[F8��{�rq\}fW
�@L��%���S�
\ No newline at end of file
diff --git a/tests/keys/message.sig.rsa.sha256 b/tests/keys/message.sig.rsa.sha256
new file mode 100644
index 0000000..845683e
Binary files /dev/null and b/tests/keys/message.sig.rsa.sha256 differ
diff --git a/tests/keys/opencpu.org.bundle b/tests/keys/opencpu.org.bundle
new file mode 100644
index 0000000..3fa737d
--- /dev/null
+++ b/tests/keys/opencpu.org.bundle
@@ -0,0 +1,86 @@
+-----BEGIN CERTIFICATE-----
+MIIFADCCA+igAwIBAgIQED8Wiv8pABa+dEMkbZvtyjANBgkqhkiG9w0BAQUFADBz
+MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
+VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEZMBcGA1UE
+AxMQUG9zaXRpdmVTU0wgQ0EgMjAeFw0xMjA1MDMwMDAwMDBaFw0xNTA1MDMyMzU5
+NTlaMFYxITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEUMBIGA1UE
+CxMLUG9zaXRpdmVTU0wxGzAZBgNVBAMTEnB1YmxpYy5vcGVuY3B1Lm9yZzCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMlvSfIY258yRs5oUCzotM3sbVp8
+nVe75I+Gjeu2ZVfUBd6uos8cNg4cjaDR4CouhGwHuru10gxJKKGiWgZFGD6D51qn
+u9DEDenSM/miD/jLSLlP/vxq/heCmz/e6l+M/VLpRRju7JIUlZX/XMXO0xBs1cVA
+U5vYmau+uJHFMwTmWbvh98EBrqPKUHiQlIyBbVX1IMlbcUh+H1/nc8b0ED46pUGQ
+M/WQ4TUNrdjyykpQgOL7XAiDRvZUjO/BQQ8HNTm14ZrBq5fROIVa9nvPj4/YgEjd
+BuIUrWvI4cmdS2hhSHmbzjy09Yam7+NoOvaD52yWl2HzXK1jG1h0AMjMy4kCAwEA
+AaOCAaswggGnMB8GA1UdIwQYMBaAFJnkQF9rFF4+Bdnd02NU/GK49wCsMB0GA1Ud
+DgQWBBTNvuqz1PYQ0wROjxAQNMxffuxyKzAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0T
+AQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0gBD8w
+PTA7BgsrBgEEAbIxAQICBzAsMCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LnBvc2l0
+aXZlc3NsLmNvbS9DUFMwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vUG9zaXRpdmVTU0xDQTIuY3JsMGwGCCsGAQUFBwEBBGAwXjA2Bggr
+BgEFBQcwAoYqaHR0cDovL2NydC5jb21vZG9jYS5jb20vUG9zaXRpdmVTU0xDQTIu
+Y3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wNQYDVR0R
+BC4wLIIScHVibGljLm9wZW5jcHUub3JnghZ3d3cucHVibGljLm9wZW5jcHUub3Jn
+MA0GCSqGSIb3DQEBBQUAA4IBAQCvcI2W9NO7141ngZafl5Zx473npOms02Hs+2rk
+BaAhlWSO8/7TN6Vq8lJKRa9FKQikteLcCVarK9vIyVOibMVQvxYTb7R44Tyy/C4m
+Ul2G+wDnEoaDxo8Up5NmuEf6/xgp+vtjZ7An/lPY5ZZrR6uHLlYlUTFxQyGvn8JL
+UqXxutDWi7hnZHOsmCUqyiWYTHRS1Agrn/e6bVKmjwtcEK8mjml5oNyGBlAawu/n
+KAm6sWviLUkNayrrtgfUnk+47zKPuIFPOa8vlCWk98tV8hqak34EftULJyf0IqcW
+rAV8nzZKhnOO8MCTyAGAcHAvniq2IrxMCm9M3jsVB4mdoF13
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIE5TCCA82gAwIBAgIQB28SRoFFnCjVSNaXxA4AGzANBgkqhkiG9w0BAQUFADBv
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
+ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
+eHRlcm5hbCBDQSBSb290MB4XDTEyMDIxNjAwMDAwMFoXDTIwMDUzMDEwNDgzOFow
+czELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxGTAXBgNV
+BAMTEFBvc2l0aXZlU1NMIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDo6jnjIqaqucQA0OeqZztDB71Pkuu8vgGjQK3g70QotdA6voBUF4V6a4Rs
+NjbloyTi/igBkLzX3Q+5K05IdwVpr95XMLHo+xoD9jxbUx6hAUlocnPWMytDqTcy
+Ug+uJ1YxMGCtyb1zLDnukNh1sCUhYHsqfwL9goUfdE+SNHNcHQCgsMDqmOK+ARRY
+FygiinddUCXNmmym5QzlqyjDsiCJ8AckHpXCLsDl6ez2PRIHSD3SwyNWQezT3zVL
+yOf2hgVSEEOajBd8i6q8eODwRTusgFX+KJPhChFo9FJXb/5IC1tdGmpnc5mCtJ5D
+YD7HWyoSbhruyzmuwzWdqLxdsC/DAgMBAAGjggF3MIIBczAfBgNVHSMEGDAWgBSt
+vZh6NLQm9/rEJlTvA73gJMtUGjAdBgNVHQ4EFgQUmeRAX2sUXj4F2d3TY1T8Yrj3
+AKwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEQYDVR0gBAow
+CDAGBgRVHSAAMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0
+LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDCBswYIKwYBBQUHAQEEgaYw
+gaMwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9BZGRUcnVz
+dEV4dGVybmFsQ0FSb290LnA3YzA5BggrBgEFBQcwAoYtaHR0cDovL2NydC51c2Vy
+dHJ1c3QuY29tL0FkZFRydXN0VVROU0dDQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRw
+Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQCcNuNOrvGK
+u2yXjI9LZ9Cf2ISqnyFfNaFbxCtjDei8d12nxDf9Sy2e6B1pocCEzNFti/OBy59L
+dLBJKjHoN0DrH9mXoxoR1Sanbg+61b4s/bSRZNy+OxlQDXqV8wQTqbtHD4tc0azC
+e3chUN1bq+70ptjUSlNrTa24yOfmUlhNQ0zCoiNPDsAgOa/fT0JbHtMJ9BgJWSrZ
+6EoYvzL7+i1ki4fKWyvouAt+vhcSxwOCKa9Yr4WEXT0K3yNRw82vEL+AaXeRCk/l
+uuGtm87fM04wO+mPZn+C+mv626PAcwDj1hKvTfIPWhRRH224hoFiB85ccsJP81cq
+cdnUl4XmGFO3
+-----END CERTIFICATE-----
+
+-----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-----
+
diff --git a/tests/keys/opencpu.org.cer b/tests/keys/opencpu.org.cer
new file mode 100644
index 0000000..893f972
Binary files /dev/null and b/tests/keys/opencpu.org.cer differ
diff --git a/tests/keys/signatures.txt b/tests/keys/signatures.txt
new file mode 100644
index 0000000..4797f09
--- /dev/null
+++ b/tests/keys/signatures.txt
@@ -0,0 +1,36 @@
+# From http://stackoverflow.com/a/18359743/318752
+
+openssl dgst -md5 -sign id_rsa -out message.sig.rsa.md5 message
+openssl dgst -md5 -verify id_rsa.pem -signature message.sig.rsa.md5 message
+
+
+openssl dgst -sha1 -sign id_rsa -out message.sig.rsa.sha1 message
+openssl dgst -sha1 -verify id_rsa.pem -signature message.sig.rsa.sha1 message
+
+openssl dgst -sha1 -sign id_dsa -out message.sig.dsa.sha1 message
+openssl dgst -sha1 -verify id_dsa.pem -signature message.sig.dsa.sha1 message
+
+openssl dgst -sha1 -sign id_ecdsa -out message.sig.ecdsa.sha1 message
+openssl dgst -sha1 -verify id_ecdsa.pem -signature message.sig.ecdsa.sha1 message
+
+openssl dgst -sha1 -sign id_ecdsa384 -out message.sig.ecdsa384.sha1 message
+openssl dgst -sha1 -verify id_ecdsa384.pem -signature message.sig.ecdsa384.sha1 message
+
+openssl dgst -sha1 -sign id_ecdsa521 -out message.sig.ecdsa521.sha1 message
+openssl dgst -sha1 -verify id_ecdsa521.pem -signature message.sig.ecdsa521.sha1 message
+
+
+openssl dgst -sha256 -sign id_rsa -out message.sig.rsa.sha256 message
+openssl dgst -sha256 -verify id_rsa.pem -signature message.sig.rsa.sha256 message
+
+openssl dgst -sha256 -sign id_dsa -out message.sig.dsa.sha256 message
+openssl dgst -sha256 -verify id_dsa.pem -signature message.sig.dsa.sha256 message
+
+openssl dgst -sha256 -sign id_ecdsa -out message.sig.ecdsa.sha256 message
+openssl dgst -sha256 -verify id_ecdsa.pem -signature message.sig.ecdsa.sha256 message
+
+openssl dgst -sha256 -sign id_ecdsa384 -out message.sig.ecdsa384.sha256 message
+openssl dgst -sha256 -verify id_ecdsa384.pem -signature message.sig.ecdsa384.sha256 message
+
+openssl dgst -sha256 -sign id_ecdsa521 -out message.sig.ecdsa521.sha256 message
+openssl dgst -sha256 -verify id_ecdsa521.pem -signature message.sig.ecdsa521.sha256 message
diff --git a/tests/keys/testmd5.sig b/tests/keys/testmd5.sig
new file mode 100644
index 0000000..f2ad846
Binary files /dev/null and b/tests/keys/testmd5.sig differ
diff --git a/tests/keys/testsha1.sig b/tests/keys/testsha1.sig
new file mode 100644
index 0000000..73434db
--- /dev/null
+++ b/tests/keys/testsha1.sig
@@ -0,0 +1 @@
+h�SVp
�'�S�+�� �״��=
�SBV��=��ok�o��B��^��;��7��1���)O���J��d��f-�,���ԨOBlO^`�3�
q�v���h0ZX�H��jp��CpHd_:ɚ��_���&l��xk�"XV��1
yl�tyV�<c7y�7�9Ĺ���]��ǘ�i�
`Q�������͂��H�%GL���
0]�f�Q;��0myN#�h0�k�[F8��{�rq\}fW
�@L��%���S�
\ No newline at end of file
diff --git a/tests/testthat.R b/tests/testthat.R
new file mode 100644
index 0000000..f9c859d
--- /dev/null
+++ b/tests/testthat.R
@@ -0,0 +1,4 @@
+library(testthat)
+library(openssl)
+
+test_check("openssl")
diff --git a/tests/testthat/test_bignum.R b/tests/testthat/test_bignum.R
new file mode 100644
index 0000000..4331538
--- /dev/null
+++ b/tests/testthat/test_bignum.R
@@ -0,0 +1,42 @@
+context("Bignum")
+
+test_that("Basic bignum math", {
+ # Regular numbers
+ x1 <- 123
+ y1 <- 456
+
+ # Bignum numbers
+ x2 <- bignum(123)
+ y2 <- bignum(456)
+
+ expect_true(x1 == x2)
+ expect_true(y1 == y2)
+ expect_true(x2 != y2)
+ expect_true(x2 < y2)
+ expect_true(x2 <= y2)
+ expect_false(x2 > y2)
+ expect_false(x2 >= y2)
+ expect_false(x1 == y2)
+ expect_true(x1+y1 == x2+y2)
+ expect_true(y1-x1 == y2-x2)
+ expect_true(x1*y1 == x2*y2)
+ expect_true(y2-y2 == 0)
+ expect_true(y2 %% x2 == y1 %% x1)
+ expect_true(y2 %/% x2 == y1 %/% x1)
+ expect_true(x2 %% y2 == x1 %% y1)
+ expect_error(x2-y2, "")
+ expect_error(x2/y2, "integer")
+})
+
+test_that("Bignum arithmetic", {
+ x <- bignum(123L)
+ y <- bignum("123456789123456789")
+ z <- bignum("D41D8CD98F00B204E9800998ECF8427E", hex = TRUE)
+
+ # Basic arithmetic
+ div <- z %/% y
+ mod <- z %% y
+ z2 <- div * y + mod
+ expect_equal(z2, z)
+ expect_true(div < z)
+})
diff --git a/tests/testthat/test_cert.R b/tests/testthat/test_cert.R
new file mode 100644
index 0000000..6a44e68
--- /dev/null
+++ b/tests/testthat/test_cert.R
@@ -0,0 +1,10 @@
+context("Read certificates")
+
+test_that("Roundtrip pem/der formats", {
+ cert <- read_cert("../keys/opencpu.org.cer", der = TRUE)
+ expect_equal(cert, read_cert(write_pem(cert)))
+ expect_equal(cert, read_cert(write_pem(cert, tempfile())))
+ expect_equal(cert, read_cert(write_der(cert), der = TRUE))
+ expect_equal(cert, read_cert(write_der(cert, tempfile()), der = TRUE))
+})
+
diff --git a/tests/testthat/test_encrypt.R b/tests/testthat/test_encrypt.R
new file mode 100644
index 0000000..44eb2b8
--- /dev/null
+++ b/tests/testthat/test_encrypt.R
@@ -0,0 +1,31 @@
+context("Test RSA encryption")
+
+test_that("rsa decrypt", {
+ key <- read_key("../keys/id_rsa")
+ msg <- readBin("../keys/message", raw(), 1000)
+ ct <- readBin("../keys/message.rsa.crypt", raw(), 1000)
+ expect_equal(msg ,rsa_decrypt(ct, key))
+})
+
+test_that("encrypt with various rsa key sizes", {
+ for(size in c(512, 1024, 2048, 4096)){
+ key <- rsa_keygen(size)
+ pubkey <- as.list(key)$pubkey
+ msg <- rand_bytes(size / 10)
+ ct <- rsa_encrypt(msg, pubkey)
+ expect_equal(msg, rsa_decrypt(ct, key))
+ bigmsg <- rand_bytes(size / 8)
+ expect_error(rsa_encrypt(bigmsg, pubkey), "too large")
+ }
+})
+
+test_that("envelopes with various rsa key sizes", {
+ for(size in c(512, 1024, 2048, 4096)){
+ key <- rsa_keygen(size)
+ pubkey <- as.list(key)$pubkey
+ msg <- serialize(iris, NULL)
+ out <- encrypt_envelope(msg, pubkey)
+ orig <- decrypt_envelope(out$data, out$iv, out$session, key)
+ expect_equal(msg, orig)
+ }
+})
diff --git a/tests/testthat/test_hash.R b/tests/testthat/test_hash.R
new file mode 100644
index 0000000..e70f8e1
--- /dev/null
+++ b/tests/testthat/test_hash.R
@@ -0,0 +1,28 @@
+context("Test AES encryption")
+
+test_that("AES-128 encrypts and decrypts for all lengths", {
+ key <- md5(charToRaw("supersecret"))
+ for(n in 0:100){
+ x <- rand_bytes(n)
+ y <- aes_cbc_encrypt(x, key)
+ x2 <- aes_cbc_decrypt(y, key)
+ expect_identical(x, x2)
+ }
+})
+
+test_that("AES-256 encrypts and decrypts for all lengths", {
+ key <- sha256(charToRaw("supersecret"))
+ for(n in 0:100){
+ x <- rand_bytes(n)
+ y <- aes_cbc_encrypt(x, key)
+ x2 <- aes_cbc_decrypt(y, key)
+ expect_equal(x, x2)
+ }
+})
+
+test_that("File API", {
+ file <- system.file("DESCRIPTION")
+ key <- rand_bytes(32)
+ ct <- aes_cbc_encrypt(file, key)
+ expect_equal(aes_cbc_decrypt(ct, key), readBin(file, raw(), 1e5))
+})
diff --git a/tests/testthat/test_hash_error.R b/tests/testthat/test_hash_error.R
new file mode 100644
index 0000000..3a8cea7
--- /dev/null
+++ b/tests/testthat/test_hash_error.R
@@ -0,0 +1,13 @@
+context("Test the error handlers for hash functions")
+
+test_that("non-vector inputs are detected", {
+
+ expect_that(md5(list(c("foo","bar"),"baz")), throws_error(regexp = "must be raw or character vector", fixed = TRUE))
+
+})
+
+test_that("non-character inputs are detected", {
+
+ expect_that(md5(12), throws_error(regexp = "must be raw or character vector", fixed = TRUE))
+
+})
diff --git a/tests/testthat/test_hash_output_length.R b/tests/testthat/test_hash_output_length.R
new file mode 100644
index 0000000..0dbfaa7
--- /dev/null
+++ b/tests/testthat/test_hash_output_length.R
@@ -0,0 +1,52 @@
+context("Test the length of the output of various algorithms.")
+
+text <- "foo"
+bin <- charToRaw(text)
+
+test_that("MD4 outputs a 32-character hash", {
+
+ expect_that(nchar(md4(text)), equals(32))
+ expect_that(length(md4(bin)), equals(16))
+ expect_identical(as.character(md4(bin)), md4(text))
+
+})
+
+test_that("MD5 outputs a 32-character hash", {
+
+ expect_that(nchar(md5(text)), equals(32))
+ expect_that(length(md5(bin)), equals(16))
+ expect_identical(as.character(md5(bin)), md5(text))
+
+})
+
+test_that("ripemd160 outputs a 40-character hash", {
+
+ expect_that(nchar(ripemd160(text)), equals(40))
+ expect_that(length(ripemd160(bin)), equals(20))
+ expect_identical(as.character(ripemd160(bin)), ripemd160(text))
+
+})
+
+test_that("SHA1 outputs a 40-character hash", {
+
+ expect_that(nchar(sha1(text)), equals(40))
+ expect_that(length(sha1(bin)), equals(20))
+ expect_identical(as.character(sha1(bin)), sha1(text))
+
+})
+
+test_that("SHA256 outputs a 64-character hash", {
+
+ expect_that(nchar(sha256(text)), equals(64))
+ expect_that(length(sha256(bin)), equals(32))
+ expect_identical(as.character(sha256(bin)), sha256(text))
+
+})
+
+test_that("SHA512 outputs a 128-character hash", {
+
+ expect_that(nchar(sha512(text)), equals(128))
+ expect_that(length(sha512(bin)), equals(64))
+ expect_identical(as.character(sha512(bin)), sha512(text))
+
+})
diff --git a/tests/testthat/test_hash_output_value.R b/tests/testthat/test_hash_output_value.R
new file mode 100644
index 0000000..a5a4b34
--- /dev/null
+++ b/tests/testthat/test_hash_output_value.R
@@ -0,0 +1,43 @@
+context("Test hash/hmac functions")
+
+test_that("Hash functions match openssl command line tool", {
+
+ # COMPARE: echo -n "foo" | openssl dgst -md4
+ expect_that(unclass(md4("foo")), equals("0ac6700c491d70fb8650940b1ca1e4b2"))
+ expect_that(unclass(md5("foo")), equals("acbd18db4cc2f85cedef654fccc4a4d8"))
+ expect_that(unclass(ripemd160("foo")), equals("42cfa211018ea492fdee45ac637b7972a0ad6873"))
+ expect_that(unclass(sha1("foo")), equals("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"))
+ expect_that(unclass(sha256("foo")), equals("2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"))
+ expect_that(unclass(sha512("foo")), equals("f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7"))
+})
+
+test_that("HMAC functions match openssl command line tool", {
+
+ # #COMPARE: echo -n "foo" | openssl dgst -md4 -hmac "secret"
+ expect_that(unclass(md4("foo", key = "secret")), equals("93e81ded7aec4ec0d73a97bb4792742a"))
+ expect_that(unclass(md5("foo", key = "secret")), equals("ba19fbc606a960051b60244e9a5ed3d2"))
+ expect_that(unclass(ripemd160("foo", key = "secret")), equals("a87093c26e44fdfa04e142e59710daa94556a5ed"))
+ expect_that(unclass(sha1("foo", key = "secret")), equals("9baed91be7f58b57c824b60da7cb262b2ecafbd2"))
+ expect_that(unclass(sha256("foo", key = "secret")), equals("773ba44693c7553d6ee20f61ea5d2757a9a4f4a44d2841ae4e95b52e4cd62db4"))
+ expect_that(unclass(sha512("foo", key = "secret")), equals("82df7103de8d82de45e01c45fe642b5d13c6c2b47decafebc009431c665c6fa5f3d1af4e978ea1bde91426622073ebeac61a3461efd467e0971c788bc8ebdbbe"))
+})
+
+test_that("Connection interface matches raw interface", {
+ mydata <- serialize(iris, NULL)
+ saveRDS(iris, tmp <- tempfile())
+ expect_equal(md5(mydata), md5(file(tmp)))
+ expect_equal(sha1(mydata), sha1(file(tmp)))
+ expect_equal(sha256(mydata), sha256(file(tmp)))
+ expect_equal(md5(mydata, key = "secret"), md5(file(tmp), key = "secret"))
+ expect_equal(sha1(mydata, key = "secret"), sha1(file(tmp), key = "secret"))
+ expect_equal(sha256(mydata, key = "secret"), sha256(file(tmp), key = "secret"))
+})
+
+test_that("Connection interface matches string interface", {
+ expect_equal(md5(charToRaw("foo")), md5(textConnection("foo")))
+ expect_equal(sha1(charToRaw("foo")), sha1(textConnection("foo")))
+ expect_equal(sha256(charToRaw("foo")), sha256(textConnection("foo")))
+ expect_equal(md5(charToRaw("foo"), key = "secret"), md5(textConnection("foo"), key = "secret"))
+ expect_equal(sha1(charToRaw("foo"), key = "secret"), sha1(textConnection("foo"), key = "secret"))
+ expect_equal(sha256(charToRaw("foo"), key = "secret"), sha256(textConnection("foo"), key = "secret"))
+})
diff --git a/tests/testthat/test_keys_dsa.R b/tests/testthat/test_keys_dsa.R
new file mode 100644
index 0000000..eca97ce
--- /dev/null
+++ b/tests/testthat/test_keys_dsa.R
@@ -0,0 +1,83 @@
+context("Test DSA formats")
+
+# Read secret key and public key
+sk1 <- read_key("../keys/id_dsa")
+pk1 <- read_pubkey("../keys/id_dsa.pub")
+
+test_that("reading protected keys", {
+ sk2 <- read_key("../keys/id_dsa.pw", password = "test")
+ expect_equal(sk1, sk2)
+ expect_error(read_key("../keys/id_dsa.pw", password = ""), "bad password")
+})
+
+test_that("reading public key formats", {
+ pk2 <- read_pubkey("../keys/id_dsa.pem")
+ pk3 <- read_pubkey("../keys/id_dsa.pub")
+ pk4 <- as.list(sk1)$pubkey
+ expect_equal(pk1, pk2)
+ expect_equal(pk1, pk3)
+ expect_equal(pk1, pk4)
+})
+
+test_that("pubkey ssh fingerprint", {
+ fp <- paste(as.list(pk1)$fingerprint, collapse = "")
+ expect_equal(fp, "6c42ea8454e549b855cadd7fc86609ca")
+ pk5 <- read_pubkey(readLines("../keys/authorized_keys")[1])
+ expect_equal(pk1, pk5)
+ pk6 <- read_pubkey(write_ssh(pk1))
+ expect_equal(pk1, pk6)
+})
+
+test_that("signatures", {
+ # DSA does not support MD5
+ msg <- readBin("../keys/message", raw(), 100)
+
+ # SHA1 signature
+ sig <- readBin("../keys/message.sig.dsa.sha1", raw(), 1000)
+ expect_true(signature_verify(msg, sig, sha1, pk1))
+
+ sig <- signature_create(msg, sha1, sk1)
+ expect_true(signature_verify(msg, sig, sha1, pk1))
+
+ # SHA256 signature
+ sig <- readBin("../keys/message.sig.dsa.sha256", raw(), 1000)
+ expect_true(signature_verify(msg, sig, sha256, pk1))
+
+ sig <- signature_create(msg, sha256, sk1)
+ expect_true(signature_verify(msg, sig, sha256, pk1))
+})
+
+test_that("roundtrip pem format", {
+ expect_equal(pk1, read_pubkey(write_pem(pk1)))
+ expect_equal(sk1, read_key(write_pem(sk1, password = NULL)))
+ expect_equal(pk1, read_pubkey(write_pem(pk1, tempfile())))
+ expect_equal(sk1, read_key(write_pem(sk1, tempfile(), password = NULL)))
+})
+
+test_that("roundtrip der format", {
+ expect_equal(pk1, read_pubkey(write_der(pk1), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1), der = TRUE))
+ expect_equal(pk1, read_pubkey(write_der(pk1, tempfile()), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1, tempfile()), der = TRUE))
+})
+
+test_that("signature path interface", {
+ sig <- signature_create("../keys/message", sha256, "../keys/id_dsa")
+ writeBin(sig, tmp <- tempfile())
+ expect_true(signature_verify("../keys/message", tmp, sha256, "../keys/id_dsa.pub"))
+})
+
+test_that("dsa_keygen works", {
+ key <- dsa_keygen(1024)
+ expect_is(key, "dsa")
+ expect_equal(as.list(key)$size, 1024)
+ rm(key)
+
+ key <- dsa_keygen(2048)
+ expect_is(key, "dsa")
+ expect_equal(as.list(key)$size, 2048)
+ rm(key)
+})
+
+# Cleanup
+rm(sk1, pk1)
diff --git a/tests/testthat/test_keys_ecdsa.R b/tests/testthat/test_keys_ecdsa.R
new file mode 100644
index 0000000..a803d3b
--- /dev/null
+++ b/tests/testthat/test_keys_ecdsa.R
@@ -0,0 +1,85 @@
+context("Test ECDSA 256 formats")
+
+if(openssl_config()$ec){
+
+# Read secret key and public key
+sk1 <- read_key("../keys/id_ecdsa")
+pk1 <- read_pubkey("../keys/id_ecdsa.pub")
+
+test_that("reading protected keys", {
+ sk2 <- read_key("../keys/id_ecdsa.pw", password = "test")
+ expect_equal(sk1, sk2)
+ expect_error(read_key("../keys/id_ecdsa.pw", password = NULL), "bad password")
+})
+
+test_that("reading public key formats", {
+ pk2 <- read_pubkey("../keys/id_ecdsa.pem")
+ pk3 <- read_pubkey("../keys/id_ecdsa.pub")
+ pk4 <- as.list(sk1)$pubkey
+ expect_equal(pk1, pk2)
+ expect_equal(pk1, pk3)
+ expect_equal(pk1, pk4)
+})
+
+test_that("pubkey ssh fingerprint", {
+ fp <- paste(as.list(pk1)$fingerprint, collapse = "")
+ expect_equal(fp, "100b0d5f53a36e63dc42085552cdc340")
+ pk5 <- read_pubkey(readLines("../keys/authorized_keys")[3])
+ expect_equal(pk1, pk5)
+ pk6 <- read_pubkey(write_ssh(pk1))
+ expect_equal(pk1, pk6)
+})
+
+test_that("signatures", {
+ # ecdsa does not support MD5
+ msg <- readBin("../keys/message", raw(), 100)
+
+ # SHA1 signature
+ sig <- readBin("../keys/message.sig.ecdsa.sha1", raw(), 1000)
+ expect_true(signature_verify(msg, sig, sha1, pk1))
+
+ sig <- signature_create(msg, sha1, sk1)
+ expect_true(signature_verify(msg, sig, sha1, pk1))
+
+ # SHA256 signature
+ sig <- readBin("../keys/message.sig.ecdsa.sha256", raw(), 1000)
+ expect_true(signature_verify(msg, sig, sha256, pk1))
+
+ sig <- signature_create(msg, sha256, sk1)
+ expect_true(signature_verify(msg, sig, sha256, pk1))
+})
+
+test_that("roundtrip pem format", {
+ expect_equal(pk1, read_pubkey(write_pem(pk1)))
+ expect_equal(sk1, read_key(write_pem(sk1, password = NULL)))
+ expect_equal(pk1, read_pubkey(write_pem(pk1, tempfile())))
+ expect_equal(sk1, read_key(write_pem(sk1, tempfile(), password = NULL)))
+})
+
+test_that("roundtrip der format", {
+ expect_equal(pk1, read_pubkey(write_der(pk1), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1), der = TRUE))
+ expect_equal(pk1, read_pubkey(write_der(pk1, tempfile()), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1, tempfile()), der = TRUE))
+})
+
+test_that("signature path interface", {
+ sig <- signature_create("../keys/message", sha256, "../keys/id_ecdsa")
+ writeBin(sig, tmp <- tempfile())
+ expect_true(signature_verify("../keys/message", tmp, sha256, "../keys/id_ecdsa.pub"))
+})
+
+test_that("ec_keygen works", {
+ key <- ec_keygen("P-256")
+ expect_equal(as.list(key)$size, 256)
+ expect_equal(as.list(key)$data$curve, "P-256")
+ rm(key)
+})
+
+# Cleanup
+rm(sk1, pk1)
+
+} else {
+ cat("ec not supported")
+}
+
diff --git a/tests/testthat/test_keys_ecdsa384.R b/tests/testthat/test_keys_ecdsa384.R
new file mode 100644
index 0000000..207a6ae
--- /dev/null
+++ b/tests/testthat/test_keys_ecdsa384.R
@@ -0,0 +1,80 @@
+context("Test ECDSA 384 formats")
+
+if(openssl_config()$ec){
+
+# Read secret key and public key
+sk1 <- read_key("../keys/id_ecdsa384")
+pk1 <- read_pubkey("../keys/id_ecdsa384.pub")
+
+test_that("reading protected keys", {
+ sk2 <- read_key("../keys/id_ecdsa384.pw", password = "test")
+ expect_equal(sk1, sk2)
+ expect_error(read_key("../keys/id_ecdsa384.pw", password = NULL), "bad password")
+})
+
+test_that("reading public key formats", {
+ pk2 <- read_pubkey("../keys/id_ecdsa384.pem")
+ pk3 <- read_pubkey("../keys/id_ecdsa384.pub")
+ pk4 <- as.list(sk1)$pubkey
+ expect_equal(pk1, pk2)
+ expect_equal(pk1, pk3)
+ expect_equal(pk1, pk4)
+})
+
+test_that("pubkey ssh fingerprint", {
+ fp <- paste(as.list(pk1)$fingerprint, collapse = "")
+ expect_equal(fp, "8cf3736c4a28cf2bd63bbf3278d00630")
+})
+
+test_that("signatures", {
+ # ecdsa384 does not support MD5
+ msg <- readBin("../keys/message", raw(), 100)
+
+ # SHA1 signature
+ sig <- readBin("../keys/message.sig.ecdsa384.sha1", raw(), 1000)
+ expect_true(signature_verify(msg, sig, sha1, pk1))
+
+ sig <- signature_create(msg, sha1, sk1)
+ expect_true(signature_verify(msg, sig, sha1, pk1))
+
+ # SHA256 signature
+ sig <- readBin("../keys/message.sig.ecdsa384.sha256", raw(), 1000)
+ expect_true(signature_verify(msg, sig, sha256, pk1))
+
+ sig <- signature_create(msg, sha256, sk1)
+ expect_true(signature_verify(msg, sig, sha256, pk1))
+})
+
+test_that("roundtrip pem format", {
+ expect_equal(pk1, read_pubkey(write_pem(pk1)))
+ expect_equal(sk1, read_key(write_pem(sk1, password = NULL)))
+ expect_equal(pk1, read_pubkey(write_pem(pk1, tempfile())))
+ expect_equal(sk1, read_key(write_pem(sk1, tempfile(), password = NULL)))
+})
+
+test_that("roundtrip der format", {
+ expect_equal(pk1, read_pubkey(write_der(pk1), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1), der = TRUE))
+ expect_equal(pk1, read_pubkey(write_der(pk1, tempfile()), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1, tempfile()), der = TRUE))
+})
+
+test_that("signature path interface", {
+ sig <- signature_create("../keys/message", sha256, "../keys/id_ecdsa384")
+ writeBin(sig, tmp <- tempfile())
+ expect_true(signature_verify("../keys/message", tmp, sha256, "../keys/id_ecdsa384.pub"))
+})
+
+test_that("ec_keygen works", {
+ key <- ec_keygen("P-384")
+ expect_equal(as.list(key)$size, 384)
+ expect_equal(as.list(key)$data$curve, "P-384")
+ rm(key)
+})
+
+# Cleanup
+rm(sk1, pk1)
+
+} else {
+ cat("ec not supported")
+}
diff --git a/tests/testthat/test_keys_ecdsa521.R b/tests/testthat/test_keys_ecdsa521.R
new file mode 100644
index 0000000..b9df803
--- /dev/null
+++ b/tests/testthat/test_keys_ecdsa521.R
@@ -0,0 +1,81 @@
+context("Test ECDSA 521 formats")
+
+if(openssl_config()$ec){
+
+# Read secret key and public key
+sk1 <- read_key("../keys/id_ecdsa521")
+pk1 <- read_pubkey("../keys/id_ecdsa521.pub")
+
+test_that("reading protected keys", {
+ sk2 <- read_key("../keys/id_ecdsa521.pw", password = "test")
+ expect_equal(sk1, sk2)
+ expect_error(read_key("../keys/id_ecdsa521.pw", password = NULL), "bad password")
+})
+
+test_that("reading public key formats", {
+ pk2 <- read_pubkey("../keys/id_ecdsa521.pem")
+ pk3 <- read_pubkey("../keys/id_ecdsa521.pub")
+ pk4 <- as.list(sk1)$pubkey
+ expect_equal(pk1, pk2)
+ expect_equal(pk1, pk3)
+ expect_equal(pk1, pk4)
+})
+
+test_that("pubkey ssh fingerprint", {
+ fp <- paste(as.list(pk1)$fingerprint, collapse = "")
+ expect_equal(fp, "904d4c50be879bf0557af96b9935f1c2")
+})
+
+test_that("signatures", {
+ # ecdsa521 does not support MD5
+ msg <- readBin("../keys/message", raw(), 100)
+
+ # SHA1 signature
+ sig <- readBin("../keys/message.sig.ecdsa521.sha1", raw(), 1000)
+ expect_true(signature_verify(msg, sig, sha1, pk1))
+
+ sig <- signature_create(msg, sha1, sk1)
+ expect_true(signature_verify(msg, sig, sha1, pk1))
+
+ # SHA256 signature
+ sig <- readBin("../keys/message.sig.ecdsa521.sha256", raw(), 1000)
+ expect_true(signature_verify(msg, sig, sha256, pk1))
+
+ sig <- signature_create(msg, sha256, sk1)
+ expect_true(signature_verify(msg, sig, sha256, pk1))
+})
+
+test_that("roundtrip pem format", {
+ expect_equal(pk1, read_pubkey(write_pem(pk1)))
+ expect_equal(sk1, read_key(write_pem(sk1, password = NULL)))
+ expect_equal(pk1, read_pubkey(write_pem(pk1, tempfile())))
+ expect_equal(sk1, read_key(write_pem(sk1, tempfile(), password = NULL)))
+})
+
+test_that("roundtrip der format", {
+ expect_equal(pk1, read_pubkey(write_der(pk1), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1), der = TRUE))
+ expect_equal(pk1, read_pubkey(write_der(pk1, tempfile()), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1, tempfile()), der = TRUE))
+})
+
+test_that("signature path interface", {
+ sig <- signature_create("../keys/message", sha256, "../keys/id_ecdsa521")
+ writeBin(sig, tmp <- tempfile())
+ expect_true(signature_verify("../keys/message", tmp, sha256, "../keys/id_ecdsa521.pub"))
+})
+
+test_that("ec_keygen works", {
+ key <- ec_keygen("P-521")
+ expect_equal(as.list(key)$size, 521)
+ expect_equal(as.list(key)$data$curve, "P-521")
+ rm(key)
+})
+
+# Cleanup
+rm(sk1, pk1)
+
+} else {
+ cat("ec not supported")
+}
+
diff --git a/tests/testthat/test_keys_rsa.R b/tests/testthat/test_keys_rsa.R
new file mode 100644
index 0000000..07f5fe6
--- /dev/null
+++ b/tests/testthat/test_keys_rsa.R
@@ -0,0 +1,86 @@
+context("Test RSA formats")
+
+# Read secret key and public key
+sk1 <- read_key("../keys/id_rsa")
+pk1 <- read_pubkey("../keys/id_rsa.pub")
+
+test_that("reading protected keys", {
+ sk2 <- read_key("../keys/id_rsa.pw", password = "test")
+ expect_equal(sk1, sk2)
+ expect_error(read_key("../keys/id_rsa.pw", password = ""), "bad password")
+})
+
+test_that("reading public key formats", {
+ pk2 <- read_pubkey("../keys/id_rsa.pem")
+ pk3 <- read_pubkey("../keys/id_rsa.pub")
+ pk4 <- read_pubkey("../keys/id_rsa.sshpem1")
+ pk5 <- read_pubkey("../keys/id_rsa.sshpem2")
+ pk6 <- as.list(sk1)$pubkey
+ expect_equal(pk1, pk2)
+ expect_equal(pk1, pk3)
+ expect_equal(pk1, pk4)
+ expect_equal(pk1, pk5)
+ expect_equal(pk1, pk6)
+})
+
+test_that("pubkey ssh fingerprint", {
+ fp <- paste(as.list(pk1)$fingerprint, collapse = "")
+ expect_equal(fp, "3ad46117a06192f13e55beb3cd4cfa6f")
+ pk7 <- read_pubkey(readLines("../keys/authorized_keys")[2])
+ expect_equal(pk1, pk7)
+ pk8 <- read_pubkey(write_ssh(pk1))
+ expect_equal(pk1, pk8)
+})
+
+test_that("signatures", {
+ # MD5 signature
+ msg <- readBin("../keys/message", raw(), 100)
+ sig <- readBin("../keys/message.sig.rsa.md5", raw(), 1000)
+ expect_equal(signature_create(msg, md5, sk1), sig)
+ expect_true(signature_verify(msg, sig, md5, pk1))
+
+ # SHA1 signature
+ sig <- readBin("../keys/message.sig.rsa.sha1", raw(), 1000)
+ expect_equal(signature_create(msg, sha1, sk1), sig)
+ expect_true(signature_verify(msg, sig, sha1, pk1))
+
+ # SHA256 signature
+ sig <- readBin("../keys/message.sig.rsa.sha256", raw(), 1000)
+ expect_equal(signature_create(msg, sha256, sk1), sig)
+ expect_true(signature_verify(msg, sig, sha256, pk1))
+})
+
+test_that("roundtrip pem format", {
+ expect_equal(pk1, read_pubkey(write_pem(pk1)))
+ expect_equal(sk1, read_key(write_pem(sk1, password = NULL)))
+ expect_equal(pk1, read_pubkey(write_pem(pk1, tempfile())))
+ expect_equal(sk1, read_key(write_pem(sk1, tempfile(), password = NULL)))
+})
+
+test_that("roundtrip der format", {
+ expect_equal(pk1, read_pubkey(write_der(pk1), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1), der = TRUE))
+ expect_equal(pk1, read_pubkey(write_der(pk1, tempfile()), der = TRUE))
+ expect_equal(sk1, read_key(write_der(sk1, tempfile()), der = TRUE))
+})
+
+test_that("signature path interface", {
+ sig <- signature_create("../keys/message", sha256, "../keys/id_rsa")
+ writeBin(sig, tmp <- tempfile())
+ expect_true(signature_verify("../keys/message", tmp, sha256, "../keys/id_rsa.pub"))
+})
+
+test_that("rsa_keygen works", {
+ key <- rsa_keygen(1024)
+ expect_is(key, "rsa")
+ expect_equal(as.list(key)$size, 1024)
+ rm(key)
+
+ key <- rsa_keygen(2048)
+ expect_is(key, "rsa")
+ expect_equal(as.list(key)$size, 2048)
+ rm(key)
+})
+
+# Cleanup
+rm(sk1, pk1)
diff --git a/tests/testthat/test_my_key.R b/tests/testthat/test_my_key.R
new file mode 100644
index 0000000..594570f
--- /dev/null
+++ b/tests/testthat/test_my_key.R
@@ -0,0 +1,27 @@
+context("Test default user key")
+
+# Read secret key and public key
+
+test_that("reading protected keys", {
+ sk1 <- rsa_keygen()
+ pk1 <- as.list(sk1)$pubkey
+ tmp_key <- tempfile()
+ tmp_pubkey <- tempfile()
+ write_pem(sk1, tmp_key, password = NULL)
+ write_pem(pk1, tmp_pubkey)
+
+ # Test default private key
+ Sys.setenv("USER_KEY" = tmp_key)
+ expect_equal(sk1, my_key())
+ expect_equal(pk1, my_pubkey())
+
+ # Test default pubkey key
+ Sys.setenv("USER_PUBKEY" = tmp_pubkey)
+ expect_equal(pk1, my_pubkey())
+
+ Sys.unsetenv("USER_KEY")
+ expect_equal(pk1, my_pubkey())
+
+ # Clean up to prevent side effects
+ Sys.unsetenv("USER_PUBKEY")
+})
diff --git a/tests/testthat/test_pkcs.R b/tests/testthat/test_pkcs.R
new file mode 100644
index 0000000..2a58382
--- /dev/null
+++ b/tests/testthat/test_pkcs.R
@@ -0,0 +1,73 @@
+context("Test p12 / p7b format")
+
+test_that("reading p12 certificates", {
+ p1 <- read_p12("../google.dk/wildcard-google.dk-chain.p12")
+
+ expect_error(read_p12("../google.dk/wildcard-google.dk-chain-password.p12", password = ""), "password")
+ p2 <- read_p12("../google.dk/wildcard-google.dk-chain-password.p12", password = "password")
+ expect_identical(p1, p2)
+
+ bundle <- read_cert_bundle("../google.dk/wildcard-google.dk-chain.pem")
+ expect_identical(p1$ca, bundle)
+
+ leaf <- read_cert("../google.dk/wildcard-google.dk-leaf.crt", der = TRUE)
+ expect_identical(leaf, bundle[[1]])
+
+})
+
+test_that("reading p12 keys", {
+ expect_error(read_p12("../certigo/example-root.p12", password = ""), "password")
+ b1 <- read_p12("../certigo/example-root.p12", password = "password")
+ c1 <- read_cert("../certigo/example-root.crt")
+ p7 <- read_p7b("../certigo/example-root.p7b")
+ expect_identical(b1$cert, c1)
+ expect_identical(c1, p7[[1]])
+ expect_identical(b1$cert$pubkey, b1$key$pubkey)
+
+ expect_error(read_p12("../certigo/example-leaf.p12", password = ""), "password")
+ b2<- read_p12("../certigo/example-leaf.p12", password = "password")
+ c2 <- read_cert("../certigo/example-leaf.crt")
+ p7 <- read_p7b("../certigo/example-leaf.p7b")
+ expect_identical(b2$cert, c2)
+ expect_identical(c2, p7[[1]])
+ expect_identical(b2$cert$pubkey, b2$key$pubkey)
+
+ if(isTRUE(openssl_config()$ec)){
+ expect_error(read_p12("../certigo/example-elliptic-sha1.p12", password = ""), "password")
+ b3 <- read_p12("../certigo/example-elliptic-sha1.p12", password = "password")
+ c3 <- read_cert("../certigo/example-elliptic-sha1.crt")
+ p7 <- read_p7b("../certigo/example-elliptic-sha1.p7b")
+ k3 <- read_key("../certigo/example-elliptic-sha1.key")
+ expect_identical(b3$cert, c3)
+ expect_identical(c3, p7[[1]])
+ expect_identical(b3$key, k3)
+ expect_identical(b3$cert$pubkey, b3$key$pubkey)
+ }
+})
+
+test_that("roundtrip p12 key and cert", {
+ if(isTRUE(openssl_config()$ec)){
+ b3 <- read_p12("../certigo/example-elliptic-sha1.p12", password = "password")
+ c3 <- read_cert("../certigo/example-elliptic-sha1.crt")
+ k3 <- read_key("../certigo/example-elliptic-sha1.key")
+ buf <- write_p12(key = k3, cert = c3)
+ expect_identical(b3, read_p12(buf))
+ }
+})
+
+test_that("writing big p12 bundle", {
+ if(isTRUE(openssl_config()$ec)){
+ bundle = ca_bundle()
+
+ #Roundtrip via p12
+ buf <- write_p12(ca = bundle, password = 'test')
+ out <- read_p12(buf, password = 'test')
+ expect_equal(bundle, out$ca)
+
+ # Roundtrip via p7b
+ buf <- write_p7b(ca = bundle)
+ out <- read_p7b(buf)
+ expect_equal(bundle, out)
+
+ }
+})
diff --git a/tests/testthat/test_rand_error.R b/tests/testthat/test_rand_error.R
new file mode 100644
index 0000000..80196bb
--- /dev/null
+++ b/tests/testthat/test_rand_error.R
@@ -0,0 +1,7 @@
+context("Test the error handlers for rand_* functions")
+
+test_that("rand_bytes detects non-numeric arguments", {
+
+ expect_that(rand_bytes("turnip"), throws_error(regexp = "numeric", fixed = TRUE))
+
+})
diff --git a/tests/testthat/test_salting.R b/tests/testthat/test_salting.R
new file mode 100644
index 0000000..c8bf017
--- /dev/null
+++ b/tests/testthat/test_salting.R
@@ -0,0 +1,73 @@
+context("Test salting works with various algorithms")
+
+test_that("MD4 salts single values", {
+ expect_false(md4("foo") == md4("foo","bar"))
+})
+
+test_that("MD4 salts multiple values", {
+ salted_hashes <- md4(c("foo","bar"), "baz")
+ unsalted_hashes <- md4(c("foo","bar"))
+ expect_that(length(salted_hashes), equals(2))
+ expect_false(salted_hashes[1] == unsalted_hashes[1])
+ expect_false(salted_hashes[2] == unsalted_hashes[2])
+})
+
+test_that("MD5 salts single values", {
+ expect_false(md5("foo") == md5("foo","bar"))
+})
+
+test_that("MD5 salts multiple values", {
+ salted_hashes <- md5(c("foo","bar"), "baz")
+ unsalted_hashes <- md5(c("foo","bar"))
+ expect_that(length(salted_hashes), equals(2))
+ expect_false(salted_hashes[1] == unsalted_hashes[1])
+ expect_false(salted_hashes[2] == unsalted_hashes[2])
+})
+
+test_that("RIPEMD160 salts single values", {
+ expect_false(ripemd160("foo") == md5("foo","bar"))
+})
+
+test_that("RIPEMD160 salts multiple values", {
+ salted_hashes <- ripemd160(c("foo","bar"), "baz")
+ unsalted_hashes <- ripemd160(c("foo","bar"))
+ expect_that(length(salted_hashes), equals(2))
+ expect_false(salted_hashes[1] == unsalted_hashes[1])
+ expect_false(salted_hashes[2] == unsalted_hashes[2])
+})
+
+test_that("SHA1 salts single values", {
+ expect_false(sha1("foo") == md5("foo","bar"))
+})
+
+test_that("SHA1 salts multiple values", {
+ salted_hashes <- sha1(c("foo","bar"), "baz")
+ unsalted_hashes <- sha1(c("foo","bar"))
+ expect_that(length(salted_hashes), equals(2))
+ expect_false(salted_hashes[1] == unsalted_hashes[1])
+ expect_false(salted_hashes[2] == unsalted_hashes[2])
+})
+
+test_that("SHA256 salts single values", {
+ expect_false(sha256("foo") == md5("foo","bar"))
+})
+
+test_that("SHA256 salts multiple values", {
+ salted_hashes <- sha256(c("foo","bar"), "baz")
+ unsalted_hashes <- sha256(c("foo","bar"))
+ expect_that(length(salted_hashes), equals(2))
+ expect_false(salted_hashes[1] == unsalted_hashes[1])
+ expect_false(salted_hashes[2] == unsalted_hashes[2])
+})
+
+test_that("SHA512 salts single values", {
+ expect_false(sha512("foo") == md5("foo","bar"))
+})
+
+test_that("SHA512 salts multiple values", {
+ salted_hashes <- sha512(c("foo","bar"), "baz")
+ unsalted_hashes <- sha512(c("foo","bar"))
+ expect_that(length(salted_hashes), equals(2))
+ expect_false(salted_hashes[1] == unsalted_hashes[1])
+ expect_false(salted_hashes[2] == unsalted_hashes[2])
+})
diff --git a/tools/version.c b/tools/version.c
new file mode 100644
index 0000000..6a43f54
--- /dev/null
+++ b/tools/version.c
@@ -0,0 +1,4 @@
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+#error OpenSSL version too old
+#endif
diff --git a/tools/winlibs.R b/tools/winlibs.R
new file mode 100644
index 0000000..d108a7a
--- /dev/null
+++ b/tools/winlibs.R
@@ -0,0 +1,8 @@
+# Build against openssl libraries that were compiled with the Rtools gcc toolchain.
+if(!file.exists("../windows/openssl-1.1.0c/include/openssl/ssl.h")){
+ if(getRversion() < "3.3.0") setInternet2()
+ download.file("https://github.com/rwinlib/openssl/archive/v1.1.0c.zip", "lib.zip", quiet = TRUE)
+ dir.create("../windows", showWarnings = FALSE)
+ unzip("lib.zip", exdir = "../windows")
+ unlink("lib.zip")
+}
diff --git a/vignettes/bignum.Rmd b/vignettes/bignum.Rmd
new file mode 100644
index 0000000..3693f4d
--- /dev/null
+++ b/vignettes/bignum.Rmd
@@ -0,0 +1,111 @@
+---
+title: "Fun with bignum: how RSA encryption works"
+date: "`r Sys.Date()`"
+vignette: >
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteIndexEntry{Fun with bignum: how RSA encryption works}
+ \usepackage[utf8]{inputenc}
+output:
+ html_document
+---
+
+```{r setup, include=FALSE}
+library(openssl)
+knitr::opts_chunk$set(echo = TRUE)
+```
+
+
+Primitive types such as `int` or `double` store numbers in exactly one or two bytes, with finite precision. This suffices for most applications, but cryptographic methods require arithmetic on much larger numbers and without loss of precision. Therefore OpenSSL provides a __bignum__ data type which holds arbitrary sized integers and implements all basic arithmetic and comparison operators such as `+`, `-`, `*`, `^`, `%%`, `%/%`, `==`, `!=`, `<`, `<=`, `>` and `>=`.
+
+One special case, the [__modular exponenent__](https://en.wikipedia.org/wiki/Modular_exponentiation) `a^b %% m` can be calculated using `bignum_mod_exp` when `b` is too large for calculating `a^b`.
+
+```{r}
+# create a bignum
+y <- bignum("123456789123456789")
+z <- bignum("D41D8CD98F00B204E9800998ECF8427E", hex = TRUE)
+
+# size grows
+print(y * z)
+
+# Basic arithmetic
+div <- z %/% y
+mod <- z %% y
+z2 <- div * y + mod
+stopifnot(z2 == z)
+stopifnot(div < z)
+```
+
+RSA involves a public key and a private key. The public key should be known by everyone and is used for encrypting messages. Messages encrypted with the public key can only be decrypted in a reasonable amount of time using the private key. In RSA, this asymmetry is based on the practical difficulty of factoring the product of two large prime numbers.
+
+### RSA key generation
+
+An RSA key-pair is generated as follows (adapted from [wikipedia](https://en.wikipedia.org/wiki/RSA_(cryptosystem))):
+
+ - Choose two distinct prime numbers $p$ and $q$. Keep these secret.
+ - Compute the product $n = p*q$. This $n$ value is public and used as the modulus.
+ - Compute $\phi(n) = (p − 1)(q − 1)$.
+ - Choose an integer $e$ smaller than $\phi(n)$ such that $e$ and $\phi(n)$ are coprime. OpenSSL always uses $65537$.
+ - Compute a value for $d$ such that $(d * e)\pmod{\phi(n)} = 1$.
+
+OpenSSL has a key generator that does these things for us.
+
+```{r}
+(key <- rsa_keygen(512))
+(pubkey <- key$pubkey)
+```
+
+Usually we would use `rsa_encrypt` and `rsa_decrypt` to perform the encryption:
+
+```{r}
+msg <- charToRaw("hello world")
+ciphertext <- rsa_encrypt(msg, pubkey)
+rawToChar(rsa_decrypt(ciphertext, key))
+```
+
+Let's look at how this works under the hood.
+
+### How RSA encryption works
+
+The `data` field of the private key extracts the underlying bignum integers:
+
+```{r}
+key$data
+```
+
+You can verify that the equations above hold for this key. The public key is simply a subset of the key which only contains $n$ and $e$:
+
+```{r}
+pubkey$data
+```
+
+In order to encrypt a message into ciphertext we have to treat the message data as an integer. The message cannot be larger than the key size. For example convert the text `hello world` into an integer:
+
+```{r}
+m <- bignum(charToRaw("hello world"))
+print(m)
+```
+
+To encrypt this message $m$ into ciphertext $c$ we calculate $c = m^e\pmod n$. Using the public key from above:
+
+```{r}
+e <- pubkey$data$e
+n <- pubkey$data$n
+c <- (m ^ e) %% n
+print(c)
+```
+
+This is number represents out encrypted message! It is usually exchanged using base64 notation for human readability:
+
+```{r}
+base64_encode(c)
+```
+
+The ciphertext can be decrypted using $d$ from the corresponding private key via $m = c^d \pmod{n}$. Note that `c^d` is too large to calculate directly so we need to use `bignum_mod_exp` instead.
+
+```{r}
+d <- key$data$d
+out <- bignum_mod_exp(c, d, n)
+rawToChar(out)
+```
+
+The only difference with the actual `rsa_encrypt` and `rsa_decrypt` functions is that these add some additional padding to the data.
diff --git a/vignettes/crypto_hashing.Rmd b/vignettes/crypto_hashing.Rmd
new file mode 100644
index 0000000..69603bb
--- /dev/null
+++ b/vignettes/crypto_hashing.Rmd
@@ -0,0 +1,58 @@
+---
+title: "Cryptographic Hashing in R"
+date: "`r Sys.Date()`"
+vignette: >
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteIndexEntry{Cryptographic Hashing in R}
+ \usepackage[utf8]{inputenc}
+output:
+ html_document
+---
+
+```{r, echo = FALSE, message = FALSE}
+knitr::opts_chunk$set(comment = "")
+library(openssl)
+```
+
+The functions `sha1`, `sha256`, `sha512`, `md4`, `md5` and `ripemd160` bind to the respective [digest functions](https://www.openssl.org/docs/manmaster/man1/dgst.html) in OpenSSL's libcrypto. Both binary and string inputs are supported and the output type will match the input type.
+
+```{r}
+md5("foo")
+md5(charToRaw("foo"))
+```
+
+Functions are fully vectorized for the case of character vectors: a vector with n strings will return n hashes.
+
+```{r}
+# Vectorized for strings
+md5(c("foo", "bar", "baz"))
+```
+
+Besides character and raw vectors we can pass a connection object (e.g. a file, socket or url). In this case the function will stream-hash the binary contents of the conection.
+
+```{r}
+# Stream-hash a file
+myfile <- system.file("CITATION")
+md5(file(myfile))
+```
+
+Same for URLs. The hash of the [`R-3.1.1-win.exe`](http://cran.us.r-project.org/bin/windows/base/old/3.1.1/R-3.1.1-win.exe) below should match the one in [`md5sum.txt`](http://cran.us.r-project.org/bin/windows/base/old/3.1.1/md5sum.txt)
+
+```{r eval=FALSE}
+# Stream-hash from a network connection
+md5(url("http://cran.us.r-project.org/bin/windows/base/old/3.1.1/R-3.1.1-win.exe"))
+```
+
+## Compare to digest
+
+Similar functionality is also available in the **digest** package, but with a slightly different interface:
+
+```{r}
+# Compare to digest
+library(digest)
+digest("foo", "md5", serialize = FALSE)
+
+# Other way around
+digest(cars, skip = 0)
+md5(serialize(cars, NULL))
+```
diff --git a/vignettes/keys.Rmd b/vignettes/keys.Rmd
new file mode 100644
index 0000000..16484cd
--- /dev/null
+++ b/vignettes/keys.Rmd
@@ -0,0 +1,99 @@
+---
+title: "Importing and exporting RSA/DSA/EC keys"
+date: "`r Sys.Date()`"
+output:
+ html_document
+vignette: >
+ %\VignetteIndexEntry{Importing and exporting RSA/DSA/EC keys}
+ %\VignetteEngine{knitr::rmarkdown}
+ \usepackage[utf8]{inputenc}
+---
+
+```{r setup, include=FALSE}
+knitr::opts_chunk$set(echo = TRUE)
+knitr::opts_chunk$set(comment = "")
+library(openssl)
+```
+
+The `openssl` package implements a modern interface to libssl and libcrypto for R. It builds on the new `EVP` api which was introduced in OpenSSL 1.0 and provides a unified API to the various methods and formats. OpenSSL supports three major public key crypto systems:
+
+ - __RSA__ : Most popular method. Supports both encryption and signatures.
+ - __DSA__ : Digital Signature Algorithm. Mostly for signatures, not very popular anymore.
+ - __ECDSA__ : Elliptic Curve DSA. Supports signatures and encryption via Diffie Hellman. Gaining popularity.
+
+For each type there are several common __formats__ for storing keys and certificates:
+
+ - [__DER__](#the-der-format): binary format, serialized ASN.1 structure
+ - [__PEM__](#the-pem-format): base64 encoded DER + header wrapped in `===`
+ - [__SSH__](#the-openssh-format): single line of base64 with a header. Only for pubkeys.
+ - [__JWK__](#the-json-web-key-jwk-format): JSON Web key. Stores key data in a JSON object
+
+The openssl package automatically detects the format when possible. However being able to recognize the various formats can be useful.
+
+### The DER format
+
+DER is the standard __binary__ format using by protocols for storing and exchanging keys and certificates. It consists of a [serialized ASN.1](https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One#Example_encoded_in_DER) structure which hold the key's (very large) prime numbers.
+
+
+```{r}
+key <- ec_keygen()
+pubkey <- key$pubkey
+bin <- write_der(pubkey)
+print(bin)
+```
+
+To read a DER key use `read_key` or `read_pubkey` with `der = TRUE`.
+
+```{r}
+read_pubkey(bin, der = TRUE)
+```
+
+Users typically don't need to worry about the key's underlying primes, but have a look at `key$data` if you are curious.
+
+### The PEM format
+
+In practice the user rarely encounters DER because it is mainly for internal use. When humans exchange keys and certificates they typically use the PEM format. PEM is simply **base64 encoded DER data, plus a header**. The header identifies the key (and possibly encryption) type.
+
+```{r}
+cat(write_pem(pubkey))
+cat(write_pem(key, password = NULL))
+```
+
+The PEM format allows for protecting private keys with a password. R will prompt you for the password when reading such a protected key.
+
+```{r}
+cat(write_pem(key, password = "supersecret"))
+```
+
+### The OpenSSH format
+
+For better or worse, OpenSSH uses a custom format for **public keys**. The advantage of this format is that it fits on a single line which is nice for e.g. your `~/.ssh/known_hosts` file. There is no special format for private keys, OpenSSH uses PEM as well.
+
+```{r}
+str <- write_ssh(pubkey)
+print(str)
+```
+
+The `read_pubkey` function will automatically detect if a file contains a `PEM` or `SSH` key.
+
+```{r}
+read_pubkey(str)
+```
+
+### The JSON Web Key (JWK) format
+
+Yet another recent format to store RSA or EC keys are JSON Web Keys (JWK). JWK is part of the **Javascript Object Signing and Encryption (JOSE)** specification. The `write_jwk` and `read_jwk` functions are implemented in a separate package which uses the `openssl` package.
+
+```{r}
+library(jose)
+json <- write_jwk(pubkey)
+jsonlite::prettify(json)
+```
+
+Keys from `jose` and `openssl` are the same.
+
+```{r}
+mykey <- read_jwk(json)
+identical(mykey, pubkey)
+print(mykey)
+```
diff --git a/vignettes/secure_rng.Rmd b/vignettes/secure_rng.Rmd
new file mode 100644
index 0000000..07c1b17
--- /dev/null
+++ b/vignettes/secure_rng.Rmd
@@ -0,0 +1,59 @@
+---
+title: "Generating Secure Random Numbers in R"
+date: "`r Sys.Date()`"
+vignette: >
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteIndexEntry{Generating Secure Random Numbers in R}
+ \usepackage[utf8]{inputenc}
+output:
+ html_document
+---
+
+```{r, echo = FALSE, message = FALSE}
+knitr::opts_chunk$set(comment = "")
+library(openssl)
+```
+
+The `rand_bytes` function binds to [RAND_bytes](https://www.openssl.org/docs/manmaster/man3/RAND_bytes.html) in OpenSSL to generate cryptographically strong pseudo-random bytes. See the OpenSSL documentation for what this means.
+
+```{r}
+rnd <- rand_bytes(10)
+print(rnd)
+```
+
+Bytes are 8 bit and hence can have `2^8 = 256` possible values.
+
+```{r}
+as.numeric(rnd)
+```
+
+Each random byte can be decomposed into 8 random bits (booleans)
+
+```{r}
+x <- rand_bytes(1)
+as.logical(rawToBits(x))
+```
+
+## Secure Random Numbers
+
+`rand_num` is a simple (2 lines) wrapper to `rand_bytes` to generate random numbers (doubles) between 0 and 1.
+
+```{r}
+rand_num(10)
+```
+
+To map random draws from [0,1] into a probability density, we can use a [Cumulative Distribution Function](http://en.wikipedia.org/wiki/Cumulative_distribution_function). For example we can combine `qnorm` and `rand_num` to simulate `rnorm`:
+
+```{r}
+# Secure rnorm
+x <- qnorm(rand_num(1000), mean = 100, sd = 15)
+hist(x)
+```
+
+Same for discrete distributions:
+
+```{r}
+# Secure rbinom
+y <- qbinom(rand_num(1000), size = 20, prob = 0.1)
+hist(y, breaks = -.5:(max(y)+1))
+```
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-openssl.git
More information about the debian-med-commit
mailing list