From 43f1f1a2b00d2e808afc12f08f674f4232de043d Mon Sep 17 00:00:00 2001 From: arithmetic1728 <58957152+arithmetic1728@users.noreply.github.com> Date: Wed, 9 Sep 2020 13:23:13 -0700 Subject: [PATCH] chore: move samples from python-docs-sample (#28) * Cloud iot core [(#946)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/946) * Initial commit. * Changes oauth2 client * Fixes google.auth and addresses changes in v1beta1 * Adds tests, CLI, and fixes some tiny bugs. [(#973)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/973) * Adds tests, CLI, and fixes some tiny bugs. * Fixes lint and adds fake certs for tests. * Print is a function. * I had to change something to retrigger tests * Address review comments * Import order style * Auto-update dependencies. [(#1005)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1005) * Auto-update dependencies. * Fix bigtable lint * Fix IOT iam interaction * Auto-update dependencies. [(#1011)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1011) * Auto-update dependencies. [(#1047)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1047) * Auto-update dependencies. [(#1055)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1055) * Auto-update dependencies. * Explicitly use latest bigtable client Change-Id: Id71e9e768f020730e4ca9514a0d7ebaa794e7d9e * Revert language update for now Change-Id: I8867f154e9a5aae00d0047c9caf880e5e8f50c53 * Remove pdb. smh Change-Id: I5ff905fadc026eebbcd45512d4e76e003e3b2b43 * Gets API key, project ID, and service account JSON from environment [(#1064)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1064) * Auto-update dependencies. [(#1094)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1094) * Auto-update dependencies. * Relax assertions in the ocr_nl sample Change-Id: I6d37e5846a8d6dd52429cb30d501f448c52cbba1 * Drop unused logging apiary samples Change-Id: I545718283773cb729a5e0def8a76ebfa40829d51 * Changes for snippets [(#1105)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1105) * Removes START / END blocks for snippets. * Fixes style * Fixes IAM section for Python3 compatibility. * Auto-update dependencies. [(#1109)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1109) * Update all generated readme auth instructions [(#1121)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1121) Change-Id: I03b5eaef8b17ac3dc3c0339fd2c7447bd3e11bd2 * Auto-update dependencies. [(#1133)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1133) * Auto-update dependencies. * Fix missing http library Change-Id: I99faa600f2f3f1f50f57694fc9835d7f35bda250 * Final additions in private beta [(#1136)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1136) * Final additions in private beta * Adds HTTP client and state support * Fixes rouge space * Remove invalid message on error. * Removes API key because discovery is now public [(#1140)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1140) * Added Link to Python Setup Guide [(#1158)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1158) * Update Readme.rst to add Python setup guide As requested in b/64770713. This sample is linked in documentation https://cloud.google.com/bigtable/docs/scaling, and it would make more sense to update the guide here than in the documentation. * Update README.rst * Update README.rst * Update README.rst * Update README.rst * Update README.rst * Update install_deps.tmpl.rst * Updated readmegen scripts and re-generated related README files * Fixed the lint error * Auto-update dependencies. [(#1186)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1186) * Updates pubsub client [(#1195)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1195) * Updates pubsub client * Fixes lint error. * Fix linter errors * Auto-update dependencies. [(#1208)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1208) * Auto-update dependencies. [(#1217)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1217) * Auto-update dependencies. [(#1239)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1239) * Updated the certificate [(#1251)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1251) * Added "Open in Cloud Shell" buttons to README files [(#1254)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1254) * Adds set-config to manager sample [(#1275)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1275) * Auto-update dependencies. [(#1282)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1282) * Auto-update dependencies. * Fix storage acl sample Change-Id: I413bea899fdde4c4859e4070a9da25845b81f7cf * Auto-update dependencies. [(#1309)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1309) * Add sample to get config versions for a device. [(#1310)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1310) * Trivial fix to Cloud IoT URL. [(#1302)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1302) * Auto-update dependencies. [(#1320)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1320) * Adds IAM examples for Python. [(#1318)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1318) * MQTT Exponential backoff and manager updates [(#1345)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1345) * Auto-update dependencies. [(#1355)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1355) * Auto-update dependencies. [(#1359)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1359) * Cleanup Cloud IoT region tags. * Adds region to examples [(#1378)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1378) * Auto-update dependencies. * Regenerate the README files and fix the Open in Cloud Shell link for some samples [(#1441)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1441) * fixes iot_list_registries closing region tag [(#1434)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1434) * Update READMEs to fix numbering and add git clone [(#1464)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1464) * Updates dependencies [(#1713)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1713) * Updates dependencies * Upgrades e2e dependencies * Auto-update dependencies. [(#1846)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1846) ACK, merging. * Updates library versions and tests [(#1884)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1884) * Updates library versions and tests * Better reliability for flaky tests [(#1960)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1960) * Increases reliability for flaky tests * Replaces checks where device or gateway ID could affect test outcome. * Migrates manager samples for Gateways from beta folder [(#1973)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1973) * Migrates manager samples for Gateways from beta folder * Migrates Gateway code to MQTT example [(#1977)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1977) * Migrates Gateway code to MQTT example * Refactors attach device and updates tests * Auto-update dependencies. [(#1980)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/1980) * Auto-update dependencies. * Update requirements.txt * Update requirements.txt * Remove stale test registries to avoid reaching limits [(#2159)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2159) * Add cleanup step to tests to avoid hitting 100 registry limit * Cleans up older test registries in case tests were cancelled and resources leaked * Fixes broken style * Renames includecode blocks to be ^iot(.*) * Fix IoT parameters [(#2320)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2320) * Fix list devices in IoT sample [(#2319)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2319) * iot: switch to Cloud Client [(#2418)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2418) * First part of Cloud client library migration, separating as this part affects tests * Updates create / delete device methods to use Cloud client library [(#2420)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2420) * Updates create / delete device methods to use Cloud client library * Lint * Adds split updates for Firebase ... opencensus [(#2438)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2438) * Cloud client library migration for registry management features [(#2453)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2453) * Cloud client library migration for registry management features * Adds cloud client for remaining Cloud IoT Core apis [(#2479)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2479) * Cleanly disconnect client before JWT expiration. [(#2622)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2622) * Auto-update dependencies. [(#2005)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2005) * Auto-update dependencies. * Revert update of appengine/flexible/datastore. * revert update of appengine/flexible/scipy * revert update of bigquery/bqml * revert update of bigquery/cloud-client * revert update of bigquery/datalab-migration * revert update of bigtable/quickstart * revert update of compute/api * revert update of container_registry/container_analysis * revert update of dataflow/run_template * revert update of datastore/cloud-ndb * revert update of dialogflow/cloud-client * revert update of dlp * revert update of functions/imagemagick * revert update of functions/ocr/app * revert update of healthcare/api-client/fhir * revert update of iam/api-client * revert update of iot/api-client/gcs_file_to_device * revert update of iot/api-client/mqtt_example * revert update of language/automl * revert update of run/image-processing * revert update of vision/automl * revert update testing/requirements.txt * revert update of vision/cloud-client/detect * revert update of vision/cloud-client/product_search * revert update of jobs/v2/api_client * revert update of jobs/v3/api_client * revert update of opencensus * revert update of translate/cloud-client * revert update to speech/cloud-client Co-authored-by: Kurtis Van Gent <31518063+kurtisvg@users.noreply.github.com> Co-authored-by: Doug Mahugh * Replaces empty return value with string [(#2709)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2709) * Replaces empty return value with string Co-authored-by: Leah E. Cole <6719667+leahecole@users.noreply.github.com> * chore(deps): update dependency google-auth to v1.11.2 [(#2724)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2724) Co-authored-by: Leah E. Cole <6719667+leahecole@users.noreply.github.com> * Iot flaky tests [(#3068)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3068) * Checks if min_passes can be used now that we have swapped out devrel tools * Replace imports. * More random registry id * chore(deps): update dependency google-cloud-iot to v0.3.1 [(#3159)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3159) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-cloud-iot](https://togithub.com/googleapis/python-iot) | patch | `==0.3.0` -> `==0.3.1` | --- ### Release Notes
googleapis/python-iot ### [`v0.3.1`](https://togithub.com/googleapis/python-iot/blob/master/CHANGELOG.md#​100httpswwwgithubcomgoogleapispython-iotcomparev031v100-2020-02-28) [Compare Source](https://togithub.com/googleapis/python-iot/compare/v0.3.0...v0.3.1) ##### Features - bump release status to GA ([#​6](https://www.github.com/googleapis/python-iot/issues/6)) ([6793d49](https://www.github.com/googleapis/python-iot/commit/6793d493ec576191996c2e82c52ff549ee26347c)) ##### [0.3.1](https://www.github.com/googleapis/python-iot/compare/v0.3.0...v0.3.1) (2020-02-06) ##### Bug Fixes - **iot:** modify retry and timeout configs; add 2.7 deprecation warning; add 'required' to docstring for required args; add 3.8 unit tests (via synth) ([#​10069](https://www.github.com/googleapis/python-iot/issues/10069)) ([ce6f5cf](https://www.github.com/googleapis/python-iot/commit/ce6f5cf2c1611af179da8dba3f73b1f8dc1bb1e1))
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * chore(deps): update dependency google-cloud-iot to v1 [(#3209)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3209) Co-authored-by: gcf-merge-on-green[bot] <60162190+gcf-merge-on-green[bot]@users.noreply.github.com> * Simplify noxfile setup. [(#2806)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/2806) * chore(deps): update dependency requests to v2.23.0 * Simplify noxfile and add version control. * Configure appengine/standard to only test Python 2.7. * Update Kokokro configs to match noxfile. * Add requirements-test to each folder. * Remove Py2 versions from everything execept appengine/standard. * Remove conftest.py. * Remove appengine/standard/conftest.py * Remove 'no-sucess-flaky-report' from pytest.ini. * Add GAE SDK back to appengine/standard tests. * Fix typo. * Roll pytest to python 2 version. * Add a bunch of testing requirements. * Remove typo. * Add appengine lib directory back in. * Add some additional requirements. * Fix issue with flake8 args. * Even more requirements. * Readd appengine conftest.py. * Add a few more requirements. * Even more Appengine requirements. * Add webtest for appengine/standard/mailgun. * Add some additional requirements. * Add workaround for issue with mailjet-rest. * Add responses for appengine/standard/mailjet. Co-authored-by: Renovate Bot * Adds example parameters [(#3102)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3102) * Adds example parameters to IoT Manager sample for appearance in documentation Co-authored-by: Leah E. Cole <6719667+leahecole@users.noreply.github.com> * Remove oauth2client from IoT and Functions samples [(#3255)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3255) * chore: remove oauth2client from functions and iot * fix: fix import * fix: correct syntax * fix: correct import for service_account * fix: fix path * [iot] fix: mitigate flaky tests [(#3299)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3299) * [iot] fix: mitigate flaky tests * use uuid4 instead of time for resource name * correctly use the pytest marker * mark another test as flaky Co-authored-by: Christopher Wilcox * Update dependency google-auth to v1.14.0 [(#3148)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3148) Co-authored-by: Leah E. Cole <6719667+leahecole@users.noreply.github.com> * chore(deps): update dependency google-api-python-client to v1.8.0 [(#3100)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3100) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-api-python-client](https://togithub.com/google/google-api-python-client) | minor | `==1.7.11` -> `==1.8.0` | --- ### Release Notes
google/google-api-python-client ### [`v1.8.0`](https://togithub.com/google/google-api-python-client/releases/v1.8.0) [Compare Source](https://togithub.com/google/google-api-python-client/compare/v1.7.12...v1.8.0) Release to support API endpoint override. New Features - Add api endpoint override. ([#​829](https://togithub.com/googleapis/google-api-python-client/pull/829)) Implementation Changes - Don't set http.redirect_codes if the attr doesn't exist and allow more httplib2 versions. ([#​841](https://togithub.com/googleapis/google-api-python-client/pull/841)) ### [`v1.7.12`](https://togithub.com/google/google-api-python-client/releases/v1.7.12) [Compare Source](https://togithub.com/google/google-api-python-client/compare/v1.7.11...v1.7.12) Bugfix release Implementation Changes - Look for field 'detail' in error message. ([#​739](https://togithub.com/googleapis/google-api-python-client/pull/739)) - Exclude 308s from httplib2 redirect codes list ([#​813](https://togithub.com/googleapis/google-api-python-client/pull/813)) Documentation - Remove oauth2client from docs ([#​738](https://togithub.com/googleapis/google-api-python-client/pull/738)) - Fix typo. ([#​745](https://togithub.com/googleapis/google-api-python-client/pull/745)) - Remove compatibility badges. ([#​746](https://togithub.com/googleapis/google-api-python-client/pull/746)) - Fix TypeError: search_analytics_api_sample.py [#​732](https://togithub.com/google/google-api-python-client/issues/732) ([#​742](https://togithub.com/googleapis/google-api-python-client/pull/742)) - Correct response access ([#​750](https://togithub.com/googleapis/google-api-python-client/pull/750)) - Fix link to API explorer ([#​760](https://togithub.com/googleapis/google-api-python-client/pull/760)) - Fix argument typo in oauth2 code example ([#​763](https://togithub.com/googleapis/google-api-python-client/pull/763)) - Recommend install with virtualenv ([#​768](https://togithub.com/googleapis/google-api-python-client/pull/768)) - Fix capitalization in docs/README.md ([#​770](https://togithub.com/googleapis/google-api-python-client/pull/770)) - Remove compatibility badges ([#​796](https://togithub.com/googleapis/google-api-python-client/pull/796)) - Remove mentions of pycrypto ([#​799](https://togithub.com/googleapis/google-api-python-client/pull/799)) - Fix typo in model.py - Add note about Google Ads llibrary ([#​814](https://togithub.com/googleapis/google-api-python-client/pull/814)) Internal / Testing Changes - Blacken ([#​772](https://togithub.com/googleapis/google-api-python-client/pull/722)) - Move kokoro configs ([#​832](https://togithub.com/googleapis/google-api-python-client/pull/832))
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * [iot] testing: re-raise the exception [(#3425)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3425) fixes #3424 * chore(deps): update dependency cryptography to v2.9 [(#3266)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3266) Co-authored-by: Leah E. Cole <6719667+leahecole@users.noreply.github.com> * Update dependency google-cloud-pubsub to v1.4.2 in functions and IoT [(#3342)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3342) Co-authored-by: Leah E. Cole <6719667+leahecole@users.noreply.github.com> * chore(deps): update dependency cryptography to v2.9.1 [(#3463)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3463) * Update dependency cryptography to v2.9.2 [(#3473)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3473) * Update dependency google-api-python-client to v1.8.2 [(#3452)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3452) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-api-python-client](https://togithub.com/google/google-api-python-client) | patch | `==1.8.0` -> `==1.8.2` | | [google-api-python-client](https://togithub.com/google/google-api-python-client) | minor | `==1.7.11` -> `==1.8.2` | --- ### Release Notes
google/google-api-python-client ### [`v1.8.2`](https://togithub.com/google/google-api-python-client/blob/master/CHANGELOG.md#​182-httpswwwgithubcomgoogleapisgoogle-api-python-clientcomparev181v182-2020-04-21) [Compare Source](https://togithub.com/google/google-api-python-client/compare/v1.8.1...v1.8.2) ### [`v1.8.1`](https://togithub.com/google/google-api-python-client/blob/master/CHANGELOG.md#​181-httpswwwgithubcomgoogleapisgoogle-api-python-clientcomparev180v181-2020-04-20) [Compare Source](https://togithub.com/google/google-api-python-client/compare/v1.8.0...v1.8.1)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * chore(deps): update dependency google-auth to v1.14.1 [(#3464)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3464) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-auth](https://togithub.com/googleapis/google-auth-library-python) | patch | `==1.14.0` -> `==1.14.1` | | [google-auth](https://togithub.com/googleapis/google-auth-library-python) | minor | `==1.11.2` -> `==1.14.1` | --- ### Release Notes
googleapis/google-auth-library-python ### [`v1.14.1`](https://togithub.com/googleapis/google-auth-library-python/blob/master/CHANGELOG.md#​1141-httpswwwgithubcomgoogleapisgoogle-auth-library-pythoncomparev1140v1141-2020-04-21) [Compare Source](https://togithub.com/googleapis/google-auth-library-python/compare/v1.14.0...v1.14.1)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * Add example command for docs [(#3708)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3708) * chore(deps): update dependency google-auth to v1.14.2 [(#3724)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3724) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-auth](https://togithub.com/googleapis/google-auth-library-python) | patch | `==1.14.1` -> `==1.14.2` | --- ### Release Notes
googleapis/google-auth-library-python ### [`v1.14.2`](https://togithub.com/googleapis/google-auth-library-python/blob/master/CHANGELOG.md#​1142-httpswwwgithubcomgoogleapisgoogle-auth-library-pythoncomparev1141v1142-2020-05-07) [Compare Source](https://togithub.com/googleapis/google-auth-library-python/compare/v1.14.1...v1.14.2)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * chore: some lint fixes [(#3747)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3747) * chore(deps): update dependency google-cloud-pubsub to v1.4.3 [(#3725)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3725) Co-authored-by: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Co-authored-by: Takashi Matsuo * chore(deps): update dependency google-auth to v1.14.3 [(#3728)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3728) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-auth](https://togithub.com/googleapis/google-auth-library-python) | patch | `==1.14.2` -> `==1.14.3` | --- ### Release Notes
googleapis/google-auth-library-python ### [`v1.14.3`](https://togithub.com/googleapis/google-auth-library-python/blob/master/CHANGELOG.md#​1143-httpswwwgithubcomgoogleapisgoogle-auth-library-pythoncomparev1142v1143-2020-05-11) [Compare Source](https://togithub.com/googleapis/google-auth-library-python/compare/v1.14.2...v1.14.3)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [x] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * update google-auth to 1.15.0 part 5 [(#3818)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3818) * update google-api-python-client to 1.8.3 part 4 [(#3826)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3826) * chore(deps): update dependency google-cloud-pubsub to v1.5.0 [(#3781)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3781) Co-authored-by: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> * chore(deps): update dependency google-api-python-client to v1.8.4 [(#3881)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3881) Co-authored-by: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Co-authored-by: gcf-merge-on-green[bot] <60162190+gcf-merge-on-green[bot]@users.noreply.github.com> * chore(deps): update dependency google-auth to v1.16.0 [(#3903)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3903) * chore(deps): update dependency google-api-python-client to v1.9.1 [(#3930)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3930) * update google-auth part 5 [(#3966)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3966) * testing: start using btlr [(#3959)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/3959) * testing: start using btlr The binary is at gs://cloud-devrel-kokoro-resources/btlr/v0.0.1/btlr * add period after DIFF_FROM * use array for btlr args * fix websocket tests * add debug message * wait longer for the server to spin up * dlp: bump the wait timeout to 10 minutes * [run] copy noxfile.py to child directory to avoid gcloud issue * [iam] fix: only display description when the key exists * use uuid4 instead of uuid1 * [iot] testing: use the same format for registry id * Stop asserting Out of memory not in the output * fix missing imports * [dns] testing: more retries with delay * [dlp] testing: longer timeout * use the max-concurrency flag * use 30 workers * [monitoring] use multiple projects * [dlp] testing: longer timeout * Replace GCLOUD_PROJECT with GOOGLE_CLOUD_PROJECT. [(#4022)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4022) * Update dependency google-api-python-client to v1.9.2 [(#4038)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4038) * Update dependency google-auth to v1.17.0 [(#4058)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4058) * chore(deps): update dependency google-auth to v1.17.1 [(#4073)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4073) * Update dependency google-auth to v1.17.2 [(#4083)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4083) * Update dependency google-api-python-client to v1.9.3 [(#4057)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4057) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-api-python-client](https://togithub.com/googleapis/google-api-python-client) | patch | `==1.9.2` -> `==1.9.3` | --- ### Release Notes
googleapis/google-api-python-client ### [`v1.9.3`](https://togithub.com/googleapis/google-api-python-client/blob/master/CHANGELOG.md#​193-httpswwwgithubcomgoogleapisgoogle-api-python-clientcomparev192v193-2020-06-10) [Compare Source](https://togithub.com/googleapis/google-api-python-client/compare/v1.9.2...v1.9.3)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * Update dependency google-auth to v1.18.0 [(#4125)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4125) * Update dependency google-cloud-pubsub to v1.6.0 [(#4039)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4039) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-cloud-pubsub](https://togithub.com/googleapis/python-pubsub) | minor | `==1.5.0` -> `==1.6.0` | --- ### Release Notes
googleapis/python-pubsub ### [`v1.6.0`](https://togithub.com/googleapis/python-pubsub/blob/master/CHANGELOG.md#​160-httpswwwgithubcomgoogleapispython-pubsubcomparev150v160-2020-06-09) [Compare Source](https://togithub.com/googleapis/python-pubsub/compare/v1.5.0...v1.6.0) ##### Features - Add flow control for message publishing ([#​96](https://www.github.com/googleapis/python-pubsub/issues/96)) ([06085c4](https://www.github.com/googleapis/python-pubsub/commit/06085c4083b9dccdd50383257799904510bbf3a0)) ##### Bug Fixes - Fix PubSub incompatibility with api-core 1.17.0+ ([#​103](https://www.github.com/googleapis/python-pubsub/issues/103)) ([c02060f](https://www.github.com/googleapis/python-pubsub/commit/c02060fbbe6e2ca4664bee08d2de10665d41dc0b)) ##### Documentation - Clarify that Schedulers shouldn't be used with multiple SubscriberClients ([#​100](https://togithub.com/googleapis/python-pubsub/pull/100)) ([cf9e87c](https://togithub.com/googleapis/python-pubsub/commit/cf9e87c80c0771f3fa6ef784a8d76cb760ad37ef)) - Fix update subscription/snapshot/topic samples ([#​113](https://togithub.com/googleapis/python-pubsub/pull/113)) ([e62c38b](https://togithub.com/googleapis/python-pubsub/commit/e62c38bb33de2434e32f866979de769382dea34a)) ##### Internal / Testing Changes - Re-generated service implementaton using synth: removed experimental notes from the RetryPolicy and filtering features in anticipation of GA, added DetachSubscription (experimental) ([#​114](https://togithub.com/googleapis/python-pubsub/pull/114)) ([0132a46](https://togithub.com/googleapis/python-pubsub/commit/0132a4680e0727ce45d5e27d98ffc9f3541a0962)) - Incorporate will_accept() checks into publish() ([#​108](https://togithub.com/googleapis/python-pubsub/pull/108)) ([6c7677e](https://togithub.com/googleapis/python-pubsub/commit/6c7677ecb259672bbb9b6f7646919e602c698570))
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * chore(deps): update dependency google-cloud-pubsub to v1.6.1 [(#4242)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4242) Co-authored-by: gcf-merge-on-green[bot] <60162190+gcf-merge-on-green[bot]@users.noreply.github.com> * chore(deps): update dependency flaky to v3.7.0 [(#4263)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4263) * Update dependency google-auth-httplib2 to v0.0.4 [(#4255)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4255) Co-authored-by: Takashi Matsuo * chore(deps): update dependency pytest to v5.4.3 [(#4279)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4279) * chore(deps): update dependency pytest to v5.4.3 * specify pytest for python 2 in appengine Co-authored-by: Leah Cole * chore(deps): update dependency google-auth to v1.19.0 [(#4293)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4293) * chore(deps): update dependency google-cloud-pubsub to v1.7.0 [(#4290)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4290) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-cloud-pubsub](https://togithub.com/googleapis/python-pubsub) | minor | `==1.6.1` -> `==1.7.0` | --- ### Release Notes
googleapis/python-pubsub ### [`v1.7.0`](https://togithub.com/googleapis/python-pubsub/blob/master/CHANGELOG.md#​170-httpswwwgithubcomgoogleapispython-pubsubcomparev161v170-2020-07-13) [Compare Source](https://togithub.com/googleapis/python-pubsub/compare/v1.6.1...v1.7.0) ##### New Features - Add support for server-side flow control. ([#​143](https://togithub.com/googleapis/python-pubsub/pull/143)) ([04e261c](https://www.github.com/googleapis/python-pubsub/commit/04e261c602a2919cc75b3efa3dab099fb2cf704c)) ##### Dependencies - Update samples dependency `google-cloud-pubsub` to `v1.6.1`. ([#​144](https://togithub.com/googleapis/python-pubsub/pull/144)) ([1cb6746](https://togithub.com/googleapis/python-pubsub/commit/1cb6746b00ebb23dbf1663bae301b32c3fc65a88)) ##### Documentation - Add pubsub/cloud-client samples from the common samples repo (with commit history). ([#​151](https://togithub.com/googleapis/python-pubsub/pull/151)) - Add flow control section to publish overview. ([#​129](https://togithub.com/googleapis/python-pubsub/pull/129)) ([acc19eb](https://www.github.com/googleapis/python-pubsub/commit/acc19eb048eef067d9818ef3e310b165d9c6307e)) - Add a link to Pub/Sub filtering language public documentation to `pubsub.proto`. ([#​121](https://togithub.com/googleapis/python-pubsub/pull/121)) ([8802d81](https://www.github.com/googleapis/python-pubsub/commit/8802d8126247f22e26057e68a42f5b5a82dcbf0d))
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Renovate will not automatically rebase this PR, because other commits have been found. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * Update dependency google-api-python-client to v1.10.0 [(#4302)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4302) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-api-python-client](https://togithub.com/googleapis/google-api-python-client) | minor | `==1.9.3` -> `==1.10.0` | --- ### Release Notes
googleapis/google-api-python-client ### [`v1.10.0`](https://togithub.com/googleapis/google-api-python-client/blob/master/CHANGELOG.md#​1100-httpswwwgithubcomgoogleapisgoogle-api-python-clientcomparev193v1100-2020-07-15) [Compare Source](https://togithub.com/googleapis/google-api-python-client/compare/v1.9.3...v1.10.0) ##### Features - allow to use 'six.moves.collections_abc.Mapping' in 'client_options.from_dict()' ([#​943](https://www.github.com/googleapis/google-api-python-client/issues/943)) ([21af37b](https://www.github.com/googleapis/google-api-python-client/commit/21af37b11ea2d6a89b3df484e1b2fa1d12849510)) - Build universal wheels ([#​948](https://www.github.com/googleapis/google-api-python-client/issues/948)) ([3e28a1e](https://www.github.com/googleapis/google-api-python-client/commit/3e28a1e0d47f829182cd92f37475ab91fa5e4afc)) - discovery supports retries ([#​967](https://www.github.com/googleapis/google-api-python-client/issues/967)) ([f3348f9](https://www.github.com/googleapis/google-api-python-client/commit/f3348f98bf91a88a28bf61b12b95e391cc3be1ff)), closes [#​848](https://www.github.com/googleapis/google-api-python-client/issues/848) ##### Documentation - consolidating and updating the Contribution Guide ([#​964](https://www.github.com/googleapis/google-api-python-client/issues/964)) ([63f97f3](https://www.github.com/googleapis/google-api-python-client/commit/63f97f37daee37a725eb05df3097b20d5d4eaaf0)), closes [#​963](https://www.github.com/googleapis/google-api-python-client/issues/963) ##### [1.9.3](https://www.github.com/googleapis/google-api-python-client/compare/v1.9.2...v1.9.3) (2020-06-10) ##### Bug Fixes - update GOOGLE_API_USE_MTLS values ([#​940](https://www.github.com/googleapis/google-api-python-client/issues/940)) ([19908ed](https://www.github.com/googleapis/google-api-python-client/commit/19908edcd8a3df1db41e34100acc1f15c3c99397)) ##### [1.9.2](https://www.github.com/googleapis/google-api-python-client/compare/v1.9.1...v1.9.2) (2020-06-04) ##### Bug Fixes - bump api-core version ([#​936](https://www.github.com/googleapis/google-api-python-client/issues/936)) ([ee53b3b](https://www.github.com/googleapis/google-api-python-client/commit/ee53b3b32a050874ba4cfb491fb384f94682c824)) ##### [1.9.1](https://www.github.com/googleapis/google-api-python-client/compare/v1.9.0...v1.9.1) (2020-06-02) ##### Bug Fixes - fix python-api-core dependency issue ([#​931](https://www.github.com/googleapis/google-api-python-client/issues/931)) ([42028ed](https://www.github.com/googleapis/google-api-python-client/commit/42028ed2b2be47f85b70eb813185264f1f573d01))
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * chore(deps): update dependency google-auth to v1.19.1 [(#4304)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4304) * chore(deps): update dependency google-auth to v1.19.2 [(#4321)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4321) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [google-auth](https://togithub.com/googleapis/google-auth-library-python) | patch | `==1.19.1` -> `==1.19.2` | --- ### Release Notes
googleapis/google-auth-library-python ### [`v1.19.2`](https://togithub.com/googleapis/google-auth-library-python/blob/master/CHANGELOG.md#​1192-httpswwwgithubcomgoogleapisgoogle-auth-library-pythoncomparev1191v1192-2020-07-17) [Compare Source](https://togithub.com/googleapis/google-auth-library-python/compare/v1.19.1...v1.19.2)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Never, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#GoogleCloudPlatform/python-docs-samples). * chore(deps): update dependency cryptography to v3 [(#4337)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4337) * Update dependency google-auth to v1.20.0 [(#4387)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4387) * Update dependency pytest to v6 [(#4390)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4390) * chore(deps): update dependency google-auth to v1.20.1 [(#4452)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4452) * chore(deps): update dependency google-api-python-client to v1.10.1 [(#4557)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4557) * chore(deps): update dependency google-api-python-client to v1.10.1 * Update requirements.txt Co-authored-by: Takashi Matsuo * Update dependency google-auth to v1.21.0 [(#4588)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4588) * Update dependency google-api-python-client to v1.11.0 [(#4587)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4587) Co-authored-by: Takashi Matsuo * Update dependency cryptography to v3.1 [(#4571)](https://github.com/GoogleCloudPlatform/python-docs-samples/issues/4571) Co-authored-by: Charles Engelke * chore: update templates * chore: add files from mqtt_example Co-authored-by: Gus Class Co-authored-by: DPE bot Co-authored-by: Jon Wayne Parrott Co-authored-by: michaelawyu Co-authored-by: Andrew Gorcester Co-authored-by: Andrew Gorcester Co-authored-by: noerog <32459203+noerog@users.noreply.github.com> Co-authored-by: postmasters Co-authored-by: Jason Dobry Co-authored-by: Brent Shaffer Co-authored-by: Frank Natividad Co-authored-by: michaelawyu Co-authored-by: Kurtis Van Gent <31518063+kurtisvg@users.noreply.github.com> Co-authored-by: Doug Mahugh Co-authored-by: Leah E. Cole <6719667+leahecole@users.noreply.github.com> Co-authored-by: WhiteSource Renovate Co-authored-by: gcf-merge-on-green[bot] <60162190+gcf-merge-on-green[bot]@users.noreply.github.com> Co-authored-by: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Co-authored-by: Takashi Matsuo Co-authored-by: Christopher Wilcox Co-authored-by: Leah Cole Co-authored-by: Charles Engelke --- .github/CODEOWNERS | 8 + .github/snippet-bot.yml | 0 .gitignore | 3 +- .kokoro/build.sh | 8 +- .kokoro/docker/docs/Dockerfile | 98 + .kokoro/docker/docs/fetch_gpg_keys.sh | 45 + .kokoro/docs/common.cfg | 21 +- .kokoro/docs/docs-presubmit.cfg | 17 + .kokoro/publish-docs.sh | 39 +- .kokoro/trampoline_v2.sh | 487 +++++ .trampolinerc | 51 + docs/conf.py | 11 +- noxfile.py | 37 + samples/AUTHORING_GUIDE.md | 1 + samples/CONTRIBUTING.md | 1 + samples/api-client/manager/README.rst | 198 ++ samples/api-client/manager/README.rst.in | 23 + samples/api-client/manager/manager.py | 1041 +++++++++ samples/api-client/manager/manager_test.py | 506 +++++ samples/api-client/manager/noxfile.py | 224 ++ .../api-client/manager/requirements-test.txt | 1 + samples/api-client/manager/requirements.txt | 9 + .../api-client/manager/resources/README.md | 9 + .../manager/resources/ec_public.pem | 4 + .../api-client/manager/resources/rsa_cert.pem | 18 + .../manager/resources/rsa_private.pem | 28 + .../mqtt_example/cloudiot_mqtt_example.py | 513 +++++ .../mqtt_example/resources/README.md | 4 + .../resources/owlister_hootie.png | Bin 0 -> 39406 bytes .../mqtt_example/resources/roots.pem | 1939 +++++++++++++++++ .../mqtt_example/resources/rsa_cert.pem | 18 + .../mqtt_example/resources/rsa_private.pem | 28 + scripts/decrypt-secrets.sh | 15 +- synth.metadata | 11 +- synth.py | 8 +- 35 files changed, 5396 insertions(+), 28 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/snippet-bot.yml create mode 100644 .kokoro/docker/docs/Dockerfile create mode 100755 .kokoro/docker/docs/fetch_gpg_keys.sh create mode 100644 .kokoro/docs/docs-presubmit.cfg create mode 100755 .kokoro/trampoline_v2.sh create mode 100644 .trampolinerc create mode 100644 samples/AUTHORING_GUIDE.md create mode 100644 samples/CONTRIBUTING.md create mode 100644 samples/api-client/manager/README.rst create mode 100644 samples/api-client/manager/README.rst.in create mode 100644 samples/api-client/manager/manager.py create mode 100644 samples/api-client/manager/manager_test.py create mode 100644 samples/api-client/manager/noxfile.py create mode 100644 samples/api-client/manager/requirements-test.txt create mode 100644 samples/api-client/manager/requirements.txt create mode 100644 samples/api-client/manager/resources/README.md create mode 100644 samples/api-client/manager/resources/ec_public.pem create mode 100644 samples/api-client/manager/resources/rsa_cert.pem create mode 100644 samples/api-client/manager/resources/rsa_private.pem create mode 100644 samples/api-client/mqtt_example/cloudiot_mqtt_example.py create mode 100644 samples/api-client/mqtt_example/resources/README.md create mode 100644 samples/api-client/mqtt_example/resources/owlister_hootie.png create mode 100644 samples/api-client/mqtt_example/resources/roots.pem create mode 100644 samples/api-client/mqtt_example/resources/rsa_cert.pem create mode 100644 samples/api-client/mqtt_example/resources/rsa_private.pem diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..ebe912ff --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,8 @@ +# Code owners file. +# This file controls who is tagged for review for any given pull request. +# +# For syntax help see: +# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax + + +/samples/**/*.py @gguuss @googleapis/python-samples-owners \ No newline at end of file diff --git a/.github/snippet-bot.yml b/.github/snippet-bot.yml new file mode 100644 index 00000000..e69de29b diff --git a/.gitignore b/.gitignore index b87e1ed5..b9daa52f 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ pip-log.txt # Built documentation docs/_build bigquery/docs/generated +docs.metadata # Virtual environment env/ @@ -57,4 +58,4 @@ system_tests/local_test_setup # Make sure a generated file isn't accidentally committed. pylintrc -pylintrc.test \ No newline at end of file +pylintrc.test diff --git a/.kokoro/build.sh b/.kokoro/build.sh index e72a53e6..1ecff726 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -36,4 +36,10 @@ python3.6 -m pip uninstall --yes --quiet nox-automation python3.6 -m pip install --upgrade --quiet nox python3.6 -m nox --version -python3.6 -m nox +# If NOX_SESSION is set, it only runs the specified session, +# otherwise run all the sessions. +if [[ -n "${NOX_SESSION:-}" ]]; then + python3.6 -m nox -s "${NOX_SESSION:-}" +else + python3.6 -m nox +fi diff --git a/.kokoro/docker/docs/Dockerfile b/.kokoro/docker/docs/Dockerfile new file mode 100644 index 00000000..412b0b56 --- /dev/null +++ b/.kokoro/docker/docs/Dockerfile @@ -0,0 +1,98 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ubuntu:20.04 + +ENV DEBIAN_FRONTEND noninteractive + +# Ensure local Python is preferred over distribution Python. +ENV PATH /usr/local/bin:$PATH + +# Install dependencies. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-transport-https \ + build-essential \ + ca-certificates \ + curl \ + dirmngr \ + git \ + gpg-agent \ + graphviz \ + libbz2-dev \ + libdb5.3-dev \ + libexpat1-dev \ + libffi-dev \ + liblzma-dev \ + libreadline-dev \ + libsnappy-dev \ + libssl-dev \ + libsqlite3-dev \ + portaudio19-dev \ + redis-server \ + software-properties-common \ + ssh \ + sudo \ + tcl \ + tcl-dev \ + tk \ + tk-dev \ + uuid-dev \ + wget \ + zlib1g-dev \ + && add-apt-repository universe \ + && apt-get update \ + && apt-get -y install jq \ + && apt-get clean autoclean \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -f /var/cache/apt/archives/*.deb + + +COPY fetch_gpg_keys.sh /tmp +# Install the desired versions of Python. +RUN set -ex \ + && export GNUPGHOME="$(mktemp -d)" \ + && echo "disable-ipv6" >> "${GNUPGHOME}/dirmngr.conf" \ + && /tmp/fetch_gpg_keys.sh \ + && for PYTHON_VERSION in 3.7.8 3.8.5; do \ + wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz" \ + && wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc" \ + && gpg --batch --verify python-${PYTHON_VERSION}.tar.xz.asc python-${PYTHON_VERSION}.tar.xz \ + && rm -r python-${PYTHON_VERSION}.tar.xz.asc \ + && mkdir -p /usr/src/python-${PYTHON_VERSION} \ + && tar -xJC /usr/src/python-${PYTHON_VERSION} --strip-components=1 -f python-${PYTHON_VERSION}.tar.xz \ + && rm python-${PYTHON_VERSION}.tar.xz \ + && cd /usr/src/python-${PYTHON_VERSION} \ + && ./configure \ + --enable-shared \ + # This works only on Python 2.7 and throws a warning on every other + # version, but seems otherwise harmless. + --enable-unicode=ucs4 \ + --with-system-ffi \ + --without-ensurepip \ + && make -j$(nproc) \ + && make install \ + && ldconfig \ + ; done \ + && rm -rf "${GNUPGHOME}" \ + && rm -rf /usr/src/python* \ + && rm -rf ~/.cache/ + +RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ + && python3.7 /tmp/get-pip.py \ + && python3.8 /tmp/get-pip.py \ + && rm /tmp/get-pip.py + +CMD ["python3.7"] diff --git a/.kokoro/docker/docs/fetch_gpg_keys.sh b/.kokoro/docker/docs/fetch_gpg_keys.sh new file mode 100755 index 00000000..d653dd86 --- /dev/null +++ b/.kokoro/docker/docs/fetch_gpg_keys.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A script to fetch gpg keys with retry. +# Avoid jinja parsing the file. +# + +function retry { + if [[ "${#}" -le 1 ]]; then + echo "Usage: ${0} retry_count commands.." + exit 1 + fi + local retries=${1} + local command="${@:2}" + until [[ "${retries}" -le 0 ]]; do + $command && return 0 + if [[ $? -ne 0 ]]; then + echo "command failed, retrying" + ((retries--)) + fi + done + return 1 +} + +# 3.6.9, 3.7.5 (Ned Deily) +retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ + 0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D + +# 3.8.0 (Ɓukasz Langa) +retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ + E3FF2839C048B25C084DEBE9B26995E310250568 + +# diff --git a/.kokoro/docs/common.cfg b/.kokoro/docs/common.cfg index 56f2f1ac..3baaac83 100644 --- a/.kokoro/docs/common.cfg +++ b/.kokoro/docs/common.cfg @@ -11,12 +11,12 @@ action { gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" # Use the trampoline script to run in docker. -build_file: "python-iot/.kokoro/trampoline.sh" +build_file: "python-iot/.kokoro/trampoline_v2.sh" # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" + value: "gcr.io/cloud-devrel-kokoro-resources/python-lib-docs" } env_vars: { key: "TRAMPOLINE_BUILD_FILE" @@ -28,6 +28,23 @@ env_vars: { value: "docs-staging" } +env_vars: { + key: "V2_STAGING_BUCKET" + value: "docs-staging-v2-staging" +} + +# It will upload the docker image after successful builds. +env_vars: { + key: "TRAMPOLINE_IMAGE_UPLOAD" + value: "true" +} + +# It will always build the docker image. +env_vars: { + key: "TRAMPOLINE_DOCKERFILE" + value: ".kokoro/docker/docs/Dockerfile" +} + # Fetch the token needed for reporting release status to GitHub before_action { fetch_keystore { diff --git a/.kokoro/docs/docs-presubmit.cfg b/.kokoro/docs/docs-presubmit.cfg new file mode 100644 index 00000000..11181078 --- /dev/null +++ b/.kokoro/docs/docs-presubmit.cfg @@ -0,0 +1,17 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "STAGING_BUCKET" + value: "gcloud-python-test" +} + +env_vars: { + key: "V2_STAGING_BUCKET" + value: "gcloud-python-test" +} + +# We only upload the image in the main `docs` build. +env_vars: { + key: "TRAMPOLINE_IMAGE_UPLOAD" + value: "false" +} diff --git a/.kokoro/publish-docs.sh b/.kokoro/publish-docs.sh index 6b91ee5f..8acb14e8 100755 --- a/.kokoro/publish-docs.sh +++ b/.kokoro/publish-docs.sh @@ -18,26 +18,16 @@ set -eo pipefail # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 -cd github/python-iot - -# Remove old nox -python3.6 -m pip uninstall --yes --quiet nox-automation +export PATH="${HOME}/.local/bin:${PATH}" # Install nox -python3.6 -m pip install --upgrade --quiet nox -python3.6 -m nox --version +python3 -m pip install --user --upgrade --quiet nox +python3 -m nox --version # build docs nox -s docs -python3 -m pip install gcp-docuploader - -# install a json parser -sudo apt-get update -sudo apt-get -y install software-properties-common -sudo add-apt-repository universe -sudo apt-get update -sudo apt-get -y install jq +python3 -m pip install --user gcp-docuploader # create metadata python3 -m docuploader create-metadata \ @@ -52,4 +42,23 @@ python3 -m docuploader create-metadata \ cat docs.metadata # upload docs -python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket docs-staging +python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}" + + +# docfx yaml files +nox -s docfx + +# create metadata. +python3 -m docuploader create-metadata \ + --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ + --version=$(python3 setup.py --version) \ + --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ + --distribution-name=$(python3 setup.py --name) \ + --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ + --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ + --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) + +cat docs.metadata + +# upload docs +python3 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}" diff --git a/.kokoro/trampoline_v2.sh b/.kokoro/trampoline_v2.sh new file mode 100755 index 00000000..719bcd5b --- /dev/null +++ b/.kokoro/trampoline_v2.sh @@ -0,0 +1,487 @@ +#!/usr/bin/env bash +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# trampoline_v2.sh +# +# This script does 3 things. +# +# 1. Prepare the Docker image for the test +# 2. Run the Docker with appropriate flags to run the test +# 3. Upload the newly built Docker image +# +# in a way that is somewhat compatible with trampoline_v1. +# +# To run this script, first download few files from gcs to /dev/shm. +# (/dev/shm is passed into the container as KOKORO_GFILE_DIR). +# +# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/secrets_viewer_service_account.json /dev/shm +# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/automl_secrets.txt /dev/shm +# +# Then run the script. +# .kokoro/trampoline_v2.sh +# +# These environment variables are required: +# TRAMPOLINE_IMAGE: The docker image to use. +# TRAMPOLINE_DOCKERFILE: The location of the Dockerfile. +# +# You can optionally change these environment variables: +# TRAMPOLINE_IMAGE_UPLOAD: +# (true|false): Whether to upload the Docker image after the +# successful builds. +# TRAMPOLINE_BUILD_FILE: The script to run in the docker container. +# TRAMPOLINE_WORKSPACE: The workspace path in the docker container. +# Defaults to /workspace. +# Potentially there are some repo specific envvars in .trampolinerc in +# the project root. + + +set -euo pipefail + +TRAMPOLINE_VERSION="2.0.5" + +if command -v tput >/dev/null && [[ -n "${TERM:-}" ]]; then + readonly IO_COLOR_RED="$(tput setaf 1)" + readonly IO_COLOR_GREEN="$(tput setaf 2)" + readonly IO_COLOR_YELLOW="$(tput setaf 3)" + readonly IO_COLOR_RESET="$(tput sgr0)" +else + readonly IO_COLOR_RED="" + readonly IO_COLOR_GREEN="" + readonly IO_COLOR_YELLOW="" + readonly IO_COLOR_RESET="" +fi + +function function_exists { + [ $(LC_ALL=C type -t $1)"" == "function" ] +} + +# Logs a message using the given color. The first argument must be one +# of the IO_COLOR_* variables defined above, such as +# "${IO_COLOR_YELLOW}". The remaining arguments will be logged in the +# given color. The log message will also have an RFC-3339 timestamp +# prepended (in UTC). You can disable the color output by setting +# TERM=vt100. +function log_impl() { + local color="$1" + shift + local timestamp="$(date -u "+%Y-%m-%dT%H:%M:%SZ")" + echo "================================================================" + echo "${color}${timestamp}:" "$@" "${IO_COLOR_RESET}" + echo "================================================================" +} + +# Logs the given message with normal coloring and a timestamp. +function log() { + log_impl "${IO_COLOR_RESET}" "$@" +} + +# Logs the given message in green with a timestamp. +function log_green() { + log_impl "${IO_COLOR_GREEN}" "$@" +} + +# Logs the given message in yellow with a timestamp. +function log_yellow() { + log_impl "${IO_COLOR_YELLOW}" "$@" +} + +# Logs the given message in red with a timestamp. +function log_red() { + log_impl "${IO_COLOR_RED}" "$@" +} + +readonly tmpdir=$(mktemp -d -t ci-XXXXXXXX) +readonly tmphome="${tmpdir}/h" +mkdir -p "${tmphome}" + +function cleanup() { + rm -rf "${tmpdir}" +} +trap cleanup EXIT + +RUNNING_IN_CI="${RUNNING_IN_CI:-false}" + +# The workspace in the container, defaults to /workspace. +TRAMPOLINE_WORKSPACE="${TRAMPOLINE_WORKSPACE:-/workspace}" + +pass_down_envvars=( + # TRAMPOLINE_V2 variables. + # Tells scripts whether they are running as part of CI or not. + "RUNNING_IN_CI" + # Indicates which CI system we're in. + "TRAMPOLINE_CI" + # Indicates the version of the script. + "TRAMPOLINE_VERSION" +) + +log_yellow "Building with Trampoline ${TRAMPOLINE_VERSION}" + +# Detect which CI systems we're in. If we're in any of the CI systems +# we support, `RUNNING_IN_CI` will be true and `TRAMPOLINE_CI` will be +# the name of the CI system. Both envvars will be passing down to the +# container for telling which CI system we're in. +if [[ -n "${KOKORO_BUILD_ID:-}" ]]; then + # descriptive env var for indicating it's on CI. + RUNNING_IN_CI="true" + TRAMPOLINE_CI="kokoro" + if [[ "${TRAMPOLINE_USE_LEGACY_SERVICE_ACCOUNT:-}" == "true" ]]; then + if [[ ! -f "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" ]]; then + log_red "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json does not exist. Did you forget to mount cloud-devrel-kokoro-resources/trampoline? Aborting." + exit 1 + fi + # This service account will be activated later. + TRAMPOLINE_SERVICE_ACCOUNT="${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" + else + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + gcloud auth list + fi + log_yellow "Configuring Container Registry access" + gcloud auth configure-docker --quiet + fi + pass_down_envvars+=( + # KOKORO dynamic variables. + "KOKORO_BUILD_NUMBER" + "KOKORO_BUILD_ID" + "KOKORO_JOB_NAME" + "KOKORO_GIT_COMMIT" + "KOKORO_GITHUB_COMMIT" + "KOKORO_GITHUB_PULL_REQUEST_NUMBER" + "KOKORO_GITHUB_PULL_REQUEST_COMMIT" + # For Build Cop Bot + "KOKORO_GITHUB_COMMIT_URL" + "KOKORO_GITHUB_PULL_REQUEST_URL" + ) +elif [[ "${TRAVIS:-}" == "true" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="travis" + pass_down_envvars+=( + "TRAVIS_BRANCH" + "TRAVIS_BUILD_ID" + "TRAVIS_BUILD_NUMBER" + "TRAVIS_BUILD_WEB_URL" + "TRAVIS_COMMIT" + "TRAVIS_COMMIT_MESSAGE" + "TRAVIS_COMMIT_RANGE" + "TRAVIS_JOB_NAME" + "TRAVIS_JOB_NUMBER" + "TRAVIS_JOB_WEB_URL" + "TRAVIS_PULL_REQUEST" + "TRAVIS_PULL_REQUEST_BRANCH" + "TRAVIS_PULL_REQUEST_SHA" + "TRAVIS_PULL_REQUEST_SLUG" + "TRAVIS_REPO_SLUG" + "TRAVIS_SECURE_ENV_VARS" + "TRAVIS_TAG" + ) +elif [[ -n "${GITHUB_RUN_ID:-}" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="github-workflow" + pass_down_envvars+=( + "GITHUB_WORKFLOW" + "GITHUB_RUN_ID" + "GITHUB_RUN_NUMBER" + "GITHUB_ACTION" + "GITHUB_ACTIONS" + "GITHUB_ACTOR" + "GITHUB_REPOSITORY" + "GITHUB_EVENT_NAME" + "GITHUB_EVENT_PATH" + "GITHUB_SHA" + "GITHUB_REF" + "GITHUB_HEAD_REF" + "GITHUB_BASE_REF" + ) +elif [[ "${CIRCLECI:-}" == "true" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="circleci" + pass_down_envvars+=( + "CIRCLE_BRANCH" + "CIRCLE_BUILD_NUM" + "CIRCLE_BUILD_URL" + "CIRCLE_COMPARE_URL" + "CIRCLE_JOB" + "CIRCLE_NODE_INDEX" + "CIRCLE_NODE_TOTAL" + "CIRCLE_PREVIOUS_BUILD_NUM" + "CIRCLE_PROJECT_REPONAME" + "CIRCLE_PROJECT_USERNAME" + "CIRCLE_REPOSITORY_URL" + "CIRCLE_SHA1" + "CIRCLE_STAGE" + "CIRCLE_USERNAME" + "CIRCLE_WORKFLOW_ID" + "CIRCLE_WORKFLOW_JOB_ID" + "CIRCLE_WORKFLOW_UPSTREAM_JOB_IDS" + "CIRCLE_WORKFLOW_WORKSPACE_ID" + ) +fi + +# Configure the service account for pulling the docker image. +function repo_root() { + local dir="$1" + while [[ ! -d "${dir}/.git" ]]; do + dir="$(dirname "$dir")" + done + echo "${dir}" +} + +# Detect the project root. In CI builds, we assume the script is in +# the git tree and traverse from there, otherwise, traverse from `pwd` +# to find `.git` directory. +if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + PROGRAM_PATH="$(realpath "$0")" + PROGRAM_DIR="$(dirname "${PROGRAM_PATH}")" + PROJECT_ROOT="$(repo_root "${PROGRAM_DIR}")" +else + PROJECT_ROOT="$(repo_root $(pwd))" +fi + +log_yellow "Changing to the project root: ${PROJECT_ROOT}." +cd "${PROJECT_ROOT}" + +# To support relative path for `TRAMPOLINE_SERVICE_ACCOUNT`, we need +# to use this environment variable in `PROJECT_ROOT`. +if [[ -n "${TRAMPOLINE_SERVICE_ACCOUNT:-}" ]]; then + + mkdir -p "${tmpdir}/gcloud" + gcloud_config_dir="${tmpdir}/gcloud" + + log_yellow "Using isolated gcloud config: ${gcloud_config_dir}." + export CLOUDSDK_CONFIG="${gcloud_config_dir}" + + log_yellow "Using ${TRAMPOLINE_SERVICE_ACCOUNT} for authentication." + gcloud auth activate-service-account \ + --key-file "${TRAMPOLINE_SERVICE_ACCOUNT}" + log_yellow "Configuring Container Registry access" + gcloud auth configure-docker --quiet +fi + +required_envvars=( + # The basic trampoline configurations. + "TRAMPOLINE_IMAGE" + "TRAMPOLINE_BUILD_FILE" +) + +if [[ -f "${PROJECT_ROOT}/.trampolinerc" ]]; then + source "${PROJECT_ROOT}/.trampolinerc" +fi + +log_yellow "Checking environment variables." +for e in "${required_envvars[@]}" +do + if [[ -z "${!e:-}" ]]; then + log "Missing ${e} env var. Aborting." + exit 1 + fi +done + +# We want to support legacy style TRAMPOLINE_BUILD_FILE used with V1 +# script: e.g. "github/repo-name/.kokoro/run_tests.sh" +TRAMPOLINE_BUILD_FILE="${TRAMPOLINE_BUILD_FILE#github/*/}" +log_yellow "Using TRAMPOLINE_BUILD_FILE: ${TRAMPOLINE_BUILD_FILE}" + +# ignore error on docker operations and test execution +set +e + +log_yellow "Preparing Docker image." +# We only download the docker image in CI builds. +if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + # Download the docker image specified by `TRAMPOLINE_IMAGE` + + # We may want to add --max-concurrent-downloads flag. + + log_yellow "Start pulling the Docker image: ${TRAMPOLINE_IMAGE}." + if docker pull "${TRAMPOLINE_IMAGE}"; then + log_green "Finished pulling the Docker image: ${TRAMPOLINE_IMAGE}." + has_image="true" + else + log_red "Failed pulling the Docker image: ${TRAMPOLINE_IMAGE}." + has_image="false" + fi +else + # For local run, check if we have the image. + if docker images "${TRAMPOLINE_IMAGE}:latest" | grep "${TRAMPOLINE_IMAGE}"; then + has_image="true" + else + has_image="false" + fi +fi + + +# The default user for a Docker container has uid 0 (root). To avoid +# creating root-owned files in the build directory we tell docker to +# use the current user ID. +user_uid="$(id -u)" +user_gid="$(id -g)" +user_name="$(id -un)" + +# To allow docker in docker, we add the user to the docker group in +# the host os. +docker_gid=$(cut -d: -f3 < <(getent group docker)) + +update_cache="false" +if [[ "${TRAMPOLINE_DOCKERFILE:-none}" != "none" ]]; then + # Build the Docker image from the source. + context_dir=$(dirname "${TRAMPOLINE_DOCKERFILE}") + docker_build_flags=( + "-f" "${TRAMPOLINE_DOCKERFILE}" + "-t" "${TRAMPOLINE_IMAGE}" + "--build-arg" "UID=${user_uid}" + "--build-arg" "USERNAME=${user_name}" + ) + if [[ "${has_image}" == "true" ]]; then + docker_build_flags+=("--cache-from" "${TRAMPOLINE_IMAGE}") + fi + + log_yellow "Start building the docker image." + if [[ "${TRAMPOLINE_VERBOSE:-false}" == "true" ]]; then + echo "docker build" "${docker_build_flags[@]}" "${context_dir}" + fi + + # ON CI systems, we want to suppress docker build logs, only + # output the logs when it fails. + if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + if docker build "${docker_build_flags[@]}" "${context_dir}" \ + > "${tmpdir}/docker_build.log" 2>&1; then + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + cat "${tmpdir}/docker_build.log" + fi + + log_green "Finished building the docker image." + update_cache="true" + else + log_red "Failed to build the Docker image, aborting." + log_yellow "Dumping the build logs:" + cat "${tmpdir}/docker_build.log" + exit 1 + fi + else + if docker build "${docker_build_flags[@]}" "${context_dir}"; then + log_green "Finished building the docker image." + update_cache="true" + else + log_red "Failed to build the Docker image, aborting." + exit 1 + fi + fi +else + if [[ "${has_image}" != "true" ]]; then + log_red "We do not have ${TRAMPOLINE_IMAGE} locally, aborting." + exit 1 + fi +fi + +# We use an array for the flags so they are easier to document. +docker_flags=( + # Remove the container after it exists. + "--rm" + + # Use the host network. + "--network=host" + + # Run in priviledged mode. We are not using docker for sandboxing or + # isolation, just for packaging our dev tools. + "--privileged" + + # Run the docker script with the user id. Because the docker image gets to + # write in ${PWD} you typically want this to be your user id. + # To allow docker in docker, we need to use docker gid on the host. + "--user" "${user_uid}:${docker_gid}" + + # Pass down the USER. + "--env" "USER=${user_name}" + + # Mount the project directory inside the Docker container. + "--volume" "${PROJECT_ROOT}:${TRAMPOLINE_WORKSPACE}" + "--workdir" "${TRAMPOLINE_WORKSPACE}" + "--env" "PROJECT_ROOT=${TRAMPOLINE_WORKSPACE}" + + # Mount the temporary home directory. + "--volume" "${tmphome}:/h" + "--env" "HOME=/h" + + # Allow docker in docker. + "--volume" "/var/run/docker.sock:/var/run/docker.sock" + + # Mount the /tmp so that docker in docker can mount the files + # there correctly. + "--volume" "/tmp:/tmp" + # Pass down the KOKORO_GFILE_DIR and KOKORO_KEYSTORE_DIR + # TODO(tmatsuo): This part is not portable. + "--env" "TRAMPOLINE_SECRET_DIR=/secrets" + "--volume" "${KOKORO_GFILE_DIR:-/dev/shm}:/secrets/gfile" + "--env" "KOKORO_GFILE_DIR=/secrets/gfile" + "--volume" "${KOKORO_KEYSTORE_DIR:-/dev/shm}:/secrets/keystore" + "--env" "KOKORO_KEYSTORE_DIR=/secrets/keystore" +) + +# Add an option for nicer output if the build gets a tty. +if [[ -t 0 ]]; then + docker_flags+=("-it") +fi + +# Passing down env vars +for e in "${pass_down_envvars[@]}" +do + if [[ -n "${!e:-}" ]]; then + docker_flags+=("--env" "${e}=${!e}") + fi +done + +# If arguments are given, all arguments will become the commands run +# in the container, otherwise run TRAMPOLINE_BUILD_FILE. +if [[ $# -ge 1 ]]; then + log_yellow "Running the given commands '" "${@:1}" "' in the container." + readonly commands=("${@:1}") + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" + fi + docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" +else + log_yellow "Running the tests in a Docker container." + docker_flags+=("--entrypoint=${TRAMPOLINE_BUILD_FILE}") + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" + fi + docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" +fi + + +test_retval=$? + +if [[ ${test_retval} -eq 0 ]]; then + log_green "Build finished with ${test_retval}" +else + log_red "Build finished with ${test_retval}" +fi + +# Only upload it when the test passes. +if [[ "${update_cache}" == "true" ]] && \ + [[ $test_retval == 0 ]] && \ + [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]]; then + log_yellow "Uploading the Docker image." + if docker push "${TRAMPOLINE_IMAGE}"; then + log_green "Finished uploading the Docker image." + else + log_red "Failed uploading the Docker image." + fi + # Call trampoline_after_upload_hook if it's defined. + if function_exists trampoline_after_upload_hook; then + trampoline_after_upload_hook + fi + +fi + +exit "${test_retval}" diff --git a/.trampolinerc b/.trampolinerc new file mode 100644 index 00000000..995ee291 --- /dev/null +++ b/.trampolinerc @@ -0,0 +1,51 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Template for .trampolinerc + +# Add required env vars here. +required_envvars+=( + "STAGING_BUCKET" + "V2_STAGING_BUCKET" +) + +# Add env vars which are passed down into the container here. +pass_down_envvars+=( + "STAGING_BUCKET" + "V2_STAGING_BUCKET" +) + +# Prevent unintentional override on the default image. +if [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]] && \ + [[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then + echo "Please set TRAMPOLINE_IMAGE if you want to upload the Docker image." + exit 1 +fi + +# Define the default value if it makes sense. +if [[ -z "${TRAMPOLINE_IMAGE_UPLOAD:-}" ]]; then + TRAMPOLINE_IMAGE_UPLOAD="" +fi + +if [[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then + TRAMPOLINE_IMAGE="" +fi + +if [[ -z "${TRAMPOLINE_DOCKERFILE:-}" ]]; then + TRAMPOLINE_DOCKERFILE="" +fi + +if [[ -z "${TRAMPOLINE_BUILD_FILE:-}" ]]; then + TRAMPOLINE_BUILD_FILE="" +fi diff --git a/docs/conf.py b/docs/conf.py index 94f74897..9bb87a0a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,6 +20,10 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath("..")) +# For plugins that can not read conf.py. +# See also: https://github.com/docascode/sphinx-docfx-yaml/issues/85 +sys.path.insert(0, os.path.abspath(".")) + __version__ = "" # -- General configuration ------------------------------------------------ @@ -90,7 +94,12 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ["_build"] +exclude_patterns = [ + "_build", + "samples/AUTHORING_GUIDE.md", + "samples/CONTRIBUTING.md", + "samples/snippets/README.rst", +] # The reST default role (used for this markup: `text`) to use for all # documents. diff --git a/noxfile.py b/noxfile.py index 66fcfd05..bc20bc17 100644 --- a/noxfile.py +++ b/noxfile.py @@ -100,6 +100,10 @@ def system(session): """Run the system test suite.""" system_test_path = os.path.join("tests", "system.py") system_test_folder_path = os.path.join("tests", "system") + + # Check the value of `RUN_SYSTEM_TESTS` env var. It defaults to true. + if os.environ.get("RUN_SYSTEM_TESTS", "true") == "false": + session.skip("RUN_SYSTEM_TESTS is set to false, skipping") # Sanity check: Only run tests if the environment variable is set. if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""): session.skip("Credentials must be set via environment variable") @@ -160,3 +164,36 @@ def docs(session): os.path.join("docs", ""), os.path.join("docs", "_build", "html", ""), ) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def docfx(session): + """Build the docfx yaml files for this library.""" + + session.install("-e", ".") + session.install("sphinx<3.0.0", "alabaster", "recommonmark", "sphinx-docfx-yaml") + + shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) + session.run( + "sphinx-build", + "-T", # show full traceback on exception + "-N", # no colors + "-D", + ( + "extensions=sphinx.ext.autodoc," + "sphinx.ext.autosummary," + "docfx_yaml.extension," + "sphinx.ext.intersphinx," + "sphinx.ext.coverage," + "sphinx.ext.napoleon," + "sphinx.ext.todo," + "sphinx.ext.viewcode," + "recommonmark" + ), + "-b", + "html", + "-d", + os.path.join("docs", "_build", "doctrees", ""), + os.path.join("docs", ""), + os.path.join("docs", "_build", "html", ""), + ) diff --git a/samples/AUTHORING_GUIDE.md b/samples/AUTHORING_GUIDE.md new file mode 100644 index 00000000..55c97b32 --- /dev/null +++ b/samples/AUTHORING_GUIDE.md @@ -0,0 +1 @@ +See https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/AUTHORING_GUIDE.md \ No newline at end of file diff --git a/samples/CONTRIBUTING.md b/samples/CONTRIBUTING.md new file mode 100644 index 00000000..34c882b6 --- /dev/null +++ b/samples/CONTRIBUTING.md @@ -0,0 +1 @@ +See https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/CONTRIBUTING.md \ No newline at end of file diff --git a/samples/api-client/manager/README.rst b/samples/api-client/manager/README.rst new file mode 100644 index 00000000..08ea4dce --- /dev/null +++ b/samples/api-client/manager/README.rst @@ -0,0 +1,198 @@ + +.. This file is automatically generated. Do not edit this file directly. + +Google Cloud IoT Core Python Samples +=============================================================================== + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=iot/api-client/manager/README.rst + + +This directory contains samples for Google Cloud IoT Core. `Google Cloud IoT Core`_ allows developers to easily integrate Publish and Subscribe functionality with devices and programmatically manage device authorization. + + + + +.. _Google Cloud IoT Core: https://cloud.google.com/iot/docs + + +Setup +------------------------------------------------------------------------------- + + + +Authentication +++++++++++++++ + +This sample requires you to have authentication setup. Refer to the +`Authentication Getting Started Guide`_ for instructions on setting up +credentials for applications. + +.. _Authentication Getting Started Guide: + https://cloud.google.com/docs/authentication/getting-started + + + + +Install Dependencies +++++++++++++++++++++ + +#. Clone python-docs-samples and change directory to the sample directory you want to use. + + .. code-block:: bash + + $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git + +#. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. + + .. _Python Development Environment Setup Guide: + https://cloud.google.com/python/setup + +#. Create a virtualenv. Samples are compatible with Python 3.6+. + + .. code-block:: bash + + $ virtualenv env + $ source env/bin/activate + +#. Install the dependencies needed to run the samples. + + .. code-block:: bash + + $ pip install -r requirements.txt + +.. _pip: https://pip.pypa.io/ +.. _virtualenv: https://virtualenv.pypa.io/ + + + + + + +Samples +------------------------------------------------------------------------------- + + +Manager ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=iot/api-client/manager/manager.py,iot/api-client/manager/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python manager.py + + + usage: manager.py [-h] [--algorithm {RS256,ES256}] + [--certificate_path CERTIFICATE_PATH] + [--cloud_region CLOUD_REGION] [--pubsub_topic PUBSUB_TOPIC] + [--config CONFIG] [--device_id DEVICE_ID] + [--ec_public_key_file EC_PUBLIC_KEY_FILE] + [--gateway_id GATEWAY_ID] [--member MEMBER] [--role ROLE] + [--send_command SEND_COMMAND] [--project_id PROJECT_ID] + [--registry_id REGISTRY_ID] + [--rsa_certificate_file RSA_CERTIFICATE_FILE] + [--service_account_json SERVICE_ACCOUNT_JSON] + [--version VERSION] + {bind-device-to-gateway,create-es256,create-gateway,create-registry,create-rsa256,create-topic,create-unauth,delete-device,delete-registry,get,get-config-versions,get-iam-permissions,get-registry,get-state,list,list-devices-for-gateway,list-gateways,list-registries,patch-es256,patch-rs256,send-command,set-config,set-iam-permissions,unbind-device-from-gateway} + ... + + Example of using the Google Cloud IoT Core device manager to administer + devices. + + Usage example: + + python manager.py \ + --project_id=my-project-id \ + --cloud_region=us-central1 \ + --service_account_json=$HOME/service_account.json \ + list-registries + + positional arguments: + {bind-device-to-gateway,create-es256,create-gateway,create-registry,create-rsa256,create-topic,create-unauth,delete-device,delete-registry,get,get-config-versions,get-iam-permissions,get-registry,get-state,list,list-devices-for-gateway,list-gateways,list-registries,patch-es256,patch-rs256,send-command,set-config,set-iam-permissions,unbind-device-from-gateway} + bind-device-to-gateway + Binds a device to a gateway. + create-es256 Create a new device with the given id, using ES256 for + authentication. + create-gateway Create a gateway to bind devices to. + create-registry Gets or creates a device registry. + create-rsa256 Create a new device with the given id, using RS256 for + authentication. + create-topic Creates a PubSub Topic and grants access to Cloud IoT + Core. + create-unauth Create a new device without authentication. + delete-device Delete the device with the given id. + delete-registry Deletes the specified registry. + get Retrieve the device with the given id. + get-config-versions + Lists versions of a device config in descending order + (newest first). + get-iam-permissions + Retrieves IAM permissions for the given registry. + get-registry Retrieves a device registry. + get-state Retrieve a device's state blobs. + list List all devices in the registry. + list-devices-for-gateway + List devices bound to a gateway + list-gateways Lists gateways in a registry + list-registries List all registries in the project. + patch-es256 Patch the device to add an ES256 public key to the + device. + patch-rs256 Patch the device to add an RSA256 public key to the + device. + send-command Send a command to a device. + set-config Patch the device to add an RSA256 public key to the + device. + set-iam-permissions + Sets IAM permissions for the given registry to a + single role/member. + unbind-device-from-gateway + Unbinds a device to a gateway. + + optional arguments: + -h, --help show this help message and exit + --algorithm {RS256,ES256} + Which encryption algorithm to use to generate the JWT. + --certificate_path CERTIFICATE_PATH + Path to public certificate. + --cloud_region CLOUD_REGION + GCP cloud region + --pubsub_topic PUBSUB_TOPIC + Google Cloud Pub/Sub topic. Format is + projects/project_id/topics/topic-id + --config CONFIG Configuration sent to a device. + --device_id DEVICE_ID + Device id. + --ec_public_key_file EC_PUBLIC_KEY_FILE + Path to public ES256 key file. + --gateway_id GATEWAY_ID + Gateway identifier. + --member MEMBER Member used for IAM commands. + --role ROLE Role used for IAM commands. + --send_command SEND_COMMAND + The command sent to the device + --project_id PROJECT_ID + GCP cloud project name. + --registry_id REGISTRY_ID + Registry id. If not set, a name will be generated. + --rsa_certificate_file RSA_CERTIFICATE_FILE + Path to RS256 certificate file. + --service_account_json SERVICE_ACCOUNT_JSON + Path to service account json file. + --version VERSION Version number for setting device configuration. + + + + + + + + + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ diff --git a/samples/api-client/manager/README.rst.in b/samples/api-client/manager/README.rst.in new file mode 100644 index 00000000..8debfbce --- /dev/null +++ b/samples/api-client/manager/README.rst.in @@ -0,0 +1,23 @@ +# This file is used to generate README.rst + +product: + name: Google Cloud IoT Core + short_name: Cloud IoT Core + url: https://cloud.google.com/iot/docs + description: > + `Google Cloud IoT Core`_ allows developers to easily integrate Publish and + Subscribe functionality with devices and programmatically manage device + authorization. + +setup: +- auth +- install_deps + +samples: +- name: Manager + file: manager.py + show_help: True + +cloud_client_library: false + +folder: iot/api-client/manager diff --git a/samples/api-client/manager/manager.py b/samples/api-client/manager/manager.py new file mode 100644 index 00000000..1701940b --- /dev/null +++ b/samples/api-client/manager/manager.py @@ -0,0 +1,1041 @@ +#!/usr/bin/env python + +# Copyright 2017 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +""" +Example of using the Google Cloud IoT Core device manager to administer +devices. + +Usage example: + + python manager.py \\ + --project_id=my-project-id \\ + --cloud_region=us-central1 \\ + --service_account_json=$HOME/service_account.json \\ + list-registries +""" + +import argparse +import io +import os +import sys +import time + +from google.api_core.exceptions import AlreadyExists +from google.cloud import iot_v1 +from google.cloud import pubsub +from google.oauth2 import service_account +from googleapiclient import discovery +from googleapiclient.errors import HttpError + + +def create_iot_topic(project, topic_name): + """Creates a PubSub Topic and grants access to Cloud IoT Core.""" + pubsub_client = pubsub.PublisherClient() + topic_path = pubsub_client.topic_path(project, topic_name) + + topic = pubsub_client.create_topic(topic_path) + policy = pubsub_client.get_iam_policy(topic_path) + + policy.bindings.add( + role='roles/pubsub.publisher', + members=['serviceAccount:cloud-iot@system.gserviceaccount.com']) + + pubsub_client.set_iam_policy(topic_path, policy) + + return topic + + +def get_client(service_account_json): + """Returns an authorized API client by discovering the IoT API and creating + a service object using the service account credentials JSON.""" + api_scopes = ['https://www.googleapis.com/auth/cloud-platform'] + api_version = 'v1' + discovery_api = 'https://cloudiot.googleapis.com/$discovery/rest' + service_name = 'cloudiotcore' + + credentials = service_account.Credentials.from_service_account_file( + service_account_json) + scoped_credentials = credentials.with_scopes(api_scopes) + + discovery_url = '{}?version={}'.format( + discovery_api, api_version) + + return discovery.build( + service_name, + api_version, + discoveryServiceUrl=discovery_url, + credentials=scoped_credentials) + + +def create_rs256_device( + service_account_json, project_id, cloud_region, registry_id, device_id, + certificate_file): + """Create a new device with the given id, using RS256 for + authentication.""" + # [START iot_create_rsa_device] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + # certificate_file = 'path/to/certificate.pem' + + client = iot_v1.DeviceManagerClient() + + parent = client.registry_path(project_id, cloud_region, registry_id) + + with io.open(certificate_file) as f: + certificate = f.read() + + # Note: You can have multiple credentials associated with a device. + device_template = { + 'id': device_id, + 'credentials': [{ + 'public_key': { + 'format': 'RSA_X509_PEM', + 'key': certificate + } + }] + } + + return client.create_device(parent, device_template) + # [END iot_create_rsa_device] + + +def create_es256_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, public_key_file): + """Create a new device with the given id, using ES256 for + authentication.""" + # [START iot_create_es_device] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + # public_key_file = 'path/to/certificate.pem' + + client = iot_v1.DeviceManagerClient() + + parent = client.registry_path(project_id, cloud_region, registry_id) + + with io.open(public_key_file) as f: + public_key = f.read() + + # Note: You can have multiple credentials associated with a device. + device_template = { + 'id': device_id, + 'credentials': [{ + 'public_key': { + 'format': 'ES256_PEM', + 'key': public_key + } + }] + } + + return client.create_device(parent, device_template) + # [END iot_create_es_device] + + +def create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id): + """Create a device to bind to a gateway if it does not exist.""" + # [START iot_create_device] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + + # Check that the device doesn't already exist + client = iot_v1.DeviceManagerClient() + + exists = False + + parent = client.registry_path(project_id, cloud_region, registry_id) + + devices = list(client.list_devices(parent=parent)) + + for device in devices: + if device.id == device_id: + exists = True + + # Create the device + device_template = { + 'id': device_id, + 'gateway_config': { + 'gateway_type': 'NON_GATEWAY', + 'gateway_auth_method': 'ASSOCIATION_ONLY' + } + } + + if not exists: + res = client.create_device(parent, device_template) + print('Created Device {}'.format(res)) + else: + print('Device exists, skipping') + # [END iot_create_device] + + +def create_unauth_device( + service_account_json, project_id, cloud_region, registry_id, + device_id): + """Create a new device without authentication.""" + # [START iot_create_unauth_device] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + client = iot_v1.DeviceManagerClient() + + parent = client.registry_path(project_id, cloud_region, registry_id) + + device_template = { + 'id': device_id, + } + + return client.create_device(parent, device_template) + # [END iot_create_unauth_device] + + +def delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id): + """Delete the device with the given id.""" + # [START iot_delete_device] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + print('Delete device') + client = iot_v1.DeviceManagerClient() + + device_path = client.device_path( + project_id, cloud_region, registry_id, device_id) + + return client.delete_device(device_path) + # [END iot_delete_device] + + +def delete_registry( + service_account_json, project_id, cloud_region, registry_id): + """Deletes the specified registry.""" + # [START iot_delete_registry] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + print('Delete registry') + + client = iot_v1.DeviceManagerClient() + registry_path = client.registry_path(project_id, cloud_region, registry_id) + + try: + client.delete_device_registry(registry_path) + print('Deleted registry') + return 'Registry deleted' + except HttpError: + print('Error, registry not deleted') + raise + # [END iot_delete_registry] + + +def get_device( + service_account_json, project_id, cloud_region, registry_id, + device_id): + """Retrieve the device with the given id.""" + # [START iot_get_device] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + print('Getting device') + client = iot_v1.DeviceManagerClient() + device_path = client.device_path( + project_id, cloud_region, registry_id, device_id) + + device = client.get_device(device_path) + + print('Id : {}'.format(device.id)) + print('Name : {}'.format(device.name)) + print('Credentials:') + + if device.credentials is not None: + for credential in device.credentials: + keyinfo = credential.public_key + print('\tcertificate: \n{}'.format(keyinfo.key)) + + if keyinfo.format == 4: + keyformat = 'ES256_X509_PEM' + elif keyinfo.format == 3: + keyformat = 'RSA_PEM' + elif keyinfo.format == 2: + keyformat = 'ES256_PEM' + elif keyinfo.format == 1: + keyformat = 'RSA_X509_PEM' + else: + keyformat = 'UNSPECIFIED_PUBLIC_KEY_FORMAT' + print('\tformat : {}'.format(keyformat)) + print('\texpiration: {}'.format(credential.expiration_time)) + + print('Config:') + print('\tdata: {}'.format(device.config.binary_data)) + print('\tversion: {}'.format(device.config.version)) + print('\tcloudUpdateTime: {}'.format(device.config.cloud_update_time)) + + return device + # [END iot_get_device] + + +def get_state( + service_account_json, project_id, cloud_region, registry_id, + device_id): + """Retrieve a device's state blobs.""" + # [START iot_get_device_state] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + client = iot_v1.DeviceManagerClient() + device_path = client.device_path( + project_id, cloud_region, registry_id, device_id) + + device = client.get_device(device_path) + print('Last state: {}'.format(device.state)) + + print('State history') + states = client.list_device_states(device_path).device_states + for state in states: + print('State: {}'.format(state)) + + return states + # [END iot_get_device_state] + + +def list_devices( + service_account_json, project_id, cloud_region, registry_id): + """List all devices in the registry.""" + # [START iot_list_devices] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + print('Listing devices') + + client = iot_v1.DeviceManagerClient() + registry_path = client.registry_path(project_id, cloud_region, registry_id) + + devices = list(client.list_devices(parent=registry_path)) + for device in devices: + print('Device: {} : {}'.format(device.num_id, device.id)) + + return devices + # [END iot_list_devices] + + +def list_registries(service_account_json, project_id, cloud_region): + """List all registries in the project.""" + # [START iot_list_registries] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + print('Listing Registries') + client = iot_v1.DeviceManagerClient() + parent = client.location_path(project_id, cloud_region) + + registries = list(client.list_device_registries(parent)) + for registry in registries: + print('id: {}\n\tname: {}'.format( + registry.id, + registry.name)) + + return registries + # [END iot_list_registries] + + +def create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id): + """ Creates a registry and returns the result. Returns an empty result if + the registry already exists.""" + # [START iot_create_registry] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # pubsub_topic = 'your-pubsub-topic' + # registry_id = 'your-registry-id' + client = iot_v1.DeviceManagerClient() + parent = client.location_path(project_id, cloud_region) + + if not pubsub_topic.startswith('projects/'): + pubsub_topic = 'projects/{}/topics/{}'.format(project_id, pubsub_topic) + + body = { + 'event_notification_configs': [{ + 'pubsub_topic_name': pubsub_topic + }], + 'id': registry_id + } + + try: + response = client.create_device_registry(parent, body) + print('Created registry') + return response + except HttpError: + print('Error, registry not created') + raise + except AlreadyExists: + print('Error, registry already exists') + raise + # [END iot_create_registry] + + +def get_registry( + service_account_json, project_id, cloud_region, registry_id): + """ Retrieves a device registry.""" + # [START iot_get_registry] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + client = iot_v1.DeviceManagerClient() + registry_path = client.registry_path(project_id, cloud_region, registry_id) + + return client.get_device_registry(registry_path) + # [END iot_get_registry] + + +def open_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id): + """Gets or creates a device registry.""" + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # pubsub_topic = 'your-pubsub-topic' + # registry_id = 'your-registry-id' + print('Creating registry') + + try: + response = create_registry( + service_account_json, project_id, cloud_region, + pubsub_topic, registry_id) + except AlreadyExists: + # Device registry already exists. We just re-use the existing one. + print( + 'Registry {} already exists - looking it up instead.'.format( + registry_id)) + response = get_registry( + service_account_json, project_id, cloud_region, + registry_id) + + print('Registry {} opened: '.format(response.name)) + print(response) + + +def patch_es256_auth( + service_account_json, project_id, cloud_region, registry_id, + device_id, public_key_file): + """Patch the device to add an ES256 public key to the device.""" + # [START iot_patch_es] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + # public_key_file = 'path/to/certificate.pem' + print('Patch device with ES256 certificate') + + client = iot_v1.DeviceManagerClient() + device_path = client.device_path( + project_id, cloud_region, registry_id, device_id) + + public_key_bytes = '' + with io.open(public_key_file) as f: + public_key_bytes = f.read() + + key = iot_v1.types.PublicKeyCredential( + format='ES256_PEM', + key=public_key_bytes) + + cred = iot_v1.types.DeviceCredential(public_key=key) + device = client.get_device(device_path) + + device.id = b'' + device.num_id = 0 + device.credentials.append(cred) + + mask = iot_v1.types.FieldMask() + mask.paths.append('credentials') + + return client.update_device( + device=device, + update_mask=mask) + # [END iot_patch_es] + + +def patch_rsa256_auth( + service_account_json, project_id, cloud_region, registry_id, device_id, + public_key_file): + """Patch the device to add an RSA256 public key to the device.""" + # [START iot_patch_rsa] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + # public_key_file = 'path/to/certificate.pem' + print('Patch device with RSA256 certificate') + + client = iot_v1.DeviceManagerClient() + device_path = client.device_path( + project_id, cloud_region, registry_id, device_id) + + public_key_bytes = '' + with io.open(public_key_file) as f: + public_key_bytes = f.read() + + key = iot_v1.types.PublicKeyCredential( + format='RSA_X509_PEM', + key=public_key_bytes) + + cred = iot_v1.types.DeviceCredential(public_key=key) + device = client.get_device(device_path) + + device.id = b'' + device.num_id = 0 + device.credentials.append(cred) + + mask = iot_v1.types.FieldMask() + mask.paths.append('credentials') + + return client.update_device( + device=device, + update_mask=mask) + + # [END iot_patch_rsa] + + +def set_config( + service_account_json, project_id, cloud_region, registry_id, device_id, + version, config): + # [START iot_set_device_config] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + # version = '0' + # config= 'your-config-data' + print('Set device configuration') + client = iot_v1.DeviceManagerClient() + device_path = client.device_path( + project_id, cloud_region, registry_id, device_id) + + data = config.encode('utf-8') + + return client.modify_cloud_to_device_config(device_path, data, version) + # [END iot_set_device_config] + + +def get_config_versions( + service_account_json, project_id, cloud_region, registry_id, + device_id): + """Lists versions of a device config in descending order (newest first).""" + # [START iot_get_device_configs] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + client = iot_v1.DeviceManagerClient() + device_path = client.device_path( + project_id, cloud_region, registry_id, device_id) + + configs = client.list_device_config_versions(device_path) + + for config in configs.device_configs: + print('version: {}\n\tcloudUpdateTime: {}\n\t data: {}'.format( + config.version, + config.cloud_update_time, + config.binary_data)) + + return configs + # [END iot_get_device_configs] + + +def get_iam_permissions( + service_account_json, project_id, cloud_region, registry_id): + """Retrieves IAM permissions for the given registry.""" + # [START iot_get_iam_policy] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + client = iot_v1.DeviceManagerClient() + + registry_path = client.registry_path(project_id, cloud_region, registry_id) + + policy = client.get_iam_policy(registry_path) + + return policy + # [END iot_get_iam_policy] + + +def set_iam_permissions( + service_account_json, project_id, cloud_region, registry_id, role, + member): + """Sets IAM permissions for the given registry to a single role/member.""" + # [START iot_set_iam_policy] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # role = 'viewer' + # member = 'group:dpebot@google.com' + client = iot_v1.DeviceManagerClient() + registry_path = client.registry_path(project_id, cloud_region, registry_id) + + body = { + 'bindings': + [{ + 'members': [member], + 'role': role + }] + } + + return client.set_iam_policy(registry_path, body) + # [END iot_set_iam_policy] + + +def send_command( + service_account_json, project_id, cloud_region, registry_id, device_id, + command): + """Send a command to a device.""" + # [START iot_send_command] + print('Sending command to device') + client = iot_v1.DeviceManagerClient() + device_path = client.device_path( + project_id, cloud_region, registry_id, device_id) + + # command = 'Hello IoT Core!' + data = command.encode('utf-8') + + return client.send_command_to_device(device_path, data) + # [END iot_send_command] + + +def create_gateway( + service_account_json, project_id, cloud_region, registry_id, device_id, + gateway_id, certificate_file, algorithm): + """Create a gateway to bind devices to.""" + # [START iot_create_gateway] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + # gateway_id = 'your-gateway-id' + # certificate_file = 'path/to/certificate.pem' + # algorithm = 'ES256' + # Check that the gateway doesn't already exist + exists = False + client = iot_v1.DeviceManagerClient() + + parent = client.registry_path(project_id, cloud_region, registry_id) + devices = list(client.list_devices(parent=parent)) + + for device in devices: + if device.id == gateway_id: + exists = True + print('Device: {} : {} : {} : {}'.format( + device.id, + device.num_id, + device.config, + device.gateway_config + )) + + with io.open(certificate_file) as f: + certificate = f.read() + + if algorithm == 'ES256': + certificate_format = 'ES256_PEM' + else: + certificate_format = 'RSA_X509_PEM' + + # TODO: Auth type + device_template = { + 'id': gateway_id, + 'credentials': [{ + 'public_key': { + 'format': certificate_format, + 'key': certificate + } + }], + 'gateway_config': { + 'gateway_type': 'GATEWAY', + 'gateway_auth_method': 'ASSOCIATION_ONLY' + } + } + + if not exists: + res = client.create_device(parent, device_template) + print('Created Gateway {}'.format(res)) + else: + print('Gateway exists, skipping') + # [END iot_create_gateway] + + +def bind_device_to_gateway( + service_account_json, project_id, cloud_region, registry_id, device_id, + gateway_id): + """Binds a device to a gateway.""" + # [START iot_bind_device_to_gateway] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + # gateway_id = 'your-gateway-id' + client = iot_v1.DeviceManagerClient() + + create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + parent = client.registry_path(project_id, cloud_region, registry_id) + + res = client.bind_device_to_gateway(parent, gateway_id, device_id) + + print('Device Bound! {}'.format(res)) + # [END iot_bind_device_to_gateway] + + +def unbind_device_from_gateway( + service_account_json, project_id, cloud_region, registry_id, device_id, + gateway_id): + """Unbinds a device to a gateway.""" + # [START iot_unbind_device_from_gateway] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # device_id = 'your-device-id' + # gateway_id = 'your-gateway-id' + client = iot_v1.DeviceManagerClient() + + parent = client.registry_path(project_id, cloud_region, registry_id) + + res = client.unbind_device_from_gateway(parent, gateway_id, device_id) + + print('Device unbound: {}'.format(res)) + # [END iot_unbind_device_from_gateway] + + +def list_gateways( + service_account_json, project_id, cloud_region, registry_id): + """Lists gateways in a registry""" + # [START iot_list_gateways] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + client = iot_v1.DeviceManagerClient() + + path = client.registry_path(project_id, cloud_region, registry_id) + mask = iot_v1.types.FieldMask() + mask.paths.append('config') + mask.paths.append('gateway_config') + devices = list(client.list_devices(parent=path, field_mask=mask)) + + for device in devices: + if device.gateway_config is not None: + if device.gateway_config.gateway_type == 1: + print('Gateway ID: {}\n\t{}'.format(device.id, device)) + # [END iot_list_gateways] + + +def list_devices_for_gateway( + service_account_json, project_id, cloud_region, registry_id, + gateway_id): + """List devices bound to a gateway""" + # [START iot_list_devices_for_gateway] + # project_id = 'YOUR_PROJECT_ID' + # cloud_region = 'us-central1' + # registry_id = 'your-registry-id' + # gateway_id = 'your-gateway-id' + client = iot_v1.DeviceManagerClient() + + path = client.registry_path(project_id, cloud_region, registry_id) + + devices = list(client.list_devices( + parent=path, + gateway_list_options={'associations_gateway_id': gateway_id})) + + found = False + for device in devices: + found = True + print('Device: {} : {}'.format(device.num_id, device.id)) + + if not found: + print('No devices bound to gateway {}'.format(gateway_id)) + # [END iot_list_devices_for_gateway] + + +def parse_command_line_args(): + """Parse command line arguments.""" + default_registry = 'cloudiot_device_manager_example_registry_{}'.format( + int(time.time())) + + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + + # Optional arguments + parser.add_argument( + '--algorithm', + choices=('RS256', 'ES256'), + help='Which encryption algorithm to use to generate the JWT.') + parser.add_argument( + '--certificate_path', + help='Path to public certificate.') + parser.add_argument( + '--cloud_region', default='us-central1', help='GCP cloud region') + parser.add_argument( + '--pubsub_topic', + help=('Google Cloud Pub/Sub topic. ' + 'Format is projects/project_id/topics/topic-id')) + parser.add_argument( + '--config', + default=None, + help='Configuration sent to a device.') + parser.add_argument( + '--device_id', + default=None, + help='Device id.') + parser.add_argument( + '--ec_public_key_file', + default=None, + help='Path to public ES256 key file.') + parser.add_argument( + '--gateway_id', + help='Gateway identifier.') + parser.add_argument( + '--member', + default=None, + help='Member used for IAM commands.') + parser.add_argument( + '--role', + default=None, + help='Role used for IAM commands.') + parser.add_argument( + '--send_command', + default='1', + help='The command sent to the device') + parser.add_argument( + '--project_id', + default=os.environ.get("GOOGLE_CLOUD_PROJECT"), + help='GCP cloud project name.') + parser.add_argument( + '--registry_id', + default=default_registry, + help='Registry id. If not set, a name will be generated.') + parser.add_argument( + '--rsa_certificate_file', + default=None, + help='Path to RS256 certificate file.') + parser.add_argument( + '--service_account_json', + default=os.environ.get("GOOGLE_APPLICATION_CREDENTIALS"), + help='Path to service account json file.') + parser.add_argument( + '--version', + default=0, + type=int, + help='Version number for setting device configuration.') + + # Command subparser + command = parser.add_subparsers(dest='command') + + command.add_parser( + 'bind-device-to-gateway', help=bind_device_to_gateway.__doc__) + command.add_parser('create-es256', help=create_es256_device.__doc__) + command.add_parser('create-gateway', help=create_gateway.__doc__) + command.add_parser('create-registry', help=open_registry.__doc__) + command.add_parser('create-rsa256', help=create_rs256_device.__doc__) + command.add_parser('create-topic', help=create_iot_topic.__doc__) + command.add_parser('create-unauth', help=create_unauth_device.__doc__) + command.add_parser('delete-device', help=delete_device.__doc__) + command.add_parser('delete-registry', help=delete_registry.__doc__) + command.add_parser('get', help=get_device.__doc__) + command.add_parser('get-config-versions', help=get_config_versions.__doc__) + command.add_parser('get-iam-permissions', help=get_iam_permissions.__doc__) + command.add_parser('get-registry', help=get_registry.__doc__) + command.add_parser('get-state', help=get_state.__doc__) + command.add_parser('list', help=list_devices.__doc__) + command.add_parser( + 'list-devices-for-gateway', help=list_devices_for_gateway.__doc__) + command.add_parser('list-gateways', help=list_gateways.__doc__) + command.add_parser('list-registries', help=list_registries.__doc__) + command.add_parser('patch-es256', help=patch_es256_auth.__doc__) + command.add_parser('patch-rs256', help=patch_rsa256_auth.__doc__) + command.add_parser('send-command', help=send_command.__doc__) + command.add_parser('set-config', help=patch_rsa256_auth.__doc__) + command.add_parser('set-iam-permissions', help=set_iam_permissions.__doc__) + command.add_parser( + 'unbind-device-from-gateway', help=unbind_device_from_gateway.__doc__) + + return parser.parse_args() + + +def run_create(args): + """Handles commands that create devices, registries, or topics.""" + if args.command == 'create-rsa256': + create_rs256_device( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.rsa_certificate_file) + + elif args.command == 'create-es256': + create_es256_device( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.ec_public_key_file) + + elif args.command == 'create-gateway': + create_gateway( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.gateway_id, args.certificate_path, args.algorithm) + + elif args.command == 'create-unauth': + create_unauth_device( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id) + + elif args.command == 'create-registry': + if (args.pubsub_topic is None): + sys.exit('Error: specify --pubsub_topic') + open_registry( + args.service_account_json, args.project_id, + args.cloud_region, args.pubsub_topic, args.registry_id) + + elif args.command == 'create-topic': + if (args.pubsub_topic is None): + sys.exit('Error: specify --pubsub_topic') + create_iot_topic(args.project_id, args.pubsub_topic) + + +def run_get(args): + if args.command == 'get': + get_device( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id) + + elif args.command == 'get-config-versions': + get_config_versions( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id) + + elif args.command == 'get-state': + get_state( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id) + + elif args.command == 'get-iam-permissions': + print(get_iam_permissions( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id)) + + elif args.command == 'get-registry': + print(get_registry( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id)) + + +def run_list(args): + if args.command == 'list': + list_devices( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id) + elif args.command == 'list-devices-for-gateway': + list_devices_for_gateway( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.gateway_id) + elif args.command == 'list-gateways': + list_gateways( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id) + elif args.command == 'list-registries': + list_registries( + args.service_account_json, args.project_id, + args.cloud_region) + + +def run_command(args): + """Calls the program using the specified command.""" + if args.project_id is None: + print('You must specify a project ID or set the environment variable.') + return + elif args.command.startswith('create'): + run_create(args) + elif args.command.startswith('get'): + run_get(args) + elif args.command.startswith('list'): + run_list(args) + + elif args.command == 'bind-device-to-gateway': + bind_device_to_gateway( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.gateway_id) + elif args.command == 'delete-device': + delete_device( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id) + elif args.command == 'delete-registry': + delete_registry( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id) + elif args.command == 'patch-es256': + if (args.ec_public_key_file is None): + sys.exit('Error: specify --ec_public_key_file') + patch_es256_auth( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.ec_public_key_file) + elif args.command == 'patch-rs256': + if (args.rsa_certificate_file is None): + sys.exit('Error: specify --rsa_certificate_file') + patch_rsa256_auth( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.rsa_certificate_file) + elif args.command == 'send-command': + send_command( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.send_command) + elif args.command == 'set-iam-permissions': + if (args.member is None): + sys.exit('Error: specify --member') + if (args.role is None): + sys.exit('Error: specify --role') + set_iam_permissions( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.role, args.member) + elif args.command == 'set-config': + if (args.config is None): + sys.exit('Error: specify --config') + if (args.version is None): + sys.exit('Error: specify --version') + set_config( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.version, args.config) + elif args.command == 'unbind-device-from-gateway': + unbind_device_from_gateway( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.gateway_id) + + +if __name__ == '__main__': + args = parse_command_line_args() + run_command(args) diff --git a/samples/api-client/manager/manager_test.py b/samples/api-client/manager/manager_test.py new file mode 100644 index 00000000..7cb3378d --- /dev/null +++ b/samples/api-client/manager/manager_test.py @@ -0,0 +1,506 @@ +# Copyright 2017 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os +import sys +import time +import uuid + +from google.cloud import pubsub +import pytest + +# Add command receiver for bootstrapping device registry / device for testing +sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'mqtt_example')) # noqa +import cloudiot_mqtt_example # noqa +import manager # noqa + + +cloud_region = 'us-central1' +device_id_template = 'test-device-{}' +ca_cert_path = '../mqtt_example/resources/roots.pem' +es_cert_path = 'resources/ec_public.pem' +rsa_cert_path = 'resources/rsa_cert.pem' +rsa_private_path = 'resources/rsa_private.pem' # Must match rsa_cert +topic_id = 'test-device-events-{}'.format(uuid.uuid4()) + +project_id = os.environ['GOOGLE_CLOUD_PROJECT'] +service_account_json = os.environ['GOOGLE_APPLICATION_CREDENTIALS'] + +pubsub_topic = 'projects/{}/topics/{}'.format(project_id, topic_id) + +# This format is used in the `clean_up_registries()` below. +registry_id = 'test-registry-{}-{}'.format(uuid.uuid4().hex, int(time.time())) + + +@pytest.fixture(scope="session", autouse=True) +def clean_up_registries(): + all_registries = list(manager.list_registries( + service_account_json, project_id, cloud_region)) + + for registry in all_registries: + registry_id = registry.id + if registry_id.find('test-registry-') == 0: + time_str = registry_id[ + registry_id.rfind('-') + 1: len(registry_id)] + test_date = datetime.datetime.utcfromtimestamp(int(time_str)) + now_date = datetime.datetime.utcfromtimestamp(int(time.time())) + difftime = now_date - test_date + + # *NOTE* Restrict to registries used in the tests older than 30 + # days to prevent thrashing in the case of async tests + if (difftime.days > 30): + client = manager.get_client(service_account_json) + gateways = client.projects().locations().registries().devices( + ).list( + parent=registry.name, + fieldMask='config,gatewayConfig' + ).execute().get('devices', []) + devices = client.projects().locations().registries().devices( + ).list(parent=registry.name).execute().get( + 'devices', []) + + # Unbind devices from each gateway and delete + for gateway in gateways: + gateway_id = gateway.get('id') + bound = client.projects().locations().registries().devices( + ).list( + parent=registry.name, + gatewayListOptions_associationsGatewayId=gateway_id + ).execute() + if 'devices' in bound: + for device in bound['devices']: + bind_request = { + 'deviceId': device.get('id'), + 'gatewayId': gateway_id + } + client.projects().locations().registries( + ).unbindDeviceFromGateway( + parent=registry.get('name'), + body=bind_request).execute() + gateway_name = '{}/devices/{}'.format( + registry.name, gateway_id) + client.projects().locations().registries().devices( + ).delete(name=gateway_name).execute() + + # Delete the devices + # Assumption is that the devices are not bound to gateways + for device in devices: + device_name = '{}/devices/{}'.format( + registry.name, device.get('id')) + print(device_name) + remove_device = True + try: + client.projects().locations().registries().devices( + ).get(name=device_name).execute() + except Exception: + remove_device = False + + if remove_device: + print('removing {}'.format(device_name)) + client.projects().locations().registries().devices( + ).delete(name=device_name).execute() + + # Delete the old test registry + client.projects().locations().registries().delete( + name=registry.name).execute() + + +@pytest.fixture(scope='module') +def test_topic(): + topic = manager.create_iot_topic(project_id, topic_id) + + yield topic + + pubsub_client = pubsub.PublisherClient() + topic_path = pubsub_client.topic_path(project_id, topic_id) + pubsub_client.delete_topic(topic_path) + + +def test_create_delete_registry(test_topic, capsys): + manager.open_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + manager.list_devices( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + + # Check that create / list worked + assert 'Created registry' in out + assert 'event_notification_config' in out + + # Clean up + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + +def test_get_iam_permissions(test_topic, capsys): + manager.open_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + manager.list_devices( + service_account_json, project_id, cloud_region, registry_id) + + # Test getting IAM permissions + print(manager.get_iam_permissions( + service_account_json, project_id, cloud_region, registry_id)) + + # Test setting IAM permissions + MEMBER = "group:dpebot@google.com" + ROLE = "roles/viewer" + print(manager.set_iam_permissions( + service_account_json, project_id, cloud_region, registry_id, + ROLE, MEMBER)) + + out, _ = capsys.readouterr() + + # Check that create / list worked + assert 'Created registry' in out + assert 'event_notification_config' in out + assert 'dpebot' in out + assert 'etag' in out + + # Clean up + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + +def test_add_delete_unauth_device(test_topic, capsys): + device_id = device_id_template.format('UNAUTH') + manager.open_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + manager.create_unauth_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.get_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + assert 'UNAUTH' in out + + +@pytest.mark.flaky(max_runs=5, min_passes=1) +def test_add_config_unauth_device(test_topic, capsys): + device_id = device_id_template.format('UNAUTH') + manager.open_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + manager.create_unauth_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.set_config( + service_account_json, project_id, cloud_region, registry_id, + device_id, 0, 'test') + + manager.get_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.get_config_versions( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + assert 'Set device configuration' in out + assert 'UNAUTH' in out + assert 'version: 2' in out + + +def test_add_delete_rs256_device(test_topic, capsys): + device_id = device_id_template.format('RSA256') + manager.open_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + manager.create_rs256_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, rsa_cert_path) + + manager.get_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.get_state( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + assert 'format : RSA_X509_PEM' in out + + +def test_add_delete_es256_device(test_topic, capsys): + device_id = device_id_template.format('ES256') + manager.open_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + manager.create_es256_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, es_cert_path) + + manager.get_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.get_state( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + assert 'format : ES256_PEM' in out + + +def test_add_patch_delete_rs256(test_topic, capsys): + device_id = device_id_template.format('PATCHME') + manager.open_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + manager.create_rs256_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, rsa_cert_path) + + manager.get_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + out, _ = capsys.readouterr() + assert 'format : RSA_X509_PEM' in out + + manager.patch_es256_auth( + service_account_json, project_id, cloud_region, registry_id, + device_id, es_cert_path) + + manager.get_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + out, _ = capsys.readouterr() + assert 'format : ES256_PEM' in out + + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + +def test_add_patch_delete_es256(test_topic, capsys): + device_id = device_id_template.format('PATCHME') + manager.open_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + manager.create_es256_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, es_cert_path) + + manager.get_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + out, _ = capsys.readouterr() + assert 'format : ES256_PEM' in out + + manager.patch_rsa256_auth( + service_account_json, project_id, cloud_region, registry_id, + device_id, rsa_cert_path) + + manager.get_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + out, _ = capsys.readouterr() + assert 'format : RSA_X509_PEM' in out + + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + +@pytest.mark.flaky(max_runs=5, min_passes=1) +def test_send_command(test_topic, capsys): + device_id = device_id_template.format('RSA256') + manager.create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + exists = False + devices = manager.list_devices( + service_account_json, project_id, cloud_region, registry_id) + for device in devices: + if device.id == device_id: + exists = True + + if not exists: + manager.create_rs256_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, rsa_cert_path) + + # Exercize the functionality + client = cloudiot_mqtt_example.get_client( + project_id, cloud_region, registry_id, device_id, + rsa_private_path, 'RS256', ca_cert_path, + 'mqtt.googleapis.com', 443) + client.loop_start() + out, _ = capsys.readouterr() + + # Pre-process commands + for i in range(1, 5): + time.sleep(1) + + manager.send_command( + service_account_json, project_id, cloud_region, registry_id, + device_id, 'me want cookies') + out, _ = capsys.readouterr() + + # Process commands + for i in range(1, 5): + time.sleep(1) + + # Clean up + client.loop_stop() + client.disconnect() + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + assert 'Sending command to device' in out + assert '400' not in out + + +def test_create_gateway(test_topic, capsys): + gateway_id = device_id_template.format('RS256') + manager.create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + # TODO: consider adding test for ES256 + manager.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + + # Clean up + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + + assert 'Created Gateway' in out + + +def test_list_gateways(test_topic, capsys): + gateway_id = device_id_template.format('RS256') + manager.create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + # TODO: consider adding test for ES256 + manager.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + + manager.list_gateways( + service_account_json, project_id, cloud_region, registry_id) + + # Clean up + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + + assert 'Gateway ID: {}'.format(gateway_id) in out + + +def test_bind_device_to_gateway_and_unbind(test_topic, capsys): + gateway_id = device_id_template.format('RS256') + device_id = device_id_template.format('noauthbind') + manager.create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + manager.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + + manager.create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + manager.bind_device_to_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + manager.unbind_device_from_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + + # Clean up + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + manager.delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + manager.delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + + assert 'Device Bound' in out + assert 'Device unbound' in out + assert 'HttpError 404' not in out diff --git a/samples/api-client/manager/noxfile.py b/samples/api-client/manager/noxfile.py new file mode 100644 index 00000000..ba55d7ce --- /dev/null +++ b/samples/api-client/manager/noxfile.py @@ -0,0 +1,224 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function + +import os +from pathlib import Path +import sys + +import nox + + +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING +# DO NOT EDIT THIS FILE EVER! +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING + +# Copy `noxfile_config.py` to your directory and modify it instead. + + +# `TEST_CONFIG` dict is a configuration hook that allows users to +# modify the test configurations. The values here should be in sync +# with `noxfile_config.py`. Users will copy `noxfile_config.py` into +# their directory and modify it. + +TEST_CONFIG = { + # You can opt out from the test for specific Python versions. + 'ignored_versions': ["2.7"], + + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT', + # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + 'envs': {}, +} + + +try: + # Ensure we can import noxfile_config in the project's directory. + sys.path.append('.') + from noxfile_config import TEST_CONFIG_OVERRIDE +except ImportError as e: + print("No user noxfile_config found: detail: {}".format(e)) + TEST_CONFIG_OVERRIDE = {} + +# Update the TEST_CONFIG with the user supplied values. +TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) + + +def get_pytest_env_vars(): + """Returns a dict for pytest invocation.""" + ret = {} + + # Override the GCLOUD_PROJECT and the alias. + env_key = TEST_CONFIG['gcloud_project_env'] + # This should error out if not set. + ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key] + + # Apply user supplied envs. + ret.update(TEST_CONFIG['envs']) + return ret + + +# DO NOT EDIT - automatically generated. +# All versions used to tested samples. +ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"] + +# Any default versions that should be ignored. +IGNORED_VERSIONS = TEST_CONFIG['ignored_versions'] + +TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) + +INSTALL_LIBRARY_FROM_SOURCE = bool(os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False)) +# +# Style Checks +# + + +def _determine_local_import_names(start_dir): + """Determines all import names that should be considered "local". + + This is used when running the linter to insure that import order is + properly checked. + """ + file_ext_pairs = [os.path.splitext(path) for path in os.listdir(start_dir)] + return [ + basename + for basename, extension in file_ext_pairs + if extension == ".py" + or os.path.isdir(os.path.join(start_dir, basename)) + and basename not in ("__pycache__") + ] + + +# Linting with flake8. +# +# We ignore the following rules: +# E203: whitespace before ‘:’ +# E266: too many leading ‘#’ for block comment +# E501: line too long +# I202: Additional newline in a section of imports +# +# We also need to specify the rules which are ignored by default: +# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121'] +FLAKE8_COMMON_ARGS = [ + "--show-source", + "--builtin=gettext", + "--max-complexity=20", + "--import-order-style=google", + "--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py", + "--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202", + "--max-line-length=88", +] + + +@nox.session +def lint(session): + session.install("flake8", "flake8-import-order") + + local_names = _determine_local_import_names(".") + args = FLAKE8_COMMON_ARGS + [ + "--application-import-names", + ",".join(local_names), + "." + ] + session.run("flake8", *args) + + +# +# Sample Tests +# + + +PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] + + +def _session_tests(session, post_install=None): + """Runs py.test for a particular project.""" + if os.path.exists("requirements.txt"): + session.install("-r", "requirements.txt") + + if os.path.exists("requirements-test.txt"): + session.install("-r", "requirements-test.txt") + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars() + ) + + +@nox.session(python=ALL_VERSIONS) +def py(session): + """Runs py.test for a sample using the specified version of Python.""" + if session.python in TESTED_VERSIONS: + _session_tests(session) + else: + session.skip("SKIPPED: {} tests are disabled for this sample.".format( + session.python + )) + + +# +# Readmegen +# + + +def _get_repo_root(): + """ Returns the root folder of the project. """ + # Get root of this repository. Assume we don't have directories nested deeper than 10 items. + p = Path(os.getcwd()) + for i in range(10): + if p is None: + break + if Path(p / ".git").exists(): + return str(p) + p = p.parent + raise Exception("Unable to detect repository root.") + + +GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")]) + + +@nox.session +@nox.parametrize("path", GENERATED_READMES) +def readmegen(session, path): + """(Re-)generates the readme for a sample.""" + session.install("jinja2", "pyyaml") + dir_ = os.path.dirname(path) + + if os.path.exists(os.path.join(dir_, "requirements.txt")): + session.install("-r", os.path.join(dir_, "requirements.txt")) + + in_file = os.path.join(dir_, "README.rst.in") + session.run( + "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file + ) diff --git a/samples/api-client/manager/requirements-test.txt b/samples/api-client/manager/requirements-test.txt new file mode 100644 index 00000000..7e460c8c --- /dev/null +++ b/samples/api-client/manager/requirements-test.txt @@ -0,0 +1 @@ +pytest==6.0.1 diff --git a/samples/api-client/manager/requirements.txt b/samples/api-client/manager/requirements.txt new file mode 100644 index 00000000..178db090 --- /dev/null +++ b/samples/api-client/manager/requirements.txt @@ -0,0 +1,9 @@ +cryptography==3.1 +flaky==3.7.0 +google-api-python-client==1.11.0 +google-auth-httplib2==0.0.4 +google-auth==1.21.0 +google-cloud-iot==1.0.0 +google-cloud-pubsub==1.7.0 +paho-mqtt==1.5.0 +pyjwt==1.7.1 diff --git a/samples/api-client/manager/resources/README.md b/samples/api-client/manager/resources/README.md new file mode 100644 index 00000000..20a0344f --- /dev/null +++ b/samples/api-client/manager/resources/README.md @@ -0,0 +1,9 @@ +# Test public certificate files + +[![Open in Cloud Shell][shell_img]][shell_link] + +[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png +[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=iot/api-client/manager/resources/README.md + +The public certificates in this folder are only provided for testing and should +not be used for registering your devices. diff --git a/samples/api-client/manager/resources/ec_public.pem b/samples/api-client/manager/resources/ec_public.pem new file mode 100644 index 00000000..3b61697a --- /dev/null +++ b/samples/api-client/manager/resources/ec_public.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhbN0N+3JH+3VBR/Xex4b1JzeJZgG +SUeTFIUpg/svqd+B4tYZySSYOccVJFUyL805mSgUMQ84/bYAIVybWZqvAQ== +-----END PUBLIC KEY----- diff --git a/samples/api-client/manager/resources/rsa_cert.pem b/samples/api-client/manager/resources/rsa_cert.pem new file mode 100644 index 00000000..f0c79f9c --- /dev/null +++ b/samples/api-client/manager/resources/rsa_cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC+DCCAeCgAwIBAgIJALt7HnuYGgVcMA0GCSqGSIb3DQEBCwUAMBExDzANBgNV +BAMMBnVudXNlZDAeFw0xODEyMDMwMDE2MjNaFw0yODExMzAwMDE2MjNaMBExDzAN +BgNVBAMMBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrA +b+5XMIgwyl6+CkdJkKKp4f+2hHAOoSqQroj2MR/i41YysUbKCk8KdQSZqTBtIvrY +df7s6zDV3zmi3LBBHX6MGnz/1j5YIXlujBhsnQTRbTuUjjDx96ik2C2rR1w7okA7 +MmBsdVzRe8g5pfNQGdV0l15UaZK+qFlLg0xzasPPKmYFFUbKXeWPaKJmtw9d/l6a +8jb87fwI3LTWjZr6Bk7L4Zf1TDlTDroMvNlkW9Z9xSkcgC77EjMtC7RYxxbelaxd +qI9IdxIpmExg6pKMJEvJNA11GYhTlAxkJNh7gd0WlYvQlwDI7D6NJPbCmm4ac1P2 +AA1MFHVgxoKAFk/8V38CAwEAAaNTMFEwHQYDVR0OBBYEFC5Dlz2bTWzaJO6i1Qn8 +lTdDAigCMB8GA1UdIwQYMBaAFC5Dlz2bTWzaJO6i1Qn8lTdDAigCMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANmnnBQaWPhJne5kOjMe+SEsdLbG +OD9L8RmokOsRPXJbj2KoM07UUXMgUe57daYm72wDfKZpvG5qwybkkym+NnahJY+C +u9FX1dTBjM/TqPWKI817mDp5W31a+q6DXdggG+Yf6pz0dMXGGzRtSTEpLKsKtXqe +Y9f7266JCx9V5QFK14SmpIdBF38G0bcNPEvRJ6uKaVKBnU4+7o4YlQLuDczT29Tp +CXL0egUViNT9kv03Pj9iSPR6EGcmOjnSZe1SFVg9OeCauF1wuuFCxUuCkWSEkEm7 +laNke9PHHTe9BoBxKMsTFEPivhVaAf9fUp+NQxZNmdgbux9AAlJgiyU0sFg= +-----END CERTIFICATE----- diff --git a/samples/api-client/manager/resources/rsa_private.pem b/samples/api-client/manager/resources/rsa_private.pem new file mode 100644 index 00000000..5eaf0240 --- /dev/null +++ b/samples/api-client/manager/resources/rsa_private.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDqwG/uVzCIMMpe +vgpHSZCiqeH/toRwDqEqkK6I9jEf4uNWMrFGygpPCnUEmakwbSL62HX+7Osw1d85 +otywQR1+jBp8/9Y+WCF5bowYbJ0E0W07lI4w8feopNgtq0dcO6JAOzJgbHVc0XvI +OaXzUBnVdJdeVGmSvqhZS4NMc2rDzypmBRVGyl3lj2iiZrcPXf5emvI2/O38CNy0 +1o2a+gZOy+GX9Uw5Uw66DLzZZFvWfcUpHIAu+xIzLQu0WMcW3pWsXaiPSHcSKZhM +YOqSjCRLyTQNdRmIU5QMZCTYe4HdFpWL0JcAyOw+jST2wppuGnNT9gANTBR1YMaC +gBZP/Fd/AgMBAAECggEBAOevf4kColJ3nPM+qlRLJaV09yjyUOlrduLUon1oRXmL +6wUCyPXtp5j04CLnKRUzUUezZVlxKHotSr/OnfKSgXKJAgeGVEN5paf8U+YzJBFC +RIV+C4wA84WNFBKWrbo43Nx50DFcOcSet4UYaFGoJ6cFB/PAaeW7p9lhbreAXcnb +g2z4SBsGGO2ZKZkSOcXg39GKX5S0bsEhHzIOFvPBdDQpaVAx/Bq76iBzVz1bRwGp +A3SjJn0g4V+3TcTrpRzgtCRRNPM48JeLHw6/mdVSk6gIoEbg+WTB92Z7BlTbjqhI +LPoMx3wQkg7J2gRrT0rPJIMkgdK9Q8RyWaulsRAn+gECgYEA/jfisAhn7IAPBXKz +ED56NSr174qX97SO2JrB7PO614BV8lHSoV4QI+nQCBkNVhL/SuWvqB3naImo+UOX +Smo6fmh78X+yIXKKhj9qY01jxRGcrnhA25L9gk7TFSNm7XaV2HxHq+TW6tvkL0uO +jXSH3D+u8/f+5ZCt/egNq3eU4n8CgYEA7GWgBLq8jmiz/VVLYboJ0YcJVZ5XAjfJ +vgzxdzX9hIkq5Cpt1ZpO9zE3IXClVvfECXcLpEzoHbiJkEve4dDqbSe4T4JPmpRx +BKRPWFJvTieLA912UmHRBDTrQSA/nZ5zxHsXYmN52femqCwbPWYu5czoqud+GcNq +ghj4oF9UCwECgYEAzpaHx1ntakne6yR807SSB2b0GUfdm1TFyMxqz655pesK7TMF +IlGYeDbn8cy6A7rIcAsbplk21sMX6Ai/h5+wDU3He0e0cG3umI4sXKpla56WX0om +Gsnm7eA0tTbhzBPUTeshK1V6Ob2cP7r9C4MpbRjriiN8pv3eBzpu8WrqOO0CgYAB +8bgGMe75EN1iGQB8tkX8ZirqfFnk18ad/IdD3rrOCz7CD6NFnXZGzC3S5ZVGiNUg +6sy6tjM2g10GRcl4e/phmXEHnl+/OrdPPXa1mD/4GZUoG/ssJEfOzAyfRX+gcTws +goKnuX+4DjRdr7ctoxiBpVTIiwzbc2L93Oy2jPIpAQKBgGzaYhfOlB3SWo+iSKcb +Vx++0gXru1Sgeo42TIn+6adO6DYfwVtfaScVL+Jcg7MZYY+94gnPCp+/ohVTJTvQ +JZdI9Czem64VUtSvc0DCji5gPqvgsO5YgBQrGJJrbmVwu0A6RlNbDwxCdkqHuYk4 +7vsxlbXvNufb0LjnNN0lSUU2 +-----END PRIVATE KEY----- diff --git a/samples/api-client/mqtt_example/cloudiot_mqtt_example.py b/samples/api-client/mqtt_example/cloudiot_mqtt_example.py new file mode 100644 index 00000000..70085a78 --- /dev/null +++ b/samples/api-client/mqtt_example/cloudiot_mqtt_example.py @@ -0,0 +1,513 @@ +#!/usr/bin/env python + +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Python sample for connecting to Google Cloud IoT Core via MQTT, using JWT. +This example connects to Google Cloud IoT Core via MQTT, using a JWT for device +authentication. After connecting, by default the device publishes 100 messages +to the device's MQTT topic at a rate of one per second, and then exits. +Before you run the sample, you must follow the instructions in the README +for this sample. +""" + +# [START iot_mqtt_includes] +import argparse +import datetime +import logging +import os +import random +import ssl +import time + +import jwt +import paho.mqtt.client as mqtt +# [END iot_mqtt_includes] + +logging.getLogger('googleapiclient.discovery_cache').setLevel(logging.CRITICAL) + +# The initial backoff time after a disconnection occurs, in seconds. +minimum_backoff_time = 1 + +# The maximum backoff time before giving up, in seconds. +MAXIMUM_BACKOFF_TIME = 32 + +# Whether to wait with exponential backoff before publishing. +should_backoff = False + + +# [START iot_mqtt_jwt] +def create_jwt(project_id, private_key_file, algorithm): + """Creates a JWT (https://jwt.io) to establish an MQTT connection. + Args: + project_id: The cloud project ID this device belongs to + private_key_file: A path to a file containing either an RSA256 or + ES256 private key. + algorithm: The encryption algorithm to use. Either 'RS256' or 'ES256' + Returns: + A JWT generated from the given project_id and private key, which + expires in 20 minutes. After 20 minutes, your client will be + disconnected, and a new JWT will have to be generated. + Raises: + ValueError: If the private_key_file does not contain a known key. + """ + + token = { + # The time that the token was issued at + 'iat': datetime.datetime.utcnow(), + # The time the token expires. + 'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=20), + # The audience field should always be set to the GCP project id. + 'aud': project_id + } + + # Read the private key file. + with open(private_key_file, 'r') as f: + private_key = f.read() + + print('Creating JWT using {} from private key file {}'.format( + algorithm, private_key_file)) + + return jwt.encode(token, private_key, algorithm=algorithm) +# [END iot_mqtt_jwt] + + +# [START iot_mqtt_config] +def error_str(rc): + """Convert a Paho error to a human readable string.""" + return '{}: {}'.format(rc, mqtt.error_string(rc)) + + +def on_connect(unused_client, unused_userdata, unused_flags, rc): + """Callback for when a device connects.""" + print('on_connect', mqtt.connack_string(rc)) + + # After a successful connect, reset backoff time and stop backing off. + global should_backoff + global minimum_backoff_time + should_backoff = False + minimum_backoff_time = 1 + + +def on_disconnect(unused_client, unused_userdata, rc): + """Paho callback for when a device disconnects.""" + print('on_disconnect', error_str(rc)) + + # Since a disconnect occurred, the next loop iteration will wait with + # exponential backoff. + global should_backoff + should_backoff = True + + +def on_publish(unused_client, unused_userdata, unused_mid): + """Paho callback when a message is sent to the broker.""" + print('on_publish') + + +def on_message(unused_client, unused_userdata, message): + """Callback when the device receives a message on a subscription.""" + payload = str(message.payload.decode('utf-8')) + print('Received message \'{}\' on topic \'{}\' with Qos {}'.format( + payload, message.topic, str(message.qos))) + + +def get_client( + project_id, cloud_region, registry_id, device_id, private_key_file, + algorithm, ca_certs, mqtt_bridge_hostname, mqtt_bridge_port): + """Create our MQTT client. The client_id is a unique string that identifies + this device. For Google Cloud IoT Core, it must be in the format below.""" + client_id = 'projects/{}/locations/{}/registries/{}/devices/{}'.format( + project_id, cloud_region, registry_id, device_id) + print('Device client_id is \'{}\''.format(client_id)) + + client = mqtt.Client(client_id=client_id) + + # With Google Cloud IoT Core, the username field is ignored, and the + # password field is used to transmit a JWT to authorize the device. + client.username_pw_set( + username='unused', + password=create_jwt( + project_id, private_key_file, algorithm)) + + # Enable SSL/TLS support. + client.tls_set(ca_certs=ca_certs, tls_version=ssl.PROTOCOL_TLSv1_2) + + # Register message callbacks. https://eclipse.org/paho/clients/python/docs/ + # describes additional callbacks that Paho supports. In this example, the + # callbacks just print to standard out. + client.on_connect = on_connect + client.on_publish = on_publish + client.on_disconnect = on_disconnect + client.on_message = on_message + + # Connect to the Google MQTT bridge. + client.connect(mqtt_bridge_hostname, mqtt_bridge_port) + + # This is the topic that the device will receive configuration updates on. + mqtt_config_topic = '/devices/{}/config'.format(device_id) + + # Subscribe to the config topic. + client.subscribe(mqtt_config_topic, qos=1) + + # The topic that the device will receive commands on. + mqtt_command_topic = '/devices/{}/commands/#'.format(device_id) + + # Subscribe to the commands topic, QoS 1 enables message acknowledgement. + print('Subscribing to {}'.format(mqtt_command_topic)) + client.subscribe(mqtt_command_topic, qos=0) + + return client +# [END iot_mqtt_config] + + +def detach_device(client, device_id): + """Detach the device from the gateway.""" + # [START iot_detach_device] + detach_topic = '/devices/{}/detach'.format(device_id) + print('Detaching: {}'.format(detach_topic)) + client.publish(detach_topic, '{}', qos=1) + # [END iot_detach_device] + + +def attach_device(client, device_id, auth): + """Attach the device to the gateway.""" + # [START iot_attach_device] + attach_topic = '/devices/{}/attach'.format(device_id) + attach_payload = '{{"authorization" : "{}"}}'.format(auth) + client.publish(attach_topic, attach_payload, qos=1) + # [END iot_attach_device] + + +def listen_for_messages( + service_account_json, project_id, cloud_region, registry_id, device_id, + gateway_id, num_messages, private_key_file, algorithm, ca_certs, + mqtt_bridge_hostname, mqtt_bridge_port, jwt_expires_minutes, duration, + cb=None): + """Listens for messages sent to the gateway and bound devices.""" + # [START iot_listen_for_messages] + global minimum_backoff_time + + jwt_iat = datetime.datetime.utcnow() + jwt_exp_mins = jwt_expires_minutes + # Use gateway to connect to server + client = get_client( + project_id, cloud_region, registry_id, gateway_id, + private_key_file, algorithm, ca_certs, mqtt_bridge_hostname, + mqtt_bridge_port) + + attach_device(client, device_id, '') + print('Waiting for device to attach.') + time.sleep(5) + + # The topic devices receive configuration updates on. + device_config_topic = '/devices/{}/config'.format(device_id) + client.subscribe(device_config_topic, qos=1) + + # The topic gateways receive configuration updates on. + gateway_config_topic = '/devices/{}/config'.format(gateway_id) + client.subscribe(gateway_config_topic, qos=1) + + # The topic gateways receive error updates on. QoS must be 0. + error_topic = '/devices/{}/errors'.format(gateway_id) + client.subscribe(error_topic, qos=0) + + # Wait for about a minute for config messages. + for i in range(1, duration): + client.loop() + if cb is not None: + cb(client) + + if should_backoff: + # If backoff time is too large, give up. + if minimum_backoff_time > MAXIMUM_BACKOFF_TIME: + print('Exceeded maximum backoff time. Giving up.') + break + + delay = minimum_backoff_time + random.randint(0, 1000) / 1000.0 + time.sleep(delay) + minimum_backoff_time *= 2 + client.connect(mqtt_bridge_hostname, mqtt_bridge_port) + + seconds_since_issue = (datetime.datetime.utcnow() - jwt_iat).seconds + if seconds_since_issue > 60 * jwt_exp_mins: + print('Refreshing token after {}s'.format(seconds_since_issue)) + jwt_iat = datetime.datetime.utcnow() + client.loop() + client.disconnect() + client = get_client( + project_id, cloud_region, registry_id, gateway_id, + private_key_file, algorithm, ca_certs, mqtt_bridge_hostname, + mqtt_bridge_port) + + time.sleep(1) + + detach_device(client, device_id) + + print('Finished.') + # [END iot_listen_for_messages] + + +def send_data_from_bound_device( + service_account_json, project_id, cloud_region, registry_id, device_id, + gateway_id, num_messages, private_key_file, algorithm, ca_certs, + mqtt_bridge_hostname, mqtt_bridge_port, jwt_expires_minutes, payload): + """Sends data from a gateway on behalf of a device that is bound to it.""" + # [START send_data_from_bound_device] + global minimum_backoff_time + + # Publish device events and gateway state. + device_topic = '/devices/{}/{}'.format(device_id, 'state') + gateway_topic = '/devices/{}/{}'.format(gateway_id, 'state') + + jwt_iat = datetime.datetime.utcnow() + jwt_exp_mins = jwt_expires_minutes + # Use gateway to connect to server + client = get_client( + project_id, cloud_region, registry_id, gateway_id, + private_key_file, algorithm, ca_certs, mqtt_bridge_hostname, + mqtt_bridge_port) + + attach_device(client, device_id, '') + print('Waiting for device to attach.') + time.sleep(5) + + # Publish state to gateway topic + gateway_state = 'Starting gateway at: {}'.format(time.time()) + print(gateway_state) + client.publish(gateway_topic, gateway_state, qos=1) + + # Publish num_messages messages to the MQTT bridge + for i in range(1, num_messages + 1): + client.loop() + + if should_backoff: + # If backoff time is too large, give up. + if minimum_backoff_time > MAXIMUM_BACKOFF_TIME: + print('Exceeded maximum backoff time. Giving up.') + break + + delay = minimum_backoff_time + random.randint(0, 1000) / 1000.0 + time.sleep(delay) + minimum_backoff_time *= 2 + client.connect(mqtt_bridge_hostname, mqtt_bridge_port) + + payload = '{}/{}-{}-payload-{}'.format( + registry_id, gateway_id, device_id, i) + + print('Publishing message {}/{}: \'{}\' to {}'.format( + i, num_messages, payload, device_topic)) + client.publish( + device_topic, '{} : {}'.format(device_id, payload), qos=1) + + seconds_since_issue = (datetime.datetime.utcnow() - jwt_iat).seconds + if seconds_since_issue > 60 * jwt_exp_mins: + print('Refreshing token after {}s').format(seconds_since_issue) + jwt_iat = datetime.datetime.utcnow() + client = get_client( + project_id, cloud_region, registry_id, gateway_id, + private_key_file, algorithm, ca_certs, mqtt_bridge_hostname, + mqtt_bridge_port) + + time.sleep(5) + + detach_device(client, device_id) + + print('Finished.') + # [END send_data_from_bound_device] + + +def parse_command_line_args(): + """Parse command line arguments.""" + parser = argparse.ArgumentParser(description=( + 'Example Google Cloud IoT Core MQTT device connection code.')) + parser.add_argument( + '--algorithm', + choices=('RS256', 'ES256'), + required=True, + help='Which encryption algorithm to use to generate the JWT.') + parser.add_argument( + '--ca_certs', + default='roots.pem', + help='CA root from https://pki.google.com/roots.pem') + parser.add_argument( + '--cloud_region', default='us-central1', help='GCP cloud region') + parser.add_argument( + '--data', + default='Hello there', + help='The telemetry data sent on behalf of a device') + parser.add_argument( + '--device_id', required=True, help='Cloud IoT Core device id') + parser.add_argument( + '--gateway_id', required=False, help='Gateway identifier.') + parser.add_argument( + '--jwt_expires_minutes', + default=20, + type=int, + help='Expiration time, in minutes, for JWT tokens.') + parser.add_argument( + '--listen_dur', + default=60, + type=int, + help='Duration (seconds) to listen for configuration messages') + parser.add_argument( + '--message_type', + choices=('event', 'state'), + default='event', + help=('Indicates whether the message to be published is a ' + 'telemetry event or a device state message.')) + parser.add_argument( + '--mqtt_bridge_hostname', + default='mqtt.googleapis.com', + help='MQTT bridge hostname.') + parser.add_argument( + '--mqtt_bridge_port', + choices=(8883, 443), + default=8883, + type=int, + help='MQTT bridge port.') + parser.add_argument( + '--num_messages', + type=int, + default=100, + help='Number of messages to publish.') + parser.add_argument( + '--private_key_file', + required=True, + help='Path to private key file.') + parser.add_argument( + '--project_id', + default=os.environ.get('GOOGLE_CLOUD_PROJECT'), + help='GCP cloud project name') + parser.add_argument( + '--registry_id', required=True, help='Cloud IoT Core registry id') + parser.add_argument( + '--service_account_json', + default=os.environ.get("GOOGLE_APPLICATION_CREDENTIALS"), + help='Path to service account json file.') + + # Command subparser + command = parser.add_subparsers(dest='command') + + command.add_parser( + 'device_demo', + help=mqtt_device_demo.__doc__) + + command.add_parser( + 'gateway_send', + help=send_data_from_bound_device.__doc__) + + command.add_parser( + 'gateway_listen', + help=listen_for_messages.__doc__) + + return parser.parse_args() + + +def mqtt_device_demo(args): + """Connects a device, sends data, and receives data.""" + # [START iot_mqtt_run] + global minimum_backoff_time + global MAXIMUM_BACKOFF_TIME + + # Publish to the events or state topic based on the flag. + sub_topic = 'events' if args.message_type == 'event' else 'state' + + mqtt_topic = '/devices/{}/{}'.format(args.device_id, sub_topic) + + jwt_iat = datetime.datetime.utcnow() + jwt_exp_mins = args.jwt_expires_minutes + client = get_client( + args.project_id, args.cloud_region, args.registry_id, + args.device_id, args.private_key_file, args.algorithm, + args.ca_certs, args.mqtt_bridge_hostname, args.mqtt_bridge_port) + + # Publish num_messages messages to the MQTT bridge once per second. + for i in range(1, args.num_messages + 1): + # Process network events. + client.loop() + + # Wait if backoff is required. + if should_backoff: + # If backoff time is too large, give up. + if minimum_backoff_time > MAXIMUM_BACKOFF_TIME: + print('Exceeded maximum backoff time. Giving up.') + break + + # Otherwise, wait and connect again. + delay = minimum_backoff_time + random.randint(0, 1000) / 1000.0 + print('Waiting for {} before reconnecting.'.format(delay)) + time.sleep(delay) + minimum_backoff_time *= 2 + client.connect(args.mqtt_bridge_hostname, args.mqtt_bridge_port) + + payload = '{}/{}-payload-{}'.format( + args.registry_id, args.device_id, i) + print('Publishing message {}/{}: \'{}\''.format( + i, args.num_messages, payload)) + # [START iot_mqtt_jwt_refresh] + seconds_since_issue = (datetime.datetime.utcnow() - jwt_iat).seconds + if seconds_since_issue > 60 * jwt_exp_mins: + print('Refreshing token after {}s'.format(seconds_since_issue)) + jwt_iat = datetime.datetime.utcnow() + client.loop() + client.disconnect() + client = get_client( + args.project_id, args.cloud_region, + args.registry_id, args.device_id, args.private_key_file, + args.algorithm, args.ca_certs, args.mqtt_bridge_hostname, + args.mqtt_bridge_port) + # [END iot_mqtt_jwt_refresh] + # Publish "payload" to the MQTT topic. qos=1 means at least once + # delivery. Cloud IoT Core also supports qos=0 for at most once + # delivery. + client.publish(mqtt_topic, payload, qos=1) + + # Send events every second. State should not be updated as often + for i in range(0, 60): + time.sleep(1) + client.loop() + # [END iot_mqtt_run] + + +def main(): + args = parse_command_line_args() + + if args.command.startswith('gateway'): + if (args.gateway_id is None): + print('Error: For gateway commands you must specify a gateway ID') + return + + if args.command == 'gateway_listen': + listen_for_messages( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.gateway_id, args.num_messages, args.private_key_file, + args.algorithm, args.ca_certs, args.mqtt_bridge_hostname, + args.mqtt_bridge_port, args.jwt_expires_minutes, + args.listen_dur) + return + elif args.command == 'gateway_send': + send_data_from_bound_device( + args.service_account_json, args.project_id, + args.cloud_region, args.registry_id, args.device_id, + args.gateway_id, args.num_messages, args.private_key_file, + args.algorithm, args.ca_certs, args.mqtt_bridge_hostname, + args.mqtt_bridge_port, args.jwt_expires_minutes, args.data) + return + else: + mqtt_device_demo(args) + print('Finished.') + + +if __name__ == '__main__': + main() diff --git a/samples/api-client/mqtt_example/resources/README.md b/samples/api-client/mqtt_example/resources/README.md new file mode 100644 index 00000000..ba272cca --- /dev/null +++ b/samples/api-client/mqtt_example/resources/README.md @@ -0,0 +1,4 @@ +# Test public certificate files + +The public certificates in this folder are only provided for testing and should +not be used for registering your devices. diff --git a/samples/api-client/mqtt_example/resources/owlister_hootie.png b/samples/api-client/mqtt_example/resources/owlister_hootie.png new file mode 100644 index 0000000000000000000000000000000000000000..e0daf5837392be8a1b456becb9da5d90c44cc518 GIT binary patch literal 39406 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 FV1nR&nEU_$ literal 0 HcmV?d00001 diff --git a/samples/api-client/mqtt_example/resources/roots.pem b/samples/api-client/mqtt_example/resources/roots.pem new file mode 100644 index 00000000..0d3e4c84 --- /dev/null +++ b/samples/api-client/mqtt_example/resources/roots.pem @@ -0,0 +1,1939 @@ +# Operating CA: Comodo Group +# Issuer: CN=AAA Certificate Services O=Comodo CA Limited +# Subject: CN=AAA Certificate Services O=Comodo CA Limited +# Label: "Comodo AAA Services root" +# Serial: 1 +# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 +# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 +# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network +# Subject: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network +# Label: "AddTrust Low-Value Services Root" +# Serial: 1 +# MD5 Fingerprint: 1e:42:95:02:33:92:6b:b9:5f:c0:7f:da:d6:b2:4b:fc +# SHA1 Fingerprint: cc:ab:0e:a0:4c:23:01:d6:69:7b:dd:37:9f:cd:12:eb:24:e3:94:9d +# SHA256 Fingerprint: 8c:72:09:27:9a:c0:4e:27:5e:16:d0:7f:d3:b7:75:e8:01:54:b5:96:80:46:e3:1f:52:dd:25:76:63:24:e9:a7 +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw +MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD +VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul +CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n +tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl +dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch +PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC ++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O +BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk +ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X +7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz +43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl +pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA +WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network +# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network +# Label: "AddTrust External Root" +# Serial: 1 +# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f +# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68 +# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2 +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network +# Subject: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network +# Label: "AddTrust Public Services Root" +# Serial: 1 +# MD5 Fingerprint: c1:62:3e:23:c5:82:73:9c:03:59:4b:2b:e9:77:49:7f +# SHA1 Fingerprint: 2a:b6:28:48:5e:78:fb:f3:ad:9e:79:10:dd:6b:df:99:72:2c:96:e5 +# SHA256 Fingerprint: 07:91:ca:07:49:b2:07:82:aa:d3:c7:d7:bd:0c:df:c9:48:58:35:84:3e:b2:d7:99:60:09:ce:43:ab:6c:69:27 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx +MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB +ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV +BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV +6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX +GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP +dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH +1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF +62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW +BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL +MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU +cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv +b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 +IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ +iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh +4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm +XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network +# Subject: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network +# Label: "AddTrust Qualified Certificates Root" +# Serial: 1 +# MD5 Fingerprint: 27:ec:39:47:cd:da:5a:af:e2:9a:01:65:21:a9:4c:bb +# SHA1 Fingerprint: 4d:23:78:ec:91:95:39:b5:00:7f:75:8f:03:3b:21:1e:c5:4d:8b:cf +# SHA256 Fingerprint: 80:95:21:08:05:db:4b:bc:35:5e:44:28:d8:fd:6e:c2:cd:e3:ab:5f:b9:7a:99:42:98:8e:b8:f4:dc:d0:60:16 +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 +MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK +EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh +BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq +xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G +87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i +2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U +WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 +0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G +A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr +pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL +ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm +aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv +hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm +hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 +P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y +iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no +xqE= +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO Certification Authority O=COMODO CA Limited +# Label: "COMODO Certification Authority" +# Serial: 104350513648249232941998508985834464573 +# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 +# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b +# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Label: "COMODO ECC Certification Authority" +# Serial: 41578283867086692638256921589707938090 +# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 +# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 +# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Label: "COMODO RSA Certification Authority" +# Serial: 101909084537582093308941363524873193117 +# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 +# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 +# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=Secure Certificate Services O=Comodo CA Limited +# Subject: CN=Secure Certificate Services O=Comodo CA Limited +# Label: "Comodo Secure Services root" +# Serial: 1 +# MD5 Fingerprint: d3:d9:bd:ae:9f:ac:67:24:b3:c8:1b:52:e1:b9:a9:bd +# SHA1 Fingerprint: 4a:65:d5:f4:1d:ef:39:b8:b8:90:4a:4a:d3:64:81:33:cf:c7:a1:d1 +# SHA256 Fingerprint: bd:81:ce:3b:4f:65:91:d1:1a:67:b5:fc:7a:47:fd:ef:25:52:1b:f9:aa:4e:18:b9:e3:df:2e:34:a7:80:3b:e8 +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp +ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow +fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV +BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM +cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S +HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 +CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk +3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz +6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV +HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud +EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv +Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw +Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww +DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 +5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI +gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ +aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl +izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=Trusted Certificate Services O=Comodo CA Limited +# Subject: CN=Trusted Certificate Services O=Comodo CA Limited +# Label: "Comodo Trusted Services root" +# Serial: 1 +# MD5 Fingerprint: 91:1b:3f:6e:cd:9e:ab:ee:07:fe:1f:71:d2:b3:61:27 +# SHA1 Fingerprint: e1:9f:e3:0e:8b:84:60:9e:80:9b:17:0d:72:a8:c5:ba:6e:14:09:bd +# SHA256 Fingerprint: 3f:06:e5:56:81:d4:96:f5:be:16:9e:b5:38:9f:9f:2b:8f:f6:1e:17:08:df:68:81:72:48:49:cd:5d:27:cb:69 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 +aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla +MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO +BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD +VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW +fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt +TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL +fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW +1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 +kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G +A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v +ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo +dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu +Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ +HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS +jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ +xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn +dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Label: "USERTrust ECC Certification Authority" +# Serial: 123013823720199481456569720443997572134 +# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 +# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 +# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Label: "USERTrust RSA Certification Authority" +# Serial: 2645093764781058787591871645665788717 +# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 +# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e +# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +# Operating CA: Comodo Group +# Issuer: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com +# Subject: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com +# Label: "UTN USERFirst Hardware Root CA" +# Serial: 91374294542884704022267039221184531197 +# MD5 Fingerprint: 4c:56:41:e5:0d:bb:2b:e8:ca:a3:ed:18:08:ad:43:39 +# SHA1 Fingerprint: 04:83:ed:33:99:ac:36:08:05:87:22:ed:bc:5e:46:00:e3:be:f9:d7 +# SHA256 Fingerprint: 6e:a5:47:41:d0:04:66:7e:ed:1b:48:16:63:4a:a3:a7:9e:6e:4b:96:95:0f:82:79:da:fc:8d:9b:d8:81:21:37 +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB +lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt +SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG +A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe +MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v +d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh +cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn +0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ +M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a +MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd +oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI +DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy +oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 +dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy +bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF +BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli +CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE +CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t +3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS +KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc +# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc +# Label: "Cybertrust Global Root" +# Serial: 4835703278459682877484360 +# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 +# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 +# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG +A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh +bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE +ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 +7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS +J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y +HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP +t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz +FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY +XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw +hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js +MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA +A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj +Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx +XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o +omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc +A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root CA" +# Serial: 17154717934120587862167794914071425081 +# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 +# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 +# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G2" +# Serial: 15385348160840213938643033620894905419 +# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d +# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f +# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G3" +# Serial: 15459312981008553731928384953135426796 +# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb +# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 +# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root CA" +# Serial: 10944719598952040374951832963794454346 +# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e +# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 +# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G2" +# Serial: 4293743540046975378534879503202253541 +# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 +# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 +# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G3" +# Serial: 7089244469030293291760083333884364146 +# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca +# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e +# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert High Assurance EV Root CA" +# Serial: 3553400076410547919724730734378100087 +# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a +# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 +# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +# Operating CA: DigiCert +# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Trusted Root G4" +# Serial: 7451500558977370777930084869016614236 +# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 +# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 +# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Label: "Entrust Root Certification Authority" +# Serial: 1164660820 +# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 +# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 +# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - EC1" +# Serial: 51543124481930649114116133369 +# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc +# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 +# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G2" +# Serial: 1246989352 +# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 +# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 +# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Premium 2048 Secure Server CA" +# Serial: 946069240 +# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 +# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 +# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +# Operating CA: GlobalSign +# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Label: "GlobalSign Root CA" +# Serial: 4835703278459707669005204 +# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a +# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c +# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +# Operating CA: GlobalSign +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Label: "GlobalSign Root CA - R2" +# Serial: 4835703278459682885658125 +# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 +# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe +# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +# Operating CA: GlobalSign +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Label: "GlobalSign Root CA - R3" +# Serial: 4835703278459759426209954 +# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 +# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad +# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- + +# Operating CA: GlobalSign +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Label: "GlobalSign ECC Root CA - R4" +# Serial: 14367148294922964480859022125800977897474 +# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e +# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb +# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= +-----END CERTIFICATE----- + +# Operating CA: GlobalSign +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Label: "GlobalSign ECC Root CA - R5" +# Serial: 32785792099990507226680698011560947931244 +# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 +# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa +# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +# Operating CA: GlobalSign +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Label: "GlobalSign Root CA - R6" +# Serial: 1417766617973444989252670301619537 +# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae +# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 +# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +# Note: "GlobalSign Root CA - R7" not added on purpose. It is P-521. + +# Operating CA: GlobalSign +# Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA - R8 +# Subject: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA - R8 +# Label: "GlobalSign Root CA - R8" +# Serial: 1462505469299036457243287072048861 +# MD5 Fingerprint: 26:15:db:de:38:b4:45:5e:19:3f:1b:57:af:53:2b:36 +# SHA1 Fingerprint: 62:01:ff:ce:4f:09:cd:c7:e0:2f:e1:10:f4:fd:67:f0:37:1a:2f:2a +# SHA256 Fingerprint: ae:48:51:ff:42:03:9b:ad:e0:58:27:91:51:d8:26:83:04:1d:25:98:e2:40:68:3c:c5:6d:76:fb:8c:f5:3d:42 +-----BEGIN CERTIFICATE----- +MIICMzCCAbmgAwIBAgIOSBtqCfT5YHE6/oHMht0wCgYIKoZIzj0EAwMwXDELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExIDAeBgNVBAMTF0dsb2JhbFNpZ24gUm9vdCBDQSAtIFI4MB4XDTE2MDYx +NTAwMDAwMFoXDTM2MDYxNTAwMDAwMFowXDELMAkGA1UEBhMCQkUxGTAXBgNVBAoT +EEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExIDAeBgNVBAMTF0ds +b2JhbFNpZ24gUm9vdCBDQSAtIFI4MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEuO58 +MIfYlB9Ua22Ynfx1+1uIq0K6jX05ft1EPTk84QWhSmRgrDemc7D5yUVLCwbQOuDx +bV/6XltaUrV240bb1R6MdHpCyUE1T8bU4ihgqzSKzrFAI0alrhkkUnyQVUTOo0Iw +QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQULzoS +JoDoisJQeG0GxDR+4kk5V3YwCgYIKoZIzj0EAwMDaAAwZQIxAMehPbKSkPrKXeAn +hII7Icz0jfiUVvIgXxHArLxfFaULyBZDp/jFf40goH9e/BYcJwIwHoz1Vr8425zm +pteEKebfDVMu6CsBt30JPLEyahqauArq6K0I8nQ51SsiNtzvRmbY +-----END CERTIFICATE----- + +# Operating CA: GoDaddy +# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Label: "Go Daddy Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 +# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b +# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- + +# Operating CA: GoDaddy +# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 +# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e +# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +# Operating CA: GoDaddy +# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Label: "Starfield Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 +# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a +# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +# Operating CA: GoDaddy +# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Label: "Go Daddy Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 +# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 +# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +# Operating CA: Symantec (GeoTrust) +# Issuer: O=Equifax OU=Equifax Secure Certificate Authority +# Subject: O=Equifax OU=Equifax Secure Certificate Authority +# Label: "Equifax Secure CA" +# Serial: 903804111 +# MD5 Fingerprint: 67:cb:9d:c0:13:24:8a:82:9b:b2:17:1e:d1:1b:ec:d4 +# SHA1 Fingerprint: d2:32:09:ad:23:d3:14:23:21:74:e4:0d:7f:9d:62:13:97:86:63:3a +# SHA256 Fingerprint: 08:29:7a:40:47:db:a2:36:80:c7:31:db:6e:31:76:53:ca:78:48:e1:be:bd:3a:0b:01:79:a7:07:f9:2c:f1:78 +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 +MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx +dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f +BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A +cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw +ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj +IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh +1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- + +# Operating CA: Symantec (GeoTrust) +# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Global CA O=GeoTrust Inc. +# Label: "GeoTrust Global CA" +# Serial: 144470 +# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5 +# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12 +# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- + +# Operating CA: Symantec (GeoTrust) +# Issuer: CN=GeoTrust Global CA 2 O=GeoTrust Inc. +# Subject: CN=GeoTrust Global CA 2 O=GeoTrust Inc. +# Label: "GeoTrust Global CA 2" +# Serial: 1 +# MD5 Fingerprint: 0e:40:a7:6c:de:03:5d:8f:d1:0f:e4:d1:8d:f9:6c:a9 +# SHA1 Fingerprint: a9:e9:78:08:14:37:58:88:f2:05:19:b0:6d:2b:0d:2b:60:16:90:7d +# SHA256 Fingerprint: ca:2d:82:a0:86:77:07:2f:8a:b6:76:4f:f0:35:67:6c:fe:3e:5e:32:5e:01:21:72:df:3f:92:09:6d:b7:9b:85 +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs +IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A +PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 +Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL +TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL +5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 +S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe +2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap +EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td +EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv +/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN +A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 +abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF +I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz +4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +# Operating CA: Symantec (GeoTrust) +# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Label: "GeoTrust Primary Certification Authority" +# Serial: 32798226551256963324313806436981982369 +# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf +# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96 +# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +# Operating CA: Symantec (GeoTrust) +# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G2" +# Serial: 80682863203381065782177908751794619243 +# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a +# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0 +# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66 +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- + +# Operating CA: Symantec (GeoTrust) +# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G3" +# Serial: 28809105769928564313984085209975885599 +# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05 +# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd +# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4 +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +# Operating CA: Symantec (GeoTrust) +# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Label: "GeoTrust Universal CA" +# Serial: 1 +# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48 +# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79 +# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12 +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +# Operating CA: Symantec (GeoTrust) +# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Label: "GeoTrust Universal CA 2" +# Serial: 1 +# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7 +# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79 +# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +# Operating CA: Symantec (Thawte) +# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA" +# Serial: 69529181992039203566298953787712940909 +# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12 +# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81 +# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- + +# Operating CA: Symantec (Thawte) +# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G2" +# Serial: 71758320672825410020661621085256472406 +# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f +# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12 +# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57 +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp +IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi +BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw +MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig +YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v +dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ +BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 +papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K +DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 +KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox +XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +# Operating CA: Symantec (Thawte) +# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G3" +# Serial: 127614157056681299805556476275995414779 +# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31 +# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2 +# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa +Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl +LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u +MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm +gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 +YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf +b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 +9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S +zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk +OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA +2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW +oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c +KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM +m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu +MdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +# Operating CA: Symantec (VeriSign) +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only +# Label: "Verisign Class 3 Public Primary Certification Authority - G3" +# Serial: 206684696279472310254277870180966723415 +# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09 +# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6 +# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b +N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t +KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu +kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm +CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu +imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te +2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe +DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p +F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt +TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +# Operating CA: Symantec (VeriSign) +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G4" +# Serial: 63143484348153506665311985501458640051 +# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41 +# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a +# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79 +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +# Operating CA: Symantec (VeriSign) +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G5" +# Serial: 33037644167568058970164719475676101450 +# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c +# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5 +# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +# Operating CA: Symantec (VeriSign) +# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Universal Root Certification Authority" +# Serial: 85209574734084581917763752644031726877 +# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19 +# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54 +# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +# Operating CA: Trend Micro +# Issuer: CN=AffirmTrust Commercial O=AffirmTrust +# Subject: CN=AffirmTrust Commercial O=AffirmTrust +# Label: "AffirmTrust Commercial" +# Serial: 8608355977964138876 +# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 +# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 +# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +# Operating CA: Trend Micro +# Issuer: CN=AffirmTrust Networking O=AffirmTrust +# Subject: CN=AffirmTrust Networking O=AffirmTrust +# Label: "AffirmTrust Networking" +# Serial: 8957382827206547757 +# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f +# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f +# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +# Operating CA: Trend Micro +# Issuer: CN=AffirmTrust Premium O=AffirmTrust +# Subject: CN=AffirmTrust Premium O=AffirmTrust +# Label: "AffirmTrust Premium" +# Serial: 7893706540734352110 +# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 +# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 +# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +# Operating CA: Trend Micro +# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust +# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust +# Label: "AffirmTrust Premium ECC" +# Serial: 8401224907861490260 +# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d +# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb +# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- + +# Operating CA: Google Trust Services LLC +# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 +# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R1 +# Label: "GTS Root R1" +# Serial: 6e:47:a9:c5:4b:47:0c:0d:ec:33:d0:89:b9:1c:f4:e1 +# MD5 Fingerprint: 82:1A:EF:D4:D2:4A:F2:9F:E2:3D:97:06:14:70:72:85 +# SHA1 Fingerprint: E1:C9:50:E6:EF:22:F8:4C:56:45:72:8B:92:20:60:D7:D5:A7:A3:E8 +# SHA256 Fingerprint: 2A:57:54:71:E3:13:40:BC:21:58:1C:BD:2C:F1:3E:15:84:63:20:3E:CE:94:BC:F9:D3:CC:19:6B:F0:9A:54:72 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX +mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 +zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P +fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc +vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 +Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp +zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO +Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW +k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ +DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF +lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW +Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z +XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR +gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 +d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv +J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg +DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM ++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy +F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 +SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws +E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl +-----END CERTIFICATE----- + +# Operating CA: Google Trust Services LLC +# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R2 +# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R2 +# Label: "GTS Root R2" +# Serial: 6e:47:a9:c6:5a:b3:e7:20:c5:30:9a:3f:68:52:f2:6f +# MD5 Fingerprint: 44:ED:9A:0E:A4:09:3B:00:F2:AE:4C:A3:C6:61:B0:8B +# SHA1 Fingerprint: D2:73:96:2A:2A:5E:39:9F:73:3F:E1:C7:1E:64:3F:03:38:34:FC:4D +# SHA256 Fingerprint: C4:5D:7B:B0:8E:6D:67:E6:2E:42:35:11:0B:56:4E:5F:78:FD:92:EF:05:8C:84:0A:EA:4E:64:55:D7:58:5C:60 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg +GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu +XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd +re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu +PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 +mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K +8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj +x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR +nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 +kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok +twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp +8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT +z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA +pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb +pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB +R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R +RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk +0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC +5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF +izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn +yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC +-----END CERTIFICATE----- + +# Operating CA: Google Trust Services LLC +# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R3 +# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R3 +# Label: "GTS Root R3" +# Serial: 6e:47:a9:c7:6c:a9:73:24:40:89:0f:03:55:dd:8d:1d +# MD5 Fingerprint: 1A:79:5B:6B:04:52:9C:5D:C7:74:33:1B:25:9A:F9:25 +# SHA1 Fingerprint: 30:D4:24:6F:07:FF:DB:91:89:8A:0B:E9:49:66:11:EB:8C:5E:46:E5 +# SHA256 Fingerprint: 15:D5:B8:77:46:19:EA:7D:54:CE:1C:A6:D0:B0:C4:03:E0:37:A9:17:F1:31:E8:A0:4E:1E:6B:7A:71:BA:BC:E5 +-----BEGIN CERTIFICATE----- +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A +DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk +fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA +njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd +-----END CERTIFICATE----- + +# Operating CA: Google Trust Services LLC +# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4 +# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R4 +# Label: "GTS Root R4" +# Serial: 6e:47:a9:c8:8b:94:b6:e8:bb:3b:2a:d8:a2:b2:c1:99 +# MD5 Fingerprint: 5D:B6:6A:C4:60:17:24:6A:1A:99:A8:4B:EE:5E:B4:26 +# SHA1 Fingerprint: 2A:1D:60:27:D9:4A:B1:0A:1C:4D:91:5C:CD:33:A0:CB:3E:2D:54:CB +# SHA256 Fingerprint: 71:CC:A5:39:1F:9E:79:4B:04:80:25:30:B3:63:E1:21:DA:8A:30:43:BB:26:66:2F:EA:4D:CA:7F:C9:51:A4:BD +-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l +xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 +CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx +sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== +-----END CERTIFICATE----- diff --git a/samples/api-client/mqtt_example/resources/rsa_cert.pem b/samples/api-client/mqtt_example/resources/rsa_cert.pem new file mode 100644 index 00000000..f0c79f9c --- /dev/null +++ b/samples/api-client/mqtt_example/resources/rsa_cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC+DCCAeCgAwIBAgIJALt7HnuYGgVcMA0GCSqGSIb3DQEBCwUAMBExDzANBgNV +BAMMBnVudXNlZDAeFw0xODEyMDMwMDE2MjNaFw0yODExMzAwMDE2MjNaMBExDzAN +BgNVBAMMBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrA +b+5XMIgwyl6+CkdJkKKp4f+2hHAOoSqQroj2MR/i41YysUbKCk8KdQSZqTBtIvrY +df7s6zDV3zmi3LBBHX6MGnz/1j5YIXlujBhsnQTRbTuUjjDx96ik2C2rR1w7okA7 +MmBsdVzRe8g5pfNQGdV0l15UaZK+qFlLg0xzasPPKmYFFUbKXeWPaKJmtw9d/l6a +8jb87fwI3LTWjZr6Bk7L4Zf1TDlTDroMvNlkW9Z9xSkcgC77EjMtC7RYxxbelaxd +qI9IdxIpmExg6pKMJEvJNA11GYhTlAxkJNh7gd0WlYvQlwDI7D6NJPbCmm4ac1P2 +AA1MFHVgxoKAFk/8V38CAwEAAaNTMFEwHQYDVR0OBBYEFC5Dlz2bTWzaJO6i1Qn8 +lTdDAigCMB8GA1UdIwQYMBaAFC5Dlz2bTWzaJO6i1Qn8lTdDAigCMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANmnnBQaWPhJne5kOjMe+SEsdLbG +OD9L8RmokOsRPXJbj2KoM07UUXMgUe57daYm72wDfKZpvG5qwybkkym+NnahJY+C +u9FX1dTBjM/TqPWKI817mDp5W31a+q6DXdggG+Yf6pz0dMXGGzRtSTEpLKsKtXqe +Y9f7266JCx9V5QFK14SmpIdBF38G0bcNPEvRJ6uKaVKBnU4+7o4YlQLuDczT29Tp +CXL0egUViNT9kv03Pj9iSPR6EGcmOjnSZe1SFVg9OeCauF1wuuFCxUuCkWSEkEm7 +laNke9PHHTe9BoBxKMsTFEPivhVaAf9fUp+NQxZNmdgbux9AAlJgiyU0sFg= +-----END CERTIFICATE----- diff --git a/samples/api-client/mqtt_example/resources/rsa_private.pem b/samples/api-client/mqtt_example/resources/rsa_private.pem new file mode 100644 index 00000000..5eaf0240 --- /dev/null +++ b/samples/api-client/mqtt_example/resources/rsa_private.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDqwG/uVzCIMMpe +vgpHSZCiqeH/toRwDqEqkK6I9jEf4uNWMrFGygpPCnUEmakwbSL62HX+7Osw1d85 +otywQR1+jBp8/9Y+WCF5bowYbJ0E0W07lI4w8feopNgtq0dcO6JAOzJgbHVc0XvI +OaXzUBnVdJdeVGmSvqhZS4NMc2rDzypmBRVGyl3lj2iiZrcPXf5emvI2/O38CNy0 +1o2a+gZOy+GX9Uw5Uw66DLzZZFvWfcUpHIAu+xIzLQu0WMcW3pWsXaiPSHcSKZhM +YOqSjCRLyTQNdRmIU5QMZCTYe4HdFpWL0JcAyOw+jST2wppuGnNT9gANTBR1YMaC +gBZP/Fd/AgMBAAECggEBAOevf4kColJ3nPM+qlRLJaV09yjyUOlrduLUon1oRXmL +6wUCyPXtp5j04CLnKRUzUUezZVlxKHotSr/OnfKSgXKJAgeGVEN5paf8U+YzJBFC +RIV+C4wA84WNFBKWrbo43Nx50DFcOcSet4UYaFGoJ6cFB/PAaeW7p9lhbreAXcnb +g2z4SBsGGO2ZKZkSOcXg39GKX5S0bsEhHzIOFvPBdDQpaVAx/Bq76iBzVz1bRwGp +A3SjJn0g4V+3TcTrpRzgtCRRNPM48JeLHw6/mdVSk6gIoEbg+WTB92Z7BlTbjqhI +LPoMx3wQkg7J2gRrT0rPJIMkgdK9Q8RyWaulsRAn+gECgYEA/jfisAhn7IAPBXKz +ED56NSr174qX97SO2JrB7PO614BV8lHSoV4QI+nQCBkNVhL/SuWvqB3naImo+UOX +Smo6fmh78X+yIXKKhj9qY01jxRGcrnhA25L9gk7TFSNm7XaV2HxHq+TW6tvkL0uO +jXSH3D+u8/f+5ZCt/egNq3eU4n8CgYEA7GWgBLq8jmiz/VVLYboJ0YcJVZ5XAjfJ +vgzxdzX9hIkq5Cpt1ZpO9zE3IXClVvfECXcLpEzoHbiJkEve4dDqbSe4T4JPmpRx +BKRPWFJvTieLA912UmHRBDTrQSA/nZ5zxHsXYmN52femqCwbPWYu5czoqud+GcNq +ghj4oF9UCwECgYEAzpaHx1ntakne6yR807SSB2b0GUfdm1TFyMxqz655pesK7TMF +IlGYeDbn8cy6A7rIcAsbplk21sMX6Ai/h5+wDU3He0e0cG3umI4sXKpla56WX0om +Gsnm7eA0tTbhzBPUTeshK1V6Ob2cP7r9C4MpbRjriiN8pv3eBzpu8WrqOO0CgYAB +8bgGMe75EN1iGQB8tkX8ZirqfFnk18ad/IdD3rrOCz7CD6NFnXZGzC3S5ZVGiNUg +6sy6tjM2g10GRcl4e/phmXEHnl+/OrdPPXa1mD/4GZUoG/ssJEfOzAyfRX+gcTws +goKnuX+4DjRdr7ctoxiBpVTIiwzbc2L93Oy2jPIpAQKBgGzaYhfOlB3SWo+iSKcb +Vx++0gXru1Sgeo42TIn+6adO6DYfwVtfaScVL+Jcg7MZYY+94gnPCp+/ohVTJTvQ +JZdI9Czem64VUtSvc0DCji5gPqvgsO5YgBQrGJJrbmVwu0A6RlNbDwxCdkqHuYk4 +7vsxlbXvNufb0LjnNN0lSUU2 +-----END PRIVATE KEY----- diff --git a/scripts/decrypt-secrets.sh b/scripts/decrypt-secrets.sh index ff599eb2..21f6d2a2 100755 --- a/scripts/decrypt-secrets.sh +++ b/scripts/decrypt-secrets.sh @@ -20,14 +20,27 @@ ROOT=$( dirname "$DIR" ) # Work from the project root. cd $ROOT +# Prevent it from overriding files. +# We recommend that sample authors use their own service account files and cloud project. +# In that case, they are supposed to prepare these files by themselves. +if [[ -f "testing/test-env.sh" ]] || \ + [[ -f "testing/service-account.json" ]] || \ + [[ -f "testing/client-secrets.json" ]]; then + echo "One or more target files exist, aborting." + exit 1 +fi + # Use SECRET_MANAGER_PROJECT if set, fallback to cloud-devrel-kokoro-resources. PROJECT_ID="${SECRET_MANAGER_PROJECT:-cloud-devrel-kokoro-resources}" gcloud secrets versions access latest --secret="python-docs-samples-test-env" \ + --project="${PROJECT_ID}" \ > testing/test-env.sh gcloud secrets versions access latest \ --secret="python-docs-samples-service-account" \ + --project="${PROJECT_ID}" \ > testing/service-account.json gcloud secrets versions access latest \ --secret="python-docs-samples-client-secrets" \ - > testing/client-secrets.json \ No newline at end of file + --project="${PROJECT_ID}" \ + > testing/client-secrets.json diff --git a/synth.metadata b/synth.metadata index 50a06681..fd84d349 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,22 +4,21 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/python-iot.git", - "sha": "5d7a613f54e5326adf719e7aeb9cac06ef64f48c" + "sha": "06ed25e2a7f407d098410969c6dfa24a4c84ac9d" } }, { "git": { - "name": "googleapis", - "remote": "https://github.com/googleapis/googleapis.git", - "sha": "cf41866c6f14f10a07aa1e2a1260fc0a2727d889", - "internalRef": "317812187" + "name": "synthtool", + "remote": "https://github.com/googleapis/synthtool.git", + "sha": "d302f93d7f47e2852e585ac35ab2d15585717ec0" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "303271797a360f8a439203413f13a160f2f5b3b4" + "sha": "d302f93d7f47e2852e585ac35ab2d15585717ec0" } } ], diff --git a/synth.py b/synth.py index bd2497d9..4fa4ab2a 100644 --- a/synth.py +++ b/synth.py @@ -15,6 +15,7 @@ """This script is used to synthesize generated parts of this library.""" import synthtool as s from synthtool import gcp +from synthtool.languages import python gapic = gcp.GAPICBazel() common = gcp.CommonTemplates() @@ -37,9 +38,14 @@ # ---------------------------------------------------------------------------- # Add templated files # ---------------------------------------------------------------------------- -templated_files = common.py_library(cov_level=74) +templated_files = common.py_library(cov_level=74, samples=True) s.move(templated_files) +# ---------------------------------------------------------------------------- +# Samples templates +# ---------------------------------------------------------------------------- +python.py_samples() + # TODO(busunkim): Use latest sphinx after microgenerator transition s.replace("noxfile.py", """['"]sphinx['"]""", '"sphinx<3.0.0"')