From 6a9fd75fec62ef0d1d2546e10dffea5665b3dba1 Mon Sep 17 00:00:00 2001 From: Gus Class Date: Fri, 7 Dec 2018 13:50:57 -0800 Subject: [PATCH 1/5] Updates IoT core betas --- iot/api-client/beta-features/README.md | 15 + .../beta-features/commands/README.md | 31 - .../beta-features/commands/receive/README.rst | 108 -- .../commands/receive/README.rst.in | 36 - .../beta-features/commands/receive/receive.py | 220 ---- .../commands/receive/receive_test.py | 188 --- .../commands/receive/resources/README.md | 4 - .../commands/receive/resources/rsa_cert.pem | 18 - .../receive/resources/rsa_private.pem | 28 - .../commands/send/requirements.txt | 8 - .../beta-features/commands/send/send.py | 136 --- .../beta-features/commands/send/send_test.py | 187 --- .../{commands/send => gateway}/README.rst | 80 +- .../{commands/send => gateway}/README.rst.in | 7 +- .../beta-features/gateway/gateway.py | 727 ++++++++++++ .../beta-features/gateway/gateway_demo.py | 259 ++++ .../beta-features/gateway/gateway_test.py | 377 ++++++ .../receive => gateway}/requirements.txt | 8 +- .../receive => gateway}/resources/roots.pem | 1052 +++-------------- .../gateway/resources/rsa_cert.pem | 18 + .../gateway/resources/rsa_private.pem | 28 + 21 files changed, 1682 insertions(+), 1853 deletions(-) create mode 100644 iot/api-client/beta-features/README.md delete mode 100644 iot/api-client/beta-features/commands/README.md delete mode 100644 iot/api-client/beta-features/commands/receive/README.rst delete mode 100644 iot/api-client/beta-features/commands/receive/README.rst.in delete mode 100644 iot/api-client/beta-features/commands/receive/receive.py delete mode 100644 iot/api-client/beta-features/commands/receive/receive_test.py delete mode 100644 iot/api-client/beta-features/commands/receive/resources/README.md delete mode 100644 iot/api-client/beta-features/commands/receive/resources/rsa_cert.pem delete mode 100644 iot/api-client/beta-features/commands/receive/resources/rsa_private.pem delete mode 100644 iot/api-client/beta-features/commands/send/requirements.txt delete mode 100644 iot/api-client/beta-features/commands/send/send.py delete mode 100644 iot/api-client/beta-features/commands/send/send_test.py rename iot/api-client/beta-features/{commands/send => gateway}/README.rst (50%) rename iot/api-client/beta-features/{commands/send => gateway}/README.rst.in (77%) create mode 100644 iot/api-client/beta-features/gateway/gateway.py create mode 100644 iot/api-client/beta-features/gateway/gateway_demo.py create mode 100644 iot/api-client/beta-features/gateway/gateway_test.py rename iot/api-client/beta-features/{commands/receive => gateway}/requirements.txt (68%) rename iot/api-client/beta-features/{commands/receive => gateway}/resources/roots.pem (64%) create mode 100644 iot/api-client/beta-features/gateway/resources/rsa_cert.pem create mode 100644 iot/api-client/beta-features/gateway/resources/rsa_private.pem diff --git a/iot/api-client/beta-features/README.md b/iot/api-client/beta-features/README.md new file mode 100644 index 00000000000..1caaea966ec --- /dev/null +++ b/iot/api-client/beta-features/README.md @@ -0,0 +1,15 @@ +# Cloud IoT Core Beta Samples +This folder contains Python samples that demonstrate the Gateway beta feature. + +## Quickstart +1. [Enable the Cloud IoT Core API from the console](https://console.cloud.google.com/iot). +2. Create a virtual environment in the gateways sample folder: + + cd gateway + virtualenv env + source env/bin/activate + +3. Run the `gateway_demo.py` script to see the gateway feature work. + + pip install -r requirements.txt + python gateway_demo.py diff --git a/iot/api-client/beta-features/commands/README.md b/iot/api-client/beta-features/commands/README.md deleted file mode 100644 index 840582f7228..00000000000 --- a/iot/api-client/beta-features/commands/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Cloud IoT Core Python Samples -This folder contains Python samples that demonstrate an overview of the -commands beta feature. - -## Quickstart -1. Install the Cloud SDK as described in [the device manager guide](https://cloud.google.com/iot/docs/device_manager_guide). -2. Create a PubSub topic: - - gcloud beta pubsub topics create projects/my-iot-project/topics/device-events - -3. Create a registry: - - gcloud iot registries create my-registry \ - --project=my-iot-project \ - --region=us-central1 \ - --event-notification-config=topic=projects/intense-wavelet-343/topics/device-events - -4. Use the `generate_keys.sh` script to generate your signing keys: - - /python-docs-samples/iot/api-client/generate_keys.sh - -5. Register a device: - - gcloud iot devices create my-python-device \ - --project=my-iot-project \ - --region=us-central1 \ - --registry=my-registry \ - --public-key path=rsa_cert.pem,type=rs256 - -6. Connect a virtual device using the sample app in the `receive` folder. -7. While the virtual device is connected, send a commmand using the sample app in the `send` folder. diff --git a/iot/api-client/beta-features/commands/receive/README.rst b/iot/api-client/beta-features/commands/receive/README.rst deleted file mode 100644 index 8f3efb052cc..00000000000 --- a/iot/api-client/beta-features/commands/receive/README.rst +++ /dev/null @@ -1,108 +0,0 @@ -.. 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/mqtt_example/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. -Before you run the sample, you must retrieve the Google root certificate. For example, ``wget https://pki.goog/roots.pem`` or ``curl https://pki.goog/roots.pem > roots.pem``. -The following example runs the sample using the project ID ``blue-jet-123`` and the device name ``my-python-device``:: - - python receive.py \ - --registry_id=my-registry \ - --project_id=blue-jet-123 \ - --device_id=my-python-device \ - --algorithm=RS256 \ - --private_key_file=../rsa_private.pem - - - - -.. _Google Cloud IoT Core: https://cloud.google.com/iot/docs - -Setup -------------------------------------------------------------------------------- - - -Install Dependencies -++++++++++++++++++++ - -#. 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 2.7 and 3.4+. - - .. 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 -------------------------------------------------------------------------------- - -MQTT Device Client Example -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -.. 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/mqtt_example/receive.py;iot/api-client/mqtt_example/README.rst - - - - -To run this sample: - -.. code-block:: bash - - $ python receive.py - - usage: receive.py [-h] [--project_id PROJECT_ID] --registry_id REGISTRY_ID - --device_id DEVICE_ID --private_key_file PRIVATE_KEY_FILE - --algorithm {RS256,ES256} [--cloud_region CLOUD_REGION] - [--ca_certs CA_CERTS] - [--mqtt_bridge_hostname MQTT_BRIDGE_HOSTNAME] - [--mqtt_bridge_port {8883,443}] - [--jwt_expires_minutes JWT_EXPIRES_MINUTES] - - Example Google Cloud IoT Core MQTT device connection code. - - optional arguments: - -h, --help show this help message and exit - --project_id PROJECT_ID - GCP cloud project name - --registry_id REGISTRY_ID - Cloud IoT Core registry id - --device_id DEVICE_ID - Cloud IoT Core device id - --private_key_file PRIVATE_KEY_FILE - Path to private key file. - --algorithm {RS256,ES256} - Which encryption algorithm to use to generate the JWT. - --cloud_region CLOUD_REGION - GCP cloud region - --ca_certs CA_CERTS CA root from https://pki.google.com/roots.pem - --mqtt_bridge_hostname MQTT_BRIDGE_HOSTNAME - MQTT bridge hostname. - --mqtt_bridge_port {8883,443} - MQTT bridge port. - --jwt_expires_minutes JWT_EXPIRES_MINUTES - Expiration time, in minutes, for JWT tokens. - - - - - -.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/iot/api-client/beta-features/commands/receive/README.rst.in b/iot/api-client/beta-features/commands/receive/README.rst.in deleted file mode 100644 index 8a4294ec090..00000000000 --- a/iot/api-client/beta-features/commands/receive/README.rst.in +++ /dev/null @@ -1,36 +0,0 @@ -# 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. - - Before you run the sample, you must retrieve the Google root certificate. - For example, ``wget https://pki.goog/roots.pem`` or - ``curl https://pki.goog/roots.pem > roots.pem``. - - The following example runs the sample using the project ID ``blue-jet-123`` - and the device name ``my-python-device``:: - - python receive.py \ - --registry_id=my-registry \ - --project_id=blue-jet-123 \ - --device_id=my-python-device \ - --algorithm=RS256 \ - --private_key_file=../rsa_private.pem - -setup: -- install_deps - -samples: -- name: MQTT Device Client Example - file: receive.py - show_help: True - -cloud_client_library: false - -folder: iot/api-client/mqtt_example diff --git a/iot/api-client/beta-features/commands/receive/receive.py b/iot/api-client/beta-features/commands/receive/receive.py deleted file mode 100644 index 44ce86b36b7..00000000000 --- a/iot/api-client/beta-features/commands/receive/receive.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2018 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. -"""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 os -import ssl -import time - -import jwt -import paho.mqtt.client as mqtt -# [END iot_mqtt_includes] - -# 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 str for the JWT from the given project id and private key path, - set to expire in 60 minutes. After 60 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=60), - # 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) - 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) - client = mqtt.Client(client_id=client_id) - - password = create_jwt(project_id, private_key_file, algorithm) - - # 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=password) - - # 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. - print('Connecting with id: {} and pass: {}'.format(client_id, password)) - client.connect(mqtt_bridge_hostname, mqtt_bridge_port) - - # This is the topic that the device will receive configuration updates on. - mqtt_command_topic = '/devices/{}/commands/#'.format(device_id) - - # Subscribe to the config topic. - print('Subscribing to {}'.format(mqtt_command_topic)) - client.subscribe(mqtt_command_topic, qos=1) - - return client -# [END iot_mqtt_config] - - -if __name__ == '__main__': - # [START iot_mqtt_run] - """Parse command line arguments.""" - parser = argparse.ArgumentParser(description=( - 'Example Google Cloud IoT Core MQTT device connection code.')) - 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( - '--device_id', required=True, help='Cloud IoT Core device id') - parser.add_argument( - '--private_key_file', - required=True, help='Path to private key file.') - parser.add_argument( - '--algorithm', - choices=('RS256', 'ES256'), - required=True, - help='Which encryption algorithm to use to generate the JWT.') - parser.add_argument( - '--cloud_region', default='us-central1', help='GCP cloud region') - parser.add_argument( - '--ca_certs', - default='roots.pem', - help=('CA root from https://pki.google.com/roots.pem')) - 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( - '--jwt_expires_minutes', - default=20, - type=int, - help=('Expiration time, in minutes, for JWT tokens.')) - - args = parser.parse_args() - - # Add any JWT refresh logic here - 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) - - # Wait two minutes for commands, for production you may want while True - for i in range(1, 120): - # Process network events. - client.loop() - print('Sleeping...') - time.sleep(1) - - print('Finished.') - # [END iot_mqtt_run] diff --git a/iot/api-client/beta-features/commands/receive/receive_test.py b/iot/api-client/beta-features/commands/receive/receive_test.py deleted file mode 100644 index 0ed3cb461e8..00000000000 --- a/iot/api-client/beta-features/commands/receive/receive_test.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright 2018 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. -import io -import os -import sys -import time - - -# Add manager for bootstrapping device registry / device for testing -sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'send')) # noqa -from google.cloud import pubsub -import pytest -import send - -import receive - - -cloud_region = 'us-central1' -device_id_template = 'test-device-{}' -ca_cert_path = 'resources/roots.pem' -rsa_cert_path = 'resources/rsa_cert.pem' -rsa_private_path = 'resources/rsa_private.pem' -topic_id = 'test-device-events-{}'.format(int(time.time())) - -project_id = os.environ['GCLOUD_PROJECT'] -service_account_json = os.environ['GOOGLE_APPLICATION_CREDENTIALS'] - -pubsub_topic = 'projects/{}/topics/{}'.format(project_id, topic_id) -registry_id = 'test-registry-{}'.format(int(time.time())) - - -# TODO: Remove once possible -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 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.""" - client = send.get_client(service_account_json) - registry_parent = 'projects/{}/locations/{}'.format( - project_id, - cloud_region) - body = { - 'eventNotificationConfigs': [{ - 'pubsubTopicName': pubsub_topic - }], - 'id': registry_id - } - request = client.projects().locations().registries().create( - parent=registry_parent, body=body) - - response = request.execute() - print('Created registry') - return response - - -def delete_registry( - service_account_json, project_id, cloud_region, registry_id): - """Deletes the specified registry.""" - print('Delete registry') - client = send.get_client(service_account_json) - registry_name = 'projects/{}/locations/{}/registries/{}'.format( - project_id, cloud_region, registry_id) - - registries = client.projects().locations().registries() - return registries.delete(name=registry_name).execute() - - -def create_device( - service_account_json, project_id, cloud_region, registry_id, - device_id, certificate_file): - """Create a new device without authentication.""" - registry_name = 'projects/{}/locations/{}/registries/{}'.format( - project_id, cloud_region, registry_id) - - with io.open(certificate_file) as f: - certificate = f.read() - - client = send.get_client(service_account_json) - device_template = { - 'id': device_id, - 'credentials': [{ - 'publicKey': { - 'format': 'RSA_X509_PEM', - 'key': certificate - } - }] - } - - devices = client.projects().locations().registries().devices() - return devices.create(parent=registry_name, body=device_template).execute() - - -def delete_device( - service_account_json, project_id, cloud_region, registry_id, - device_id): - """Delete the device with the given id.""" - print('Delete device') - client = send.get_client(service_account_json) - registry_name = 'projects/{}/locations/{}/registries/{}'.format( - project_id, cloud_region, registry_id) - - device_name = '{}/devices/{}'.format(registry_name, device_id) - - devices = client.projects().locations().registries().devices() - return devices.delete(name=device_name).execute() - - -# Keep scaffolding from here -@pytest.fixture(scope='module') -def iot_topic(): - topic = 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_receive(iot_topic, capsys): - device_id = device_id_template.format('RSA256') - create_registry( - service_account_json, project_id, cloud_region, pubsub_topic, - registry_id) - create_device( - service_account_json, project_id, cloud_region, registry_id, - device_id, rsa_cert_path) - - # Exercize the functionality - client = receive.get_client( - project_id, cloud_region, registry_id, device_id, - rsa_private_path, 'RS256', ca_cert_path, - 'mqtt.googleapis.com', 443) - client.loop_start() - - # Pre-process commands - for i in range(1, 3): - client.loop() - time.sleep(1) - - send.send_command( - service_account_json, project_id, cloud_region, registry_id, - device_id, 'me want cookies') - - # Process commands - for i in range(1, 3): - client.loop() - time.sleep(1) - - # Clean up - delete_device( - service_account_json, project_id, cloud_region, registry_id, - device_id) - delete_registry( - service_account_json, project_id, cloud_region, registry_id) - - out, _ = capsys.readouterr() - assert 'on_connect' in out # Verify can connect - assert '\'me want cookies\'' in out # Verify can receive command diff --git a/iot/api-client/beta-features/commands/receive/resources/README.md b/iot/api-client/beta-features/commands/receive/resources/README.md deleted file mode 100644 index ba272ccaf74..00000000000 --- a/iot/api-client/beta-features/commands/receive/resources/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# 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/iot/api-client/beta-features/commands/receive/resources/rsa_cert.pem b/iot/api-client/beta-features/commands/receive/resources/rsa_cert.pem deleted file mode 100644 index d81ae7c4f43..00000000000 --- a/iot/api-client/beta-features/commands/receive/resources/rsa_cert.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC9TCCAd2gAwIBAgIJALM44e3ivEWkMA0GCSqGSIb3DQEBCwUAMBExDzANBgNV -BAMMBnVudXNlZDAeFw0xNzEyMDcwMDQ1MjdaFw0yNzEyMDUwMDQ1MjdaMBExDzAN -BgNVBAMMBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL4w -BxHuEyYdbiwKiD8yXY7vYpcygeOQ4/ZdEg3wCB2OuYcaFRcCuqLcTLMnuzdcL+y3 -HBjWkrRW658cg3NG93Vj0iwSrga6u24CGBNYV+h8MBvwaDxk+uubnd5M/Q2OyL1J -GiMxQ1blR/71Hr5hhqaQZ2+qOF6kuf1m9rLUtMUJwOKp/PjPDmy654ZGsFWFSZmy -eRpNzmGU+KJg0o+Qf+sm75a8gQZ8AsrqveW0S/8o+zAjD0SkPcd01QBmYzQhjbi/ -LGGITrzbaB3ld9umJBIcXfnYPYisJfwSsT/jFwiXhrhpxNNaIaKlTzlQIt5l8bSs -HXzJBbuIg5Jb/SyIEpkCAwEAAaNQME4wHQYDVR0OBBYEFOfaQTUVAoNb6fc7qzzl -uKyHGrCYMB8GA1UdIwQYMBaAFOfaQTUVAoNb6fc7qzzluKyHGrCYMAwGA1UdEwQF -MAMBAf8wDQYJKoZIhvcNAQELBQADggEBALKKDtiV1YV8k0YsNdiIXRlS3jsuoGuI -VVBrvDGz5Hel0rH9YmmfPS/Yn08kk3DF8Uynr4Xo1Zt9hmhgoq3ZoWm7MIP1+a9s -WyACyEMhVQSCzQrexRvG5ElpHx/vNjbcwiBkE5urlIvMBVt+BRRNKMNWq6F9ae63 -FxRp7CtNFSbibtLJuPgCs6qoNs0nlt2FPsNvs7jpPipj69o+egVckvQjAyppirWO -+jO5hCLy7EahLz2wCn90z0Xf9lhOZni9meaV1Vy3CHHg6jwIB8/XlRaHFrOGMGXg -h8eQqsmpk9/3o8pv00yj6Hkq+swVg7Rg9FZaUiOv/HO/J7stWU7qPbI= ------END CERTIFICATE----- diff --git a/iot/api-client/beta-features/commands/receive/resources/rsa_private.pem b/iot/api-client/beta-features/commands/receive/resources/rsa_private.pem deleted file mode 100644 index 06a66e3d40e..00000000000 --- a/iot/api-client/beta-features/commands/receive/resources/rsa_private.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+MAcR7hMmHW4s -Cog/Ml2O72KXMoHjkOP2XRIN8AgdjrmHGhUXArqi3EyzJ7s3XC/stxwY1pK0Vuuf -HINzRvd1Y9IsEq4GurtuAhgTWFfofDAb8Gg8ZPrrm53eTP0Njsi9SRojMUNW5Uf+ -9R6+YYamkGdvqjhepLn9Zvay1LTFCcDiqfz4zw5suueGRrBVhUmZsnkaTc5hlPii -YNKPkH/rJu+WvIEGfALK6r3ltEv/KPswIw9EpD3HdNUAZmM0IY24vyxhiE6822gd -5XfbpiQSHF352D2IrCX8ErE/4xcIl4a4acTTWiGipU85UCLeZfG0rB18yQW7iIOS -W/0siBKZAgMBAAECggEAfwLmBdRfl2m6JNFX0hSZpJY72kuRsN8XTnUzVHmDgfHJ -9u61POvGpnLHCjIzdjIrk0NqETBjQup1aooJQ1gWdKAYQPSsobPc7geZ+nlaI9mj -61Su1/58EBKZ6Faz/HTpnHeQbAY/OW3fmeYrBOtumBgB6/HauWH7D77Oa/lfS+Ij -4f6OVAxevsi6PUtNmNtBwk5S0lZl9SFcKeHurVindquX9vWZjBEEFtNXazJttIJS -z9KX29VYwoLfflIKaUKckn8X+wYc+3u3BvH8zJpd60yQ6MSo7Sb1XkxT9549m+JW -Cb+i1K7MC/yQo4mvDtAQIVBh8p8qpd4VjpBwMuUbgQKBgQDexuAaLO3adSYFXGwW -nom6Mz/ImYcpxYo0ouAR1talbmF5/oKl9Tcwh7l1eDHfe70gfeP+g4uwAcc1hx3a -ZtXusrJFBktFezlFQnZXaE5ppryrFWeu0he0RYLAVxnL6IlP9dYQhVsTZm+7uX5d -UP7aZtmOU9ZTEsAoqvjJQXvaCQKBgQDajPebXOxIUj8ffGTeiPZczTwXux04caDC -eFKSCbAlHWgG7mR4P3fQONfEGWNHF0CxBSrew9CHmKdPyiISaExCfUaUWDDCPQCp -UE5VAHPdjSlb4lqi+cyNVlJxBJGONtyYkbQNd6N9GHMnBS8jZi7zf8VzIXpeExA4 -n79Aml/YEQKBgDFrGId19AWD+z0xNWEHJjJB8CJFvHANvAzVHLOYXuEvzTvMs5qw -/N8tHHzsftO+lUPB6XOqJrCSlGhRYtPx//8FcPpS3Ru6rAerKKlXIB3buPqSsv9a -55s72DdmmvhayysLs8LSclOpY5vXGCsHLqGwMw6Zlm+zNyFOXAX5GspRAoGAaJMx -W68ABK8OM0OzhGQm9kriKTzIg5yjXspyQBzQo0HJ6B8kBgHgk8rPO68mOPsgYlPl -qogp/OgHjv9ahFJRwzLslckJM7g628loYfYAew+zrZrG4dsDjNG0Sw3zlAgeUAbQ -D+2iVhZf61josFiRuMP3t9paEi+vAFk4C3KSz/ECgYBpi1akpIzsYehW5uOL7Jhw -Hay5eshQ4vmHYuhDnn3gtT3h6J7TMwWs9pOygBG1I1b7GJ+tp4BZWJ2PmI7P8s45 -jdI99WODHwv03lAzjLwigoqDUDduaYqXcGghcGht5Sknkl2uYDChwLtI5JdBZ9/x -8h9dE9oAiH/KTzhPmK1E1Q== ------END PRIVATE KEY----- diff --git a/iot/api-client/beta-features/commands/send/requirements.txt b/iot/api-client/beta-features/commands/send/requirements.txt deleted file mode 100644 index fb06d0015e6..00000000000 --- a/iot/api-client/beta-features/commands/send/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -cryptography==2.4.2 -google-api-python-client==1.7.4 -google-auth-httplib2==0.0.3 -google-auth==1.6.1 -google-cloud-pubsub==0.38.0 -oauth2client==4.1.3 -paho-mqtt==1.4.0 -pyjwt==1.6.4 diff --git a/iot/api-client/beta-features/commands/send/send.py b/iot/api-client/beta-features/commands/send/send.py deleted file mode 100644 index 0da5c883ec0..00000000000 --- a/iot/api-client/beta-features/commands/send/send.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2018 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. - - -""" -Example of using the Google Cloud IoT Core device manager to administer -devices. - -Usage example: - - python send.py \\ - --device_id=your-device-id \\ - --project_id=your-project-id \\ - --send_command="Command to send" \\ - --registry_id=your-registry-id \\ - --service_account_json=/path/to/your/service_account.json \\ - send-command - -""" - -import argparse -import base64 -import os -import time - -from google.oauth2 import service_account -from googleapiclient import discovery - - -def get_client(service_account_json): - """Returns an authorized API client by discovering the IoT API using the - provided API key and creating a service object using the service account - credentials JSON.""" - # [START authorize] - 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) - # [END authorize] - - -def send_command( - service_account_json, project_id, cloud_region, registry_id, device_id, - command): - """Send a command to a device.""" - # [START send_command] - print('Sending command to device') - client = get_client(service_account_json) - device_path = 'projects/{}/locations/{}/registries/{}/devices/{}'.format( - project_id, cloud_region, registry_id, device_id) - - config_body = { - 'binaryData': base64.urlsafe_b64encode( - command.encode('utf-8')).decode('ascii') - } - - return client.projects( - ).locations().registries( - ).devices().sendCommandToDevice( - name=device_path, body=config_body).execute() - # [END send_command] - - -if __name__ == '__main__': - """Parse command line arguments.""" - default_registry = 'cloudiot_device_manager_example_registry_{}'.format( - int(time.time())) - - parser = argparse.ArgumentParser( - description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter) - - # Required arguments - parser.add_argument( - '--registry_id', - default=default_registry, - required=True, - help='Registry id. If not set, a name will be generated.') - parser.add_argument( - '--device_id', - required=True, - help='Device id.') - parser.add_argument( - '--send_command', - required=True, - help='The command sent to the device') - - # Optional arguments - parser.add_argument( # TODO: FIXME(class) switch to us-central1 - '--cloud_region', default='us-central1', help='GCP cloud region') - parser.add_argument( - '--project_id', - default=os.environ.get("GOOGLE_CLOUD_PROJECT"), - help='GCP cloud project name.') - 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('send-command', help=send_command.__doc__) - - args = parser.parse_args() - - print(args.command) - send_command( - args.service_account_json, args.project_id, - args.cloud_region, args.registry_id, args.device_id, - args.send_command) diff --git a/iot/api-client/beta-features/commands/send/send_test.py b/iot/api-client/beta-features/commands/send/send_test.py deleted file mode 100644 index a6895fde86e..00000000000 --- a/iot/api-client/beta-features/commands/send/send_test.py +++ /dev/null @@ -1,187 +0,0 @@ -# Copyright 2018 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. -import io -import os -import sys -import time - -# Add command receiver for bootstrapping device registry / device for testing -sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'receive')) # noqa -from google.cloud import pubsub -import pytest -import receive - -import send - -cloud_region = 'us-central1' -device_id_template = 'test-device-{}' -ca_cert_path = '../receive/resources/roots.pem' -rsa_cert_path = '../receive/resources/rsa_cert.pem' -rsa_private_path = '../receive/resources/rsa_private.pem' -topic_id = 'test-device-events-{}'.format(int(time.time())) - -project_id = os.environ['GCLOUD_PROJECT'] -service_account_json = os.environ['GOOGLE_APPLICATION_CREDENTIALS'] - -pubsub_topic = 'projects/{}/topics/{}'.format(project_id, topic_id) -registry_id = 'test-registry-{}'.format(int(time.time())) - - -# TODO: Remove once possible -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 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.""" - client = send.get_client(service_account_json) - registry_parent = 'projects/{}/locations/{}'.format( - project_id, - cloud_region) - body = { - 'eventNotificationConfigs': [{ - 'pubsubTopicName': pubsub_topic - }], - 'id': registry_id - } - request = client.projects().locations().registries().create( - parent=registry_parent, body=body) - - response = request.execute() - print('Created registry') - return response - - -def delete_registry( - service_account_json, project_id, cloud_region, registry_id): - """Deletes the specified registry.""" - print('Delete registry') - client = send.get_client(service_account_json) - registry_name = 'projects/{}/locations/{}/registries/{}'.format( - project_id, cloud_region, registry_id) - - registries = client.projects().locations().registries() - return registries.delete(name=registry_name).execute() - - -def create_device( - service_account_json, project_id, cloud_region, registry_id, - device_id, certificate_file): - """Create a new device without authentication.""" - registry_name = 'projects/{}/locations/{}/registries/{}'.format( - project_id, cloud_region, registry_id) - - with io.open(certificate_file) as f: - certificate = f.read() - - client = send.get_client(service_account_json) - device_template = { - 'id': device_id, - 'credentials': [{ - 'publicKey': { - 'format': 'RSA_X509_PEM', - 'key': certificate - } - }] - } - - devices = client.projects().locations().registries().devices() - return devices.create(parent=registry_name, body=device_template).execute() - - -def delete_device( - service_account_json, project_id, cloud_region, registry_id, - device_id): - """Delete the device with the given id.""" - print('Delete device') - client = send.get_client(service_account_json) - registry_name = 'projects/{}/locations/{}/registries/{}'.format( - project_id, cloud_region, registry_id) - - device_name = '{}/devices/{}'.format(registry_name, device_id) - - devices = client.projects().locations().registries().devices() - return devices.delete(name=device_name).execute() - - -# Keep scaffolding from here -@pytest.fixture(scope='module') -def iot_topic(): - topic = 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_send(iot_topic, capsys): - device_id = device_id_template.format('RSA256') - create_registry( - service_account_json, project_id, cloud_region, pubsub_topic, - registry_id) - create_device( - service_account_json, project_id, cloud_region, registry_id, - device_id, rsa_cert_path) - - # Exercize the functionality - client = receive.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, 3): - client.loop() - time.sleep(1) - - send.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, 3): - client.loop() - time.sleep(1) - - # Clean up - delete_device( - service_account_json, project_id, cloud_region, registry_id, - device_id) - delete_registry( - service_account_json, project_id, cloud_region, registry_id) - - assert 'Sending command to device' in out - assert '400' not in out diff --git a/iot/api-client/beta-features/commands/send/README.rst b/iot/api-client/beta-features/gateway/README.rst similarity index 50% rename from iot/api-client/beta-features/commands/send/README.rst rename to iot/api-client/beta-features/gateway/README.rst index f97d257a189..a915deb078e 100644 --- a/iot/api-client/beta-features/commands/send/README.rst +++ b/iot/api-client/beta-features/gateway/README.rst @@ -31,16 +31,10 @@ credentials for applications. 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 + .. _Python Development Environment Setup Guide: + https://cloud.google.com/python/setup #. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. @@ -61,11 +55,11 @@ Install Dependencies Samples ------------------------------------------------------------------------------- -Command sender +Cloud IoT Hub +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. 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=/send.py,/README.rst + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/hub.py;/README.rst @@ -74,45 +68,77 @@ To run this sample: .. code-block:: bash - $ python send.py + $ python hub.py - usage: send.py [-h] --registry_id REGISTRY_ID --device_id DEVICE_ID - --send_command SEND_COMMAND [--cloud_region CLOUD_REGION] - [--project_id PROJECT_ID] - [--service_account_json SERVICE_ACCOUNT_JSON] - {send-command} ... + usage: hub.py [-h] --registry_id REGISTRY_ID --device_id DEVICE_ID + --gateway_id GATEWAY_ID [--cloud_region CLOUD_REGION] + [--data DATA] [--project_id PROJECT_ID] + [--service_account_json SERVICE_ACCOUNT_JSON] + [--jwt_expires_minutes JWT_EXPIRES_MINUTES] + [--certificate_path CERTIFICATE_PATH] + [--num_messages NUM_MESSAGES] + [--private_key_file PRIVATE_KEY_FILE] [--ca_certs CA_CERTS] + [--algorithm {RS256,ES256}] + {create_gateway,bind_device_to_gateway,unbind_device_from_gateway,list_devices_for_gateway,list_gateways,send_data_from_bound_device,listen_for_config_messages} + ... - Example of using the Google Cloud IoT Core device manager to administer - devices. + Example of using the Google Cloud IoT Core device manager to send telemetry + messages on behalf of other devices. Usage example: - python send.py \ - --device_id=your-device-id \ + python hub.py \ + --device_id=bound-device-id \ + --gateway_id=your-gateway-id \ --project_id=your-project-id \ - --send_command="Command to send" \ + --data="optional telemetry data" \ --registry_id=your-registry-id \ --service_account_json=/path/to/your/service_account.json \ - send-command + create_gateway positional arguments: - {send-command} - send-command Send a command to a device. + {create_gateway,bind_device_to_gateway,unbind_device_from_gateway,list_devices_for_gateway,list_gateways,send_data_from_bound_device,listen_for_config_messages} + create_gateway Create a gateway to bind devices to. + bind_device_to_gateway + Binds a device to a gateway. + unbind_device_from_gateway + Unbinds a device to a gateway. + list_devices_for_gateway + List devices bound to a gateway + list_gateways Lists gateways in a registry + send_data_from_bound_device + Sends data from a gateway on behalf of a device that + is bound to it. + listen_for_config_messages + Listens for configuration messages on the hub and + bound devices. optional arguments: -h, --help show this help message and exit --registry_id REGISTRY_ID Registry id. If not set, a name will be generated. --device_id DEVICE_ID - Device id. - --send_command SEND_COMMAND - The command sent to the device + Device identifier. + --gateway_id GATEWAY_ID + Gateway identifier. --cloud_region CLOUD_REGION GCP cloud region + --data DATA The telemetry data sent on behalf of a device --project_id PROJECT_ID GCP cloud project name. --service_account_json SERVICE_ACCOUNT_JSON Path to service account json file. + --jwt_expires_minutes JWT_EXPIRES_MINUTES + Expiration time (in minutes) for JWT tokens. + --certificate_path CERTIFICATE_PATH + Path to public certificate. + --num_messages NUM_MESSAGES + Number of messages to send. + --private_key_file PRIVATE_KEY_FILE + Path to private key file. + --ca_certs CA_CERTS CA root from https://pki.google.com/roots.pem + --algorithm {RS256,ES256} + Which encryption algorithm to use to generate the JWT. diff --git a/iot/api-client/beta-features/commands/send/README.rst.in b/iot/api-client/beta-features/gateway/README.rst.in similarity index 77% rename from iot/api-client/beta-features/commands/send/README.rst.in rename to iot/api-client/beta-features/gateway/README.rst.in index 7f5831d91f5..7677ebeb5ce 100644 --- a/iot/api-client/beta-features/commands/send/README.rst.in +++ b/iot/api-client/beta-features/gateway/README.rst.in @@ -14,8 +14,11 @@ setup: - install_deps samples: -- name: Command sender - file: send.py +- name: Cloud IoT Gateway sample + file: gateway.py + show_help: True +- name: Cloud IoT Gateway demo + file: gateway_demo.py show_help: True cloud_client_library: false diff --git a/iot/api-client/beta-features/gateway/gateway.py b/iot/api-client/beta-features/gateway/gateway.py new file mode 100644 index 00000000000..8a6c718ffd0 --- /dev/null +++ b/iot/api-client/beta-features/gateway/gateway.py @@ -0,0 +1,727 @@ +#!/usr/bin/env python + +# Copyright 2018 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. + + +""" +Example of using the Google Cloud IoT Core device manager to send telemetry +messages on behalf of other devices. + +Usage example: + + python gateway.py \\ + --device_id=bound-device-id \\ + --gateway_id=your-gateway-id \\ + --project_id=your-project-id \\ + --data="optional telemetry data" \\ + --registry_id=your-registry-id \\ + --service_account_json=/path/to/your/service_account.json \\ + create_gateway + +""" + +import argparse +import datetime +import io +import os +import random +import ssl +import time +import re + +from google.oauth2 import service_account +from googleapiclient import discovery + +# [START iot_gateway_mqtt_includes] +# For sending telemetry and receiving commands +import jwt +import paho.mqtt.client as mqtt +# [END iot_gateway_mqtt_includes] + +# [START iot_gateway_mqtt_variables] +# 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 + +mqtt_bridge_hostname = 'mqtt.googleapis.com' +mqtt_bridge_port = 8883 +# [END iot_gateway_mqtt_variables] + + +# [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: + An MQTT 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=60), + # 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] + + +def get_client(service_account_json): + """Returns an authorized API client by discovering the IoT API using the + provided API key and creating a service object using the service account + credentials JSON.""" + # [START authorize] + api_scopes = ['https://www.googleapis.com/auth/cloud-platform'] + api_version = 'v1' + discovery_api = 'https://cloudiot.googleapis.com/$discovery/rest' + labels = 'CLOUD_IOT_ALPHA' + + # Used to authorize the request for the discovery document + # Generated from https://console.cloud.google.com/apis/credentials + # TODO(class) remove before publish + key = 'AIzaSyCE3D0dO5rO67-VbACI0IPS6KIg888MTzg' + service_name = 'cloudiotcore' + credentials = service_account.Credentials.from_service_account_file( + service_account_json) + scoped_credentials = credentials.with_scopes(api_scopes) + discovery_url = '{}?version={}&key={}&labels={}'.format( + discovery_api, api_version, key, labels) + + return discovery.build( + service_name, + api_version, + discoveryServiceUrl=discovery_url, + credentials=scoped_credentials) + + # [END authorize] + + +def create_gateway( + service_account_json, project_id, cloud_region, registry_id, device_id, + gateway_id, certificate_file, algorithm): + # [START create_gateway] + """Create a gateway to bind devices to.""" + # Check that the gateway doesn't already exist + exists = False + client = get_client(service_account_json) + registry_path = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + devices = client.projects().locations().registries().devices( + ).list( + parent=registry_path, fieldMask='config,gatewayConfig' + ).execute().get('devices', []) + + for device in devices: + if device.get('id') == gateway_id: + exists = True + print('Device: {} : {} : {} : {}'.format( + device.get('id'), + device.get('numId'), + device.get('config'), + device.get('gatewayConfig') + )) + + # Create the gateway + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + 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': [{ + 'publicKey': { + 'format': certificate_format, + 'key': certificate + } + }], + 'gatewayConfig': { + 'gatewayType': 'GATEWAY', + 'gatewayAuthMethod': 'ASSOCIATION_ONLY' + } + } + devices = client.projects().locations().registries().devices() + + if not exists: + res = devices.create( + parent=registry_name, body=device_template).execute() + print('Created gateway {}'.format(res)) + else: + print('Gateway exists, skipping') + # [END create_gateway] + + +def create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id): + """Create a device to bind to a gateway.""" + # [START create_device] + # Check that the device doesn't already exist + exists = False + + client = get_client(service_account_json) + registry_path = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + devices = client.projects().locations().registries().devices( + ).list( + parent=registry_path, fieldMask='config,gatewayConfig' + ).execute().get('devices', []) + + for device in devices: + if device.get('id') == device_id: + exists = True + + # Create the device + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + device_template = { + 'id': device_id, + 'gatewayConfig': { + 'gatewayType': 'NON_GATEWAY', + 'gatewayAuthMethod': 'ASSOCIATION_ONLY' + } + } + devices = client.projects().locations().registries().devices() + + if not exists: + res = devices.create( + parent=registry_name, body=device_template).execute() + print('Created Device {}'.format(res)) + else: + print('Device exists, skipping') + # [END create_device] + + +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 bind_device_to_gateway] + client = get_client(service_account_json) + + create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + bind_request = { + 'deviceId': device_id, + 'gatewayId': gateway_id + } + client.projects().locations().registries().bindDeviceToGateway( + parent=registry_name, body=bind_request).execute() + print('Device Bound!') + # [END 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 unbind_device_from_gateway] + client = get_client(service_account_json) + + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + bind_request = { + 'deviceId': device_id, + 'gatewayId': gateway_id + } + + res = client.projects().locations().registries().unbindDeviceFromGateway( + parent=registry_name, body=bind_request).execute() + print('Device unbound: {}'.format(res)) + # [END unbind_device_from_gateway] + + +def list_gateways( + service_account_json, project_id, cloud_region, registry_id): + """Lists gateways in a registry""" + # [START list_gateways] + client = get_client(service_account_json) + registry_path = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + devices = client.projects().locations().registries().devices( + ).list( + parent=registry_path, fieldMask='config,gatewayConfig' + ).execute().get('devices', []) + + for device in devices: + if device.get('gatewayConfig') is not None: + if device.get('gatewayConfig').get('gatewayType') == 'GATEWAY': + print('Gateway ID: {}\n\t{}'.format(device.get('id'), device)) + # [END 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 list_devices_for_gateway] + client = get_client(service_account_json) + + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + gateway_name = '{}/devices/{}'.format( + registry_name, gateway_id) + + devices = client.projects().locations().registries().devices( + ).listDeviceIdsForGateway(gatewayName=gateway_name).execute() + + if devices.get('deviceNumIds') is not None: + for device_id in devices.get('deviceNumIds'): + device_name = '{}/devices/{}'.format( + registry_name, device_id) + device = client.projects().locations().registries().devices().get( + name=device_name).execute() + print('Id: {}\n\tName: {}\n\traw: {}'.format( + device_id, device.get('id'), device)) + else: + print('No devices bound to gateway {}'.format(gateway_id)) + # [END list_devices_for_gateway] + + +# [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_subscribe( + unused_client, unused_userdata, unused_mid, unused_granted_qos): + """Paho callback when client subscribes to a topic..""" + print('on_subscribe') + + +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) + messageType = 'message' + if(re.match( + r'/devices/[A-Za-z0-9_-]+/errors', message.topic, re.M | re.I)): + messageType = 'ERROR ' + messageType + print('Received {} \'{}\' on topic \'{}\' with Qos {}'.format( + messageType, payload, message.topic, str(message.qos))) + + +def get_mqtt_client( + project_id, cloud_region, registry_id, gateway_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 = mqtt.Client( + client_id=('projects/{}/locations/{}/registries/{}/devices/{}' + .format( + project_id, + cloud_region, + registry_id, + gateway_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 + client.on_subscribe = on_subscribe + + # Connect to the Google MQTT bridge. + client.connect(mqtt_bridge_hostname, mqtt_bridge_port) + + return client +# [END iot_mqtt_config] + + +def detach_device(client, device_id): + """Detach the device from the gateway.""" + # [START detach_device] + detach_topic = '/devices/{}/detach'.format(device_id) + print('Detaching: {}'.format(detach_topic)) + client.loop() + client.connect(mqtt_bridge_hostname, mqtt_bridge_port) + client.publish(detach_topic, '{}', qos=1) + time.sleep(5) # wait for the server to respond / will trigger callback + # [END detach_device] + + +def attach_device(client, device_id): + """Attach the device to the gateway.""" + # [START attach_device] + attach_topic = '/devices/{}/attach'.format(device_id) + print('Attaching: {}'.format(attach_topic)) + # TODO {'authorization': ''} + attach_payload = '{}' + client.loop() + client.publish(attach_topic, attach_payload, qos=1) + time.sleep(5) + # [END attach_device] + + +def listen_for_config_and_error_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 configuration and system error messages on the gateway and + bound devices.""" + # [START listen_for_config_messages] + global minimum_backoff_time + + jwt_iat = datetime.datetime.utcnow() + jwt_exp_mins = jwt_expires_minutes + # Use gateway to connect to server + client = get_mqtt_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 = get_mqtt_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 listen_for_config_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_mqtt_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 HUB at: {}'.format(time.time()) + print(gateway_state) + client.publish(gateway_topic, gateway_state, qos=1) + + # Publish num_messages mesages 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_mqtt_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.""" + default_registry = 'cloudiot_device_manager_example_registry_{}'.format( + int(time.time())) + + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + + # Required arguments + parser.add_argument( + '--registry_id', + default=default_registry, + required=True, + help='Registry id. If not set, a name will be generated.') + parser.add_argument( + '--device_id', + required=True, + help='Device identifier.') + parser.add_argument( + '--gateway_id', + required=True, + help='Gateway identifier.') + + # Optional arguments + 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( + '--project_id', + default=os.environ.get("GOOGLE_CLOUD_PROJECT"), + help='GCP cloud project name.') + parser.add_argument( + '--service_account_json', + default=os.environ.get("GOOGLE_APPLICATION_CREDENTIALS"), + help='Path to service account json file.') + + parser.add_argument( + '--jwt_expires_minutes', + default=60, + help='Expiration time (in minutes) for JWT tokens.') + parser.add_argument( + '--listen_dur', + default=60, + help='Duration (seconds) to listen for configuration messages') + parser.add_argument( + '--certificate_path', + help='Path to public certificate.') + parser.add_argument( + '--num_messages', + default=10, + type=int, + help='Number of messages to send.') + parser.add_argument( + '--private_key_file', + help='Path to private key file.') + parser.add_argument( + '--ca_certs', + default='roots.pem', + help=('CA root from https://pki.google.com/roots.pem')) + parser.add_argument( + '--algorithm', + choices=('RS256', 'ES256'), + help='Which encryption algorithm to use to generate the JWT.') + + # Command subparser + command = parser.add_subparsers(dest='command') + + command.add_parser( + 'create_gateway', + help=create_gateway.__doc__) + + command.add_parser( + 'bind_device_to_gateway', + help=bind_device_to_gateway.__doc__) + + command.add_parser( + 'unbind_device_from_gateway', + help=unbind_device_from_gateway.__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( + 'send_data_from_bound_device', + help=send_data_from_bound_device.__doc__) + + command.add_parser( + 'listen_for_config_messages', + help=listen_for_config_and_error_messages.__doc__) + + return parser.parse_args() + + +def run_command(args): + """Calls the program using the specified command.""" + if 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 == '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 == '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) + elif args.command == 'list_gateways': + list_gateways( + 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 == 'listen_for_config_messages': + listen_for_config_and_error_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, mqtt_bridge_hostname, + mqtt_bridge_port, args.jwt_expires_minutes, args.listen_dur) + elif args.command == 'send_data_from_bound_device': + 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, mqtt_bridge_hostname, + mqtt_bridge_port, args.jwt_expires_minutes, args.data) + + +if __name__ == '__main__': + args = parse_command_line_args() + run_command(args) diff --git a/iot/api-client/beta-features/gateway/gateway_demo.py b/iot/api-client/beta-features/gateway/gateway_demo.py new file mode 100644 index 00000000000..1582858811e --- /dev/null +++ b/iot/api-client/beta-features/gateway/gateway_demo.py @@ -0,0 +1,259 @@ +# Copyright 2018 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. +# [START iot_gateway_demo] +import csv +import datetime +import io +import logging +import os +import time + +from google.cloud import pubsub + +# import manager # TODO(class) when feature exits beta, remove borrowed defs +import gateway + +logging.getLogger('googleapiclient.discovery_cache').setLevel(logging.CRITICAL) + +cloud_region = 'us-central1' +device_id_template = 'test-device-{}' +gateway_id_template = 'test-gateway-{}' +topic_id = 'test-device-events-{}'.format(int(time.time())) + +ca_cert_path = 'resources/roots.pem' +log_path = 'config_log.csv' +rsa_cert_path = 'resources/rsa_cert.pem' +rsa_private_path = 'resources/rsa_private.pem' + +if ('GCLOUD_PROJECT' not in os.environ or + 'GOOGLE_APPLICATION_CREDENTIALS' not in os.environ): + print( + 'You must set GCLOUD_PROJECT and GOOGLE_APPLICATION_CREDENTIALS') + quit() + +project_id = os.environ['GCLOUD_PROJECT'] +service_account_json = os.environ['GOOGLE_APPLICATION_CREDENTIALS'] + +pubsub_topic = 'projects/{}/topics/{}'.format(project_id, topic_id) +registry_id = 'test-registry-{}'.format(int(time.time())) + +base_url = 'https://console.cloud.google.com/iot/locations/{}'.format( + cloud_region) +edit_template = '{}/registries/{}?project={}'.format( + base_url, '{}', '{}') + +device_url_template = '{}/registries/{}/devices/{}?project={}'.format( + base_url, '{}', '{}', '{}') + +mqtt_bridge_hostname = 'mqtt.googleapis.com' +mqtt_bridge_port = 8883 + +num_messages = 15 +jwt_exp_time = 20 +listen_time = 30 + + +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 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.""" + client = gateway.get_client(service_account_json) + registry_parent = 'projects/{}/locations/{}'.format( + project_id, + cloud_region) + body = { + 'eventNotificationConfigs': [{ + 'pubsubTopicName': pubsub_topic + }], + 'id': registry_id + } + request = client.projects().locations().registries().create( + parent=registry_parent, body=body) + + response = request.execute() + print('Created registry') + return response + + +def delete_registry( + service_account_json, project_id, cloud_region, registry_id): + """Deletes the specified registry.""" + print('Delete registry') + client = gateway.get_client(service_account_json) + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + registries = client.projects().locations().registries() + return registries.delete(name=registry_name).execute() + + +def create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, certificate_file): + """Create a new device without authentication.""" + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + with io.open(certificate_file) as f: + certificate = f.read() + + client = gateway.get_client(service_account_json) + device_template = { + 'id': device_id, + 'credentials': [{ + 'publicKey': { + 'format': 'RSA_X509_PEM', + 'key': certificate + } + }] + } + + devices = client.projects().locations().registries().devices() + return devices.create(parent=registry_name, body=device_template).execute() + + +def delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id): + """Delete the device with the given id.""" + print('Delete device') + client = gateway.get_client(service_account_json) + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + device_name = '{}/devices/{}'.format(registry_name, device_id) + + devices = client.projects().locations().registries().devices() + return devices.delete(name=device_name).execute() + + +if __name__ == '__main__': + print("Running demo") + + gateway_id = device_id_template.format('RS256') + device_id = device_id_template.format('noauthbind') + + # [START iot_gateway_demo_create_registry] + print('Creating registry: {}'.format(registry_id)) + create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + # [END iot_gateway_demo_create_registry] + + # [START iot_gateway_demo_create_gateway] + print('Creating gateway: {}'.format(gateway_id)) + gateway.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + # [END iot_gateway_demo_create_gateway] + + # [START iot_gateway_demo_create_bound_device] + print('Creating device to bind: {}'.format(device_id)) + gateway.create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + # [END iot_gateway_demo_create_bound_device] + + # [START iot_gateway_demo_bind_device] + print('Binding device') + gateway.bind_device_to_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + # [END iot_gateway_demo_bind_device] + + # [START iot_gateway_demo_listen] + print('Listening for messages for {} seconds'.format(listen_time)) + print('Try setting configuration in: ') + print('\t{}'.format(edit_template.format(registry_id, project_id))) + try: + input("Press enter to continue") + except SyntaxError: + pass + + def log_callback(client): + def log_on_message(unused_client, unused_userdata, message): + if not os.path.exists(log_path): + with open(log_path, 'w') as csvfile: + logwriter = csv.writer(csvfile, dialect='excel') + logwriter.writerow(['time', 'topic', 'data']) + + with open(log_path, 'a') as csvfile: + logwriter = csv.writer(csvfile, dialect='excel') + logwriter.writerow([ + datetime.datetime.now().isoformat(), + message.topic, + message.payload]) + + client.on_message = log_on_message + + gateway.listen_for_config_messages( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id, num_messages, rsa_private_path, 'RS256', + ca_cert_path, mqtt_bridge_hostname, mqtt_bridge_port, + jwt_exp_time, listen_time, log_callback) + # [END iot_gateway_demo_listen] + + # [START iot_gateway_demo_publish] + print('Publishing messages demo') + print('Publishing: {} messages'.format(num_messages)) + gateway.send_data_from_bound_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id, num_messages, rsa_private_path, 'RS256', + ca_cert_path, mqtt_bridge_hostname, mqtt_bridge_port, + jwt_exp_time, "Hello from gateway_demo.py") + + print('You can read the state messages for your device at this URL:') + print('\t{}'.format(device_url_template).format( + registry_id, device_id, project_id)) + try: + input('Press enter to continue after reading the messages.') + except SyntaxError: + pass + # [END iot_gateway_demo_publish] + + # [START iot_gateway_demo_cleanup] + # Clean up + gateway.unbind_device_from_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + delete_registry( + service_account_json, project_id, cloud_region, registry_id) + # [END iot_gateway_demo_cleanup] + +# [END iot_gateway_demo] diff --git a/iot/api-client/beta-features/gateway/gateway_test.py b/iot/api-client/beta-features/gateway/gateway_test.py new file mode 100644 index 00000000000..974accfb0cd --- /dev/null +++ b/iot/api-client/beta-features/gateway/gateway_test.py @@ -0,0 +1,377 @@ +# Copyright 2018 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. +import io +import os +import sys +import time + +# Add command receiver for bootstrapping device registry / device for testing +sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'receive')) # noqa +from google.cloud import pubsub +import pytest + +import gateway + +cloud_region = 'us-central1' +device_id_template = 'test-device-{}' +gateway_id_template = 'test-gateway-{}' +ca_cert_path = 'resources/roots.pem' +rsa_cert_path = 'resources/rsa_cert.pem' +rsa_private_path = 'resources/rsa_private.pem' +topic_id = 'test-device-events-{}'.format(int(time.time())) + +project_id = os.environ['GCLOUD_PROJECT'] +service_account_json = os.environ['GOOGLE_APPLICATION_CREDENTIALS'] + +pubsub_topic = 'projects/{}/topics/{}'.format(project_id, topic_id) +registry_id = 'test-registry-{}'.format(int(time.time())) + +mqtt_bridge_hostname = 'mqtt.googleapis.com' +mqtt_bridge_port = 443 + + +# TODO: Remove once possible +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 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.""" + client = gateway.get_client(service_account_json) + registry_parent = 'projects/{}/locations/{}'.format( + project_id, + cloud_region) + body = { + 'eventNotificationConfigs': [{ + 'pubsubTopicName': pubsub_topic + }], + 'id': registry_id + } + request = client.projects().locations().registries().create( + parent=registry_parent, body=body) + + response = request.execute() + print('Created registry') + return response + + +def delete_registry( + service_account_json, project_id, cloud_region, registry_id): + """Deletes the specified registry.""" + print('Delete registry') + client = gateway.get_client(service_account_json) + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + registries = client.projects().locations().registries() + return registries.delete(name=registry_name).execute() + + +def create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, certificate_file): + """Create a new device without authentication.""" + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + with io.open(certificate_file) as f: + certificate = f.read() + + client = gateway.get_client(service_account_json) + device_template = { + 'id': device_id, + 'credentials': [{ + 'publicKey': { + 'format': 'RSA_X509_PEM', + 'key': certificate + } + }] + } + + devices = client.projects().locations().registries().devices() + return devices.create(parent=registry_name, body=device_template).execute() + + +def delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id): + """Delete the device with the given id.""" + print('Delete device') + client = gateway.get_client(service_account_json) + registry_name = 'projects/{}/locations/{}/registries/{}'.format( + project_id, cloud_region, registry_id) + + device_name = '{}/devices/{}'.format(registry_name, device_id) + + devices = client.projects().locations().registries().devices() + return devices.delete(name=device_name).execute() + + +# Keep scaffolding from here +@pytest.fixture(scope='module') +def iot_topic(): + topic = 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_gateway(iot_topic, capsys): + gateway_id = device_id_template.format('RS256') + create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + # TODO: consider adding test for ES256 + gateway.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + + # Clean up + delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + + assert 'Created gateway' in out + assert '400' not in out + + +def test_list_gateways(iot_topic, capsys): + gateway_id = device_id_template.format('RS256') + create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + + # TODO: consider adding test for ES256 + gateway.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + + gateway.list_gateways( + service_account_json, project_id, cloud_region, registry_id) + + # Clean up + delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + + assert 'Gateway ID: {}'.format(gateway_id) in out + assert '400' not in out + + +def test_bind_device_to_gateway_and_unbind(iot_topic, capsys): + gateway_id = device_id_template.format('RS256') + device_id = device_id_template.format('noauthbind') + create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + gateway.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + + gateway.create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + + gateway.bind_device_to_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + gateway.unbind_device_from_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + + # Clean up + delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + 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 '400' not in out + + +def test_gateway_listen_for_bound_device_configs(iot_topic, capsys): + gateway_id = device_id_template.format('RS256') + device_id = device_id_template.format('noauthbind') + create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + gateway.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + gateway.create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + gateway.bind_device_to_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + + # Setup for listening for config messages + num_messages = 0 + jwt_exp_time = 20 + listen_time = 5 + + # Connect the gateway + gateway.listen_for_config_and_error_messages( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id, num_messages, rsa_private_path, + 'RS256', ca_cert_path, mqtt_bridge_hostname, mqtt_bridge_port, + jwt_exp_time, listen_time, None) + # Clean up + gateway.unbind_device_from_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + assert 'Received message' in out + + +def test_gateway_send_data_for_device(iot_topic, capsys): + gateway_id = device_id_template.format('RS256') + device_id = device_id_template.format('noauthbind') + create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + gateway.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + gateway.create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + gateway.bind_device_to_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + + # Setup for listening for config messages + num_messages = 5 + jwt_exp_time = 20 + listen_time = 5 + + # Connect the gateway + gateway.send_data_from_bound_device( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id, num_messages, rsa_private_path, + 'RS256', ca_cert_path, mqtt_bridge_hostname, mqtt_bridge_port, + jwt_exp_time, listen_time) + + # Clean up + gateway.unbind_device_from_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + assert 'Publishing message 5/5' in out + assert 'Out of memory' not in out # Indicates could not connect + + +def test_gateway_trigger_error_topic(iot_topic, capsys): + gateway_id = device_id_template.format('RS256-err') + device_id = device_id_template.format('noauthbind') + create_registry( + service_account_json, project_id, cloud_region, pubsub_topic, + registry_id) + gateway.create_gateway( + service_account_json, project_id, cloud_region, registry_id, + None, gateway_id, rsa_cert_path, 'RS256') + gateway.create_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + gateway.bind_device_to_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + + # Setup for listening for config messages + num_messages = 4 + jwt_exp_time = 30 + listen_time = 5 + + # Callback for causing an error + def trigger_error(client): + gateway.attach_device(client, 'invalid_device_id') + + # Connect the gateway + # Connect the gateway + gateway.listen_for_config_and_error_messages( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id, num_messages, rsa_private_path, + 'RS256', ca_cert_path, mqtt_bridge_hostname, mqtt_bridge_port, + jwt_exp_time, listen_time, trigger_error) + + # Clean up + gateway.unbind_device_from_gateway( + service_account_json, project_id, cloud_region, registry_id, + device_id, gateway_id) + delete_device( + service_account_json, project_id, cloud_region, registry_id, + device_id) + delete_device( + service_account_json, project_id, cloud_region, registry_id, + gateway_id) + delete_registry( + service_account_json, project_id, cloud_region, registry_id) + + out, _ = capsys.readouterr() + assert 'Received ERROR message' in out + assert 'Out of memory' not in out # Indicates could not connect diff --git a/iot/api-client/beta-features/commands/receive/requirements.txt b/iot/api-client/beta-features/gateway/requirements.txt similarity index 68% rename from iot/api-client/beta-features/commands/receive/requirements.txt rename to iot/api-client/beta-features/gateway/requirements.txt index fb06d0015e6..51ee928f1a3 100644 --- a/iot/api-client/beta-features/commands/receive/requirements.txt +++ b/iot/api-client/beta-features/gateway/requirements.txt @@ -1,8 +1,8 @@ -cryptography==2.4.2 google-api-python-client==1.7.4 google-auth-httplib2==0.0.3 -google-auth==1.6.1 -google-cloud-pubsub==0.38.0 oauth2client==4.1.3 -paho-mqtt==1.4.0 +google-auth==1.5.1 +google-cloud-pubsub==0.38.0 +cryptography==2.3.1 pyjwt==1.6.4 +paho-mqtt==1.3.1 diff --git a/iot/api-client/beta-features/commands/receive/resources/roots.pem b/iot/api-client/beta-features/gateway/resources/roots.pem similarity index 64% rename from iot/api-client/beta-features/commands/receive/resources/roots.pem rename to iot/api-client/beta-features/gateway/resources/roots.pem index 0d3e4c8447c..e68993aa4c3 100644 --- a/iot/api-client/beta-features/commands/receive/resources/roots.pem +++ b/iot/api-client/beta-features/gateway/resources/roots.pem @@ -32,39 +32,6 @@ 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 @@ -99,73 +66,6 @@ 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 @@ -268,74 +168,6 @@ QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl 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 @@ -404,41 +236,6 @@ 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 @@ -745,6 +542,35 @@ r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE----- +# Operating CA: DigiCert +# 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: 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. @@ -876,6 +702,126 @@ bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er fF6adulZkMV8gzURZVE= -----END CERTIFICATE----- +# Operating CA: Entrust Datacard +# 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: Entrust Datacard +# 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: Entrust Datacard +# 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: Entrust Datacard +# 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: 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 @@ -906,37 +852,6 @@ 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 @@ -967,28 +882,6 @@ 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 @@ -1208,610 +1101,57 @@ 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 +# Operating CA: Google Trust Services LLC +# 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----- -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== +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: 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 +# Operating CA: Google Trust Services LLC +# 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----- -MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC -VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ -cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ -BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt -VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D -0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 -ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G -A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs -aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I -flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= -----END CERTIFICATE----- # Operating CA: Google Trust Services LLC diff --git a/iot/api-client/beta-features/gateway/resources/rsa_cert.pem b/iot/api-client/beta-features/gateway/resources/rsa_cert.pem new file mode 100644 index 00000000000..22c67d0df92 --- /dev/null +++ b/iot/api-client/beta-features/gateway/resources/rsa_cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC+DCCAeCgAwIBAgIJAPDD+L2jOpRBMA0GCSqGSIb3DQEBCwUAMBExDzANBgNV +BAMMBnVudXNlZDAeFw0xODEyMDcxOTA3NDhaFw0yODEyMDQxOTA3NDhaMBExDzAN +BgNVBAMMBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANlz +KMj0cYzNFniSZL0IBaGbR5zJ+RtYJ3+aal+QbjRm2A6+hZXvFDIIqefdBD/7BryI +kxv/KF7brYgFiRu7zLr+Gp1HrW914Z74AX/0zBz+H/gykA45X/1zdVDD3z//WTgi +RuLNx7nFxOajUvXeVttYEBz7Si6xwEB+zEKxm+uxTbScTC1ghuB6Lc0SV0NSuKae +3lkUNaKL6A0Xwi1sGFiDnl9cpEAk+JRls9SVXzuyzP0lAxzkBy8jCawzyEQmvDeG +8eEm1KgsC75zMYJUus05tHcB19sRUqwUT1OYivn1ZPvSJvQlFLZ68JzGoC0kLvYP +d/K15HRz4m99aZWQuyMCAwEAAaNTMFEwHQYDVR0OBBYEFLbz1KrCj11KQMA0Ug4I +k63Ns4fXMB8GA1UdIwQYMBaAFLbz1KrCj11KQMA0Ug4Ik63Ns4fXMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBALxfdum3gLovxauw21I/ePlDi0sE +Xnid9+oh7X35bWNBvHGjYv6a52T5Q0GMGQtsU7Oq2FkjRBglmukwR16BsOnR6IY0 +sxebUYZc/zD5sgcTAdUAF5EkuL5MYcVdA2mCXmVcLP7hthPOGHFHlSrYFvLIBc7a +eJVX2aToAJzoK/SunFcyIP8lgKYsgz/7RNn5/VMVIW+cAwqCrK1koHO2WQjO7pAD +wDGJUO/kcCVmRUhuVKEbiUpCgS46CKra5FZNeVNeXONfed5t1VDu4ERF962agPMq +tWr44c5jINxWFXnsbRkgnmasCM6OR9QIzU1iYWFaXXztJlBb1zx+Wpq8mqU= +-----END CERTIFICATE----- diff --git a/iot/api-client/beta-features/gateway/resources/rsa_private.pem b/iot/api-client/beta-features/gateway/resources/rsa_private.pem new file mode 100644 index 00000000000..bb60a8b8005 --- /dev/null +++ b/iot/api-client/beta-features/gateway/resources/rsa_private.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDZcyjI9HGMzRZ4 +kmS9CAWhm0ecyfkbWCd/mmpfkG40ZtgOvoWV7xQyCKnn3QQ/+wa8iJMb/yhe262I +BYkbu8y6/hqdR61vdeGe+AF/9Mwc/h/4MpAOOV/9c3VQw98//1k4Ikbizce5xcTm +o1L13lbbWBAc+0ouscBAfsxCsZvrsU20nEwtYIbgei3NEldDUrimnt5ZFDWii+gN +F8ItbBhYg55fXKRAJPiUZbPUlV87ssz9JQMc5AcvIwmsM8hEJrw3hvHhJtSoLAu+ +czGCVLrNObR3AdfbEVKsFE9TmIr59WT70ib0JRS2evCcxqAtJC72D3fyteR0c+Jv +fWmVkLsjAgMBAAECggEBALVAMzfF4Twu2tMnm0ahgCgjiX6cL8LmKQ5IxO/hMKsH +KoKntiuyu4+0/wKgjGFUOVo/MPf+KEVhMPUXQCDY2h7nnYGJ9Hvas3TRXlas0tI7 +1KQKaV8h3ewiKCBpFBaBHnoWwCVex2MHAUgJzSXZ7WYpskyl/UCMsyZPSq0w5DmA +6BgTIHK742X3Inhq5EOJRT6tpDNEfk9jriXaBVnl/AleJvvR/d2keFMdNcMTiarD +oaP6x1InLtPrabrdqjLaAjiI/iEQ6LkU1qHS+VrGbLmvEjnacRUQkx+15236Lyuu +X9KdsdhDa4ZULC/rT0r9CgroeU+LZiy2heNW0oA9foECgYEA9TdEskNNOokJ2tih +Xkzi9bchMNFjrLscfIxm+r7Qr9Ap0weG09ArmineoYUqnsrRe8rjmF1bgp7siNEr +6+owX0z6nrCCHGU8h6ijbxyD727sNAmfapm9eTD/La15A0sR2ei+YyywleudYqO5 +tYsGfowHjwqPayld+WO9HFRxw8ECgYEA4wNKWu96Jf54lYC3JtliLnfdE/bWLplc +bt/WFMyML/xZvIZq3BDeQjE8GalnBvzMZUA80XtvE2qJ0/AsbrsqSYC9P0I/8iuj +IoWqqo8+Z770WqV+1LZ99I6bDBoLxF8pmMg18KMIHGPe6ndqOZnmN4fWlJq6lPEu +CGEb+yxN5+MCgYEAk5EJ/zjvLc2wJ4n8OjKM1o+5IpavpBAKCY24nybbkSH1OXCr +G6aHxsNxncP0rRCi1ht3sYZk/otDDubJxrPtHjzGCV9xPUNTFNRQXhpL73fSH1K3 +I8CXPGpW9hcR3wB7IqakhCwtrFrZILYkmPKsGtWL6vHQ8w0251C1Smoq+EECgYB3 +RaZOat4xkibG3e7csYA9S+rS73CO4TLIakBvgxzwpVR8kd8ZKp+sBXQ/Q1sHN9Eo +LX0GzySH/gTWXqzprNrF7acA0o0Ibtbyb2pA3Kv8FD8MVUFy/0LkN/zMee7OyPTw ++dglS3Maf3qClCUyiGKFsJAUWctIMANwkZ0C9b8k4wKBgQDAvb1I68mjvvRcRWWU +hikQimffQLLlEoiNbhxVkyhuB/J6bqvP8VRFugTHQG4n2/GM1WYXCbhrSOaaA1Yr +C/2/CAcd4raWWZoeyvw5mw+yI2tifD/WuVHb0u/0IK7I4ykieWXeGzQt6mq753sW +XkhHltMkCD20h8Cwe7W/h5M23A== +-----END PRIVATE KEY----- From 6e97c06c0d4a530c982f856bf0bd2e8901bd36b5 Mon Sep 17 00:00:00 2001 From: Gus Class Date: Fri, 7 Dec 2018 14:12:49 -0800 Subject: [PATCH 2/5] Updates test for list devices for gateway --- iot/api-client/beta-features/gateway/gateway.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/iot/api-client/beta-features/gateway/gateway.py b/iot/api-client/beta-features/gateway/gateway.py index 8a6c718ffd0..166e24c8f95 100644 --- a/iot/api-client/beta-features/gateway/gateway.py +++ b/iot/api-client/beta-features/gateway/gateway.py @@ -37,9 +37,9 @@ import io import os import random +import re import ssl import time -import re from google.oauth2 import service_account from googleapiclient import discovery @@ -309,11 +309,17 @@ def list_devices_for_gateway( registry_name = 'projects/{}/locations/{}/registries/{}'.format( project_id, cloud_region, registry_id) - gateway_name = '{}/devices/{}'.format( - registry_name, gateway_id) devices = client.projects().locations().registries().devices( - ).listDeviceIdsForGateway(gatewayName=gateway_name).execute() + ).list( + parent=registry_name, + gatewayListOptions_associationsGatewayId=gateway_id + ).execute() + + for device in devices.get('devices', []): + print('Device: {} : {}'.format( + device.get('numId'), + device.get('id'))) if devices.get('deviceNumIds') is not None: for device_id in devices.get('deviceNumIds'): From 4212520fef9cb2854262b2ea2218482fadbeea69 Mon Sep 17 00:00:00 2001 From: Gus Class Date: Fri, 7 Dec 2018 15:24:47 -0800 Subject: [PATCH 3/5] Extends time for waiting for config messages in test --- iot/api-client/beta-features/gateway/gateway_test.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iot/api-client/beta-features/gateway/gateway_test.py b/iot/api-client/beta-features/gateway/gateway_test.py index 974accfb0cd..7622037ad46 100644 --- a/iot/api-client/beta-features/gateway/gateway_test.py +++ b/iot/api-client/beta-features/gateway/gateway_test.py @@ -254,8 +254,8 @@ def test_gateway_listen_for_bound_device_configs(iot_topic, capsys): # Setup for listening for config messages num_messages = 0 - jwt_exp_time = 20 - listen_time = 5 + jwt_exp_time = 60 + listen_time = 30 # Connect the gateway gateway.listen_for_config_and_error_messages( @@ -263,6 +263,7 @@ def test_gateway_listen_for_bound_device_configs(iot_topic, capsys): device_id, gateway_id, num_messages, rsa_private_path, 'RS256', ca_cert_path, mqtt_bridge_hostname, mqtt_bridge_port, jwt_exp_time, listen_time, None) + # Clean up gateway.unbind_device_from_gateway( service_account_json, project_id, cloud_region, registry_id, @@ -298,15 +299,15 @@ def test_gateway_send_data_for_device(iot_topic, capsys): # Setup for listening for config messages num_messages = 5 - jwt_exp_time = 20 - listen_time = 5 + jwt_exp_time = 60 + listen_time = 20 # Connect the gateway gateway.send_data_from_bound_device( service_account_json, project_id, cloud_region, registry_id, device_id, gateway_id, num_messages, rsa_private_path, 'RS256', ca_cert_path, mqtt_bridge_hostname, mqtt_bridge_port, - jwt_exp_time, listen_time) + jwt_exp_time, listen_time, None) # Clean up gateway.unbind_device_from_gateway( From c2cb1ab38668348a5bf7de887e34003e665fa693 Mon Sep 17 00:00:00 2001 From: Gus Class Date: Fri, 7 Dec 2018 15:32:28 -0800 Subject: [PATCH 4/5] Stop breaking stuff. --- iot/api-client/beta-features/gateway/gateway_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot/api-client/beta-features/gateway/gateway_test.py b/iot/api-client/beta-features/gateway/gateway_test.py index 7622037ad46..50491e4c6fb 100644 --- a/iot/api-client/beta-features/gateway/gateway_test.py +++ b/iot/api-client/beta-features/gateway/gateway_test.py @@ -307,7 +307,7 @@ def test_gateway_send_data_for_device(iot_topic, capsys): service_account_json, project_id, cloud_region, registry_id, device_id, gateway_id, num_messages, rsa_private_path, 'RS256', ca_cert_path, mqtt_bridge_hostname, mqtt_bridge_port, - jwt_exp_time, listen_time, None) + jwt_exp_time, listen_time) # Clean up gateway.unbind_device_from_gateway( From 94312fa0ab9dde794e44fa010ad43ca1e1a583c9 Mon Sep 17 00:00:00 2001 From: Gus Class Date: Mon, 10 Dec 2018 16:01:08 -0800 Subject: [PATCH 5/5] Updates library versions --- iot/api-client/beta-features/gateway/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iot/api-client/beta-features/gateway/requirements.txt b/iot/api-client/beta-features/gateway/requirements.txt index 51ee928f1a3..d399d155285 100644 --- a/iot/api-client/beta-features/gateway/requirements.txt +++ b/iot/api-client/beta-features/gateway/requirements.txt @@ -1,8 +1,8 @@ google-api-python-client==1.7.4 google-auth-httplib2==0.0.3 oauth2client==4.1.3 -google-auth==1.5.1 +google-auth==1.6.1 google-cloud-pubsub==0.38.0 -cryptography==2.3.1 +cryptography==2.4.2 pyjwt==1.6.4 -paho-mqtt==1.3.1 +paho-mqtt==1.4.0