diff --git a/tools/bin/published_devices_client/published_devices_cli_deploy.jar b/tools/bin/published_devices_client/published_devices_cli_deploy.jar new file mode 100755 index 0000000..40936b0 Binary files /dev/null and b/tools/bin/published_devices_client/published_devices_cli_deploy.jar differ diff --git a/tools/bin/published_devices_delta/published_devices_delta_deploy.jar b/tools/bin/published_devices_delta/published_devices_delta_deploy.jar new file mode 100755 index 0000000..cc18dd5 Binary files /dev/null and b/tools/bin/published_devices_delta/published_devices_delta_deploy.jar differ diff --git a/tools/source/published_devices_client/WORKSPACE b/tools/source/published_devices_client/WORKSPACE new file mode 100644 index 0000000..c09fe7a --- /dev/null +++ b/tools/source/published_devices_client/WORKSPACE @@ -0,0 +1,369 @@ +# JTS Framework WORKSPACE. + +workspace(name = "jts") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository", "git_repository") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +# In Bazel 2.0, Maven rules provided via new rules_jvm_external. +RULES_JVM_EXTERNAL_TAG = "3.1" +RULES_JVM_EXTERNAL_SHA = "e246373de2353f3d34d35814947aa8b7d0dd1a58c2f7a6c41cfeaff3007c2d14" +http_archive( + name = "rules_jvm_external", + strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG, + sha256 = RULES_JVM_EXTERNAL_SHA, + url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG, +) +load("@rules_jvm_external//:defs.bzl", "maven_install") + +# Google Guice. +maven_install( + name = "google_guice", + artifacts = ["com.google.inject:guice:4.2.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Appache core framework. +maven_install( + name = "apache_httpcore", + artifacts = ["org.apache.httpcomponents:httpcore:4.4.10"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google APIs client library +maven_install( + name = "google_api", + artifacts = ["com.google.api-client:google-api-client:1.30.2"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google HTTP Client +maven_install( + name = "google_http_client", + artifacts = ["com.google.http-client:google-http-client:1.30.2"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google HTTP Client Jackson2 Extensions +maven_install( + name = "jackson2", + artifacts = ["com.google.http-client:google-http-client-jackson2:1.31.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "jackson_core", + artifacts = ["com.fasterxml.jackson.core:jackson-core:2.10.0.pr2"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google Oauth2 API +maven_install( + name = "google_oauth2", + artifacts = ["com.google.oauth-client:google-oauth-client:1.30.1"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google Java common framework. +maven_install( + name = "google_guava", + artifacts = ["com.google.guava:guava:25.1-jre"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GRPC +git_repository( + name = "io_grpc_grpc_java", + remote = "https://github.com/grpc/grpc-java.git", + tag = "v1.23.0", +) + +# GRPC Core +maven_install( + name = "grpc_core", + artifacts = ["io.grpc:grpc-core:1.23.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GRPC Netty +maven_install( + name = "grpc_netty", + artifacts = ["io.grpc:grpc-netty:1.23.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "grpc_netty_all", + artifacts = ["io.netty:netty-all:4.1.41.Final"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GRPC Stub +maven_install( + name = "grpc_stub", + artifacts = ["io.grpc:grpc-stub:1.23.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GRPC Contenxt +maven_install( + name = "grpc_context", + artifacts = ["io.grpc:grpc-context:1.18.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GSON +maven_install( + name = "gson", + artifacts = ["com.google.code.gson:gson:2.8.6"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Netty TcNative (for GRPC) +maven_install( + name = "netty_tcnative", + artifacts = ["io.netty:netty-tcnative:2.0.25.Final"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Netty BoringSSL +maven_install( + name = "netty_boringssl", + artifacts = ["io.netty:netty-tcnative-boringssl-static:2.0.25.Final"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Open Census (for GRPC) +maven_install( + name = "open_census_api", + artifacts = ["io.opencensus:opencensus-api:0.24.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "open_census", + artifacts = ["io.opencensus:opencensus-contrib-http-jetty-client:0.19.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "open_census_util", + artifacts = ["io.opencensus:opencensus-contrib-http-util:0.19.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "open_census_grpc_metrics", + artifacts = ["io.opencensus:opencensus-contrib-grpc-metrics:0.24.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Perfmark (GRPC) +maven_install( + name = "io_perfmark_api", + artifacts = ["io.perfmark:perfmark-api:0.17.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google Protobuf Protos +PROTOBUF_BUILD_FILE = """ +package(default_visibility = ["//visibility:public"]) + +PROTO_FILES = [ + "google/protobuf/descriptor.proto", +] + +filegroup( + name = "protobuf_files", + srcs = PROTO_FILES, + visibility = ["//visibility:public"], +) + +proto_library( + name = "protobuf_protos", + srcs = [":protobuf_files"], + visibility = ["//visibility:public"], + +) +""" + +git_repository( + name = "com_github_googleapis_googleapis", + remote = "https://github.com/googleapis/googleapis.git", + branch = "master", +) +load("@com_github_googleapis_googleapis//:repository_rules.bzl", "switched_rules_by_language") +switched_rules_by_language( + name = "com_google_googleapis_imports", + java = True) + +http_archive( + name = "common_protos", + build_file_content = PROTOBUF_BUILD_FILE, + strip_prefix = "protobuf-3.9.1/src", + urls = [ + "https://github.com/protocolbuffers/protobuf/releases/download/v3.9.1/protobuf-all-3.9.1.tar.gz", + ], +) + +# Java commandline framework. +maven_install( + name = "jcommander", + artifacts = ["com.beust:jcommander:1.72"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +#Javax Inject (for Guice). +maven_install( + name = "javax_inject", + artifacts = ["javax.inject:javax.inject:1"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# JSON Java. +maven_install( + name = "json", + artifacts = ["org.json:json:20090211"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# JSR305 Annotations. +maven_install( + name = "jsr305_annotations", + artifacts = ["com.google.code.findbugs:jsr305:3.0.2"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# AOP (for Guice). +maven_install( + name = "aopalliance", + artifacts = ["aopalliance:aopalliance:1.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Protocol Buffer compiler. +git_repository( + name = "com_google_protobuf", + remote = "https://github.com/google/protobuf.git", + tag = "v3.9.1", +) + +bind( + name = "protobuf", + actual = "@com_google_protobuf//:protobuf", +) + +bind( + name = "protobuf_java", + actual = "@com_google_protobuf//:protobuf_java", +) + +# Loads necessary bazel rules for later consumption. +load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories") +grpc_java_repositories() + +load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") +protobuf_deps() diff --git a/tools/source/published_devices_client/google/chrome/widevine/contentpartners/v1beta1/BUILD b/tools/source/published_devices_client/google/chrome/widevine/contentpartners/v1beta1/BUILD new file mode 100644 index 0000000..4175520 --- /dev/null +++ b/tools/source/published_devices_client/google/chrome/widevine/contentpartners/v1beta1/BUILD @@ -0,0 +1,40 @@ +# Copyright 2019 Google LLC. All rights reserved. + +# Published Devices protocol buffer definitions for the +# Widevine Published Devices One Platform API service. + +package(default_visibility = ["//visibility:public"]) + +load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") + +proto_library( + name = "published_devices_proto", + srcs = ["published_devices.proto"], + deps = [ + ":device_security_profiles_proto", + "@com_github_googleapis_googleapis//google/api:annotations_proto", + "@com_github_googleapis_googleapis//google/api:field_behavior_proto", + ], +) + +proto_library( + name = "device_security_profiles_proto", + srcs = ["device_security_profiles.proto"], + deps = [ + "@com_github_googleapis_googleapis//google/api:field_behavior_proto", + ], +) + +java_proto_library( + name = "published_devices_java_proto", + deps = [":published_devices_proto"], + +) + +java_grpc_library( + name = "published_devices_grpc", + srcs = [":published_devices_proto"], + deps = [ + ":published_devices_java_proto", + ], +) diff --git a/tools/source/published_devices_client/google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto b/tools/source/published_devices_client/google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto new file mode 100644 index 0000000..83abdc2 --- /dev/null +++ b/tools/source/published_devices_client/google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto @@ -0,0 +1,94 @@ +// This file contains the proto definitions of DeviceSecurityProfile needed for +// the PublishedDevicesService. + +syntax = "proto3"; + +package google.chrome.widevine.contentpartners.v1beta1; + +import "google/api/field_behavior.proto"; + +option java_multiple_files = true; +option java_outer_classname = "DeviceSecurityProfilesProto"; +option java_package = "com.google.chrome.widevine.contentpartners.v1beta1"; + +// The DeviceSecurityProfileCriteria is produced by the client (a Widevine +// SDK). It is serialized and embedded in the +// ListDeviceSecurityProfilesRequest. +message DeviceSecurityProfileCriteria { + // Content provider who wants to get the DSPs. Required. + string content_provider = 1 [(google.api.field_behavior) = REQUIRED]; + // Content owners who own the DSPs. If this field is empty, return all + // DSPs that the content provider is included. Otherwise, a list of DSPs + // owned by the listed content_owners would be filtered for the requested + // provider. Optional field. + repeated string content_owners = 2 [(google.api.field_behavior) = OPTIONAL]; +} + +// A request sent to Widevine Published Server to retrieve +// the DeviceSecurityProfiles. +// (-- api-linter: core::0132::request-unknown-fields=disabled +// api-linter: core::0132::request-parent-required=disabled +// api-linter: core::0158::request-page-token-field=disabled +// api-linter: core::0158::request-page-size-field=disabled +// aip.dev/not-precedent: This is a non-standard, non-precedent API that +// cannot use pagination. It has no parent, page_size and page_token. +// Pagination is not appropriate. --) +message ListDeviceSecurityProfilesRequest { + // DeviceSecurityProfileCriteria for List request. Required. + DeviceSecurityProfileCriteria device_security_profile_criteria = 1 + [(google.api.field_behavior) = REQUIRED]; +} + +// A signed message which contains a serialized DeviceSecurityProfileList and +// the signature. +// (--GOOGLE_INTERNAL +// This message is copied from +// video/widevine/protos/public/device_security_profile_list.proto +// --) +message SignedDeviceSecurityProfiles { + // Serialized DeviceSecurityProfileList. Required. + // A device security profile list contains device security profiles + // defined by the content owner. Each DSP aggregates the device's + // capabilities, such as security profile level, minimum output requirements, + // minimum security requirements for this profile. The information is intended + // to be shared publicly. + bytes device_security_profiles = 1 [(google.api.field_behavior) = REQUIRED]; + // Signature of device_security_profiles. Signed with root + // certificate private key using RSASSA-PSS. Required. + bytes signature = 2 [(google.api.field_behavior) = REQUIRED]; + // Optional field that indicates the hash algorithm used in signature scheme. + HashAlgorithm hash_algorithm = 3 [(google.api.field_behavior) = OPTIONAL]; +} + +// A response returned from Widevine Published Server which contains a signed +// DeviceSecurityProfileList message. +// (-- api-linter: core::0132::response-unknown-fields=disabled +// api-linter: core::0158::response-repeated-first-field=disabled +// api-linter: core::0158::response-next-page-token-field=disabled +// aip.dev/not-precedent: This is a non-standard, non-precedent API that +// cannot use pagination. We serialize and sign the list data in a signed +// message, which is used in the response. The first field is not repeated +// and response has no next_page_token field. The +// SignedDeviceSecurityProfiles is intended to be consumed as a single blob. +// Pagination is not appropriate. --) +message ListDeviceSecurityProfilesResponse { + // A signed message which contains a serialized DeviceSecurityProfileList and + // the signature. + SignedDeviceSecurityProfiles signed_device_security_profiles = 1 + [(google.api.field_behavior) = REQUIRED]; +} + +// A representation of a hash algorithm used in signature. +// (--GOOGLE_INTERNAL +// This enum is copied from +// video/widevine/protos/public/hash_algorithm.proto +// --) +enum HashAlgorithm { + // Unspecified hash algorithm: SHA_256 shall be used for ECC based algorithms + // and SHA_1 shall be used otherwise. + HASH_ALGORITHM_UNSPECIFIED = 0; + // Secure Hash Algorithm 1 (SHA-1). + HASH_ALGORITHM_SHA_1 = 1; + // Secure Hash Algorithm 2 256 bits (SHA-256). + HASH_ALGORITHM_SHA_256 = 2; +} diff --git a/tools/source/published_devices_client/google/chrome/widevine/contentpartners/v1beta1/published_devices.proto b/tools/source/published_devices_client/google/chrome/widevine/contentpartners/v1beta1/published_devices.proto new file mode 100755 index 0000000..6483e6d --- /dev/null +++ b/tools/source/published_devices_client/google/chrome/widevine/contentpartners/v1beta1/published_devices.proto @@ -0,0 +1,100 @@ +// This file contains the definitions needed for the PublishedDevicesService. +// The PublishedDevicesService allows clients to retrieve a signed and +// verifiable list of devices and device security profiles that support the +// Widevine Digital Rights Management (DRM) solution. +// +// (--GOOGLE_INTERNAL +// This proto is intended to support a feature of the "Widevine API" where +// external content providers will retrieve device certificate status list +// as well as device secruity profiles to achieve better and more secure +// playback experience. +// +// For more info about the service, please see design doc +// https://docs.google.com/document/d/1ZClc0HJuFlijDrdZxcR_DmNOi6Hqo7bjjEtewLnafas/edit?usp=sharing +// --) + +syntax = "proto3"; + +package google.chrome.widevine.contentpartners.v1beta1; + +import "google/api/annotations.proto"; +import "google/api/field_behavior.proto"; +import "google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto"; + +option csharp_namespace = "Google.Chrome.Widevine.ContentPartners.V1Beta1"; +option java_multiple_files = true; +option java_outer_classname = "PublishedDevicesProtos"; +option java_package = "com.google.chrome.widevine.contentpartners.v1beta1"; + +// GCWPD is an acronym for Google Chrome Widevine Published Devices. +option objc_class_prefix = "GCWPD"; + + +// This service produces a list of Widevine supported devices +// signed by a certificate that can be verified by the client. +service PublishedDevicesService { + // Return the PublishedDevices containing the list of devices and a signature. + // The request is used to authenticate the client. + rpc GetPublishedDevices(PublishedDevicesRequest) returns (PublishedDevices) { + + option (google.api.http) = { + post: "/v1beta1/publishedDevices:getSignedBatch" + body: "*" + }; + } + + // Return the ListDeviceSecurityProfilesResponse containing a list of + // device security profiles. + rpc ListDeviceSecurityProfiles(ListDeviceSecurityProfilesRequest) + returns (ListDeviceSecurityProfilesResponse) { + + option (google.api.http) = { + get: "/v1beta1/deviceSecurityProfiles:listDeviceSecurityProfiles" + }; + } +} + +// The SdkClientInformation is produced by the client (a Widevine SDK). It is +// serialized and embedded in the PublishedDevicesRequest. It is used to +// declare attributes of the client's SDK including the Widevine-issued service +// certificate that is used by the client. +message SdkClientInformation { + // The version of sdk. Required. + string sdk_version = 1; + // POSIX time, in seconds, when this request was created. Required. + uint64 sdk_time_seconds = 2; + // The serialized service certificate used to sign the request. Required. + bytes service_certificate = 3; +} + +// A signed request sent to Widevine Provisioning Server (keysmith) to retrieve +// the PublishedDevices. +message PublishedDevicesRequest { + // A serialized SdkClientInformation proto. Required. + bytes sdk_client_information = 1; + + // This is the SHA256 digest, PKCS#7 padded signature of the + // sdk_client_information field. This signature uses the + // RSA private key corresponding to the server certificate. Required. + bytes signature = 2; + + // Optional field that indicates the hash algorithm used in signature scheme. + HashAlgorithm hash_algorithm = 3 [(google.api.field_behavior) = OPTIONAL]; +} + +// Contains a serialized DeviceCertificateStatusList and the signature. +message PublishedDevices { + // Serialized DeviceCertificateStatusList. Required. + // A device certificate status list contains information about various + // device series information such as the make, model and status (RELEASED, + // IN_TESTING, REVOKED, etc).The information is intended to be shared + // publicly. + bytes published_devices = 1; + + // Signature of device_certificate_status_list_request. Signed with root + // certificate private key using RSASSA-PSS. Required. + bytes signature = 2; + + // Optional field that indicates the hash algorithm used in signature scheme. + HashAlgorithm hash_algorithm = 3 [(google.api.field_behavior) = OPTIONAL]; +} diff --git a/tools/source/published_devices_client/httpclient/BUILD b/tools/source/published_devices_client/httpclient/BUILD new file mode 100644 index 0000000..0051ae5 --- /dev/null +++ b/tools/source/published_devices_client/httpclient/BUILD @@ -0,0 +1,21 @@ +# Copyright 2019 Google LLC. All rights reserved. +# Desciption: +# JTS http clients. + +package( + default_visibility = ["//visibility:public"], +) + +java_library( + name = "httpclient", + srcs = glob(["*.java"]), + deps = [ + "@google_guice//:com_google_inject_guice", + "@json//:org_json_json", + "@google_api//:com_google_api_client_google_api_client", + "@google_http_client//:com_google_http_client_google_http_client", + "@google_oauth2//:com_google_oauth_client_google_oauth_client", + "@jackson2//:com_google_http_client_google_http_client_jackson2", + "@jackson_core//:com_fasterxml_jackson_core_jackson_core", + ], +) diff --git a/tools/source/published_devices_client/httpclient/Credentials.java b/tools/source/published_devices_client/httpclient/Credentials.java new file mode 100644 index 0000000..b11004e --- /dev/null +++ b/tools/source/published_devices_client/httpclient/Credentials.java @@ -0,0 +1,56 @@ +// Copyright 2019 Google LLC. All rights reserved. +package com.google.video.widevine.jts.httpclient; + +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * JTS Cloud Credentials. + * + * Provides Oauth2 authentication, and access/refresh tokens. + */ +public class Credentials { + + private static final List SCOPES = Arrays.asList( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/widevine/frontend"); + private static final int MIN_ACCESS_TOKEN_REFRESH_SEC = 1200; + private static final Logger logger = Logger.getLogger(Credentials.class.getName()); + + private String credentialsJsonFile = null; + private GoogleCredential googleCredential = null; + private String accessToken = null; + + /** + * Credentials Constructor. + * + * @param credentialsJsonFile The full path to a GCP service account json credentials file. + */ + public Credentials(String credentialsJsonFile) throws IOException { + this.credentialsJsonFile = credentialsJsonFile; + activateGoogleCredentials(); + } + + private void activateGoogleCredentials() throws IOException { + googleCredential = GoogleCredential + .fromStream(new FileInputStream(credentialsJsonFile)) + .createScoped(SCOPES); + googleCredential.refreshToken(); + } + + /** Provides an Oauth2 Access Token that can be used to make GCP service calls.*/ + public String getAccessToken() throws IOException { + if (accessToken == null + || googleCredential.getExpiresInSeconds() <= MIN_ACCESS_TOKEN_REFRESH_SEC) { + googleCredential.refreshToken(); + accessToken = googleCredential.getAccessToken(); + logger.log(Level.INFO, "Getting new access token."); + } + return accessToken; + } +} diff --git a/tools/source/published_devices_client/interfaces/BUILD b/tools/source/published_devices_client/interfaces/BUILD new file mode 100644 index 0000000..4735f66 --- /dev/null +++ b/tools/source/published_devices_client/interfaces/BUILD @@ -0,0 +1,17 @@ +# Copyright 2018 Google LLC. All rights reserved. +# Desciption: +# JTS interfaces. + +package( + default_visibility = ["//visibility:public"], +) + +java_library( + name = "interfaces", + srcs = glob(["*.java"]), + deps = [ + "//google/chrome/widevine/contentpartners/v1beta1:published_devices_java_proto", + "@com_google_protobuf//:protobuf_java", + "@apache_httpcore//:org_apache_httpcomponents_httpcore", + ], +) diff --git a/tools/source/published_devices_client/interfaces/DeviceCertificate.java b/tools/source/published_devices_client/interfaces/DeviceCertificate.java new file mode 100644 index 0000000..ef5ac88 --- /dev/null +++ b/tools/source/published_devices_client/interfaces/DeviceCertificate.java @@ -0,0 +1,18 @@ +// Copyright 2019 Google LLC. All rights reserved. +package com.google.video.widevine.jts.interfaces; + +import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices; + +/** + * DeviceCertificate defines APIs for getting PublishedDevices and Published Devices list. + */ +public interface DeviceCertificate { + + /** + * Get the latest {@code PublishedDevices} containing Published Devices list data. + * + * @return {@code PublishedDevices} containing Published Devices list data. + */ + public PublishedDevices getPublishedDevices() throws Exception; + +} diff --git a/tools/source/published_devices_client/providers/BUILD b/tools/source/published_devices_client/providers/BUILD new file mode 100644 index 0000000..506b639 --- /dev/null +++ b/tools/source/published_devices_client/providers/BUILD @@ -0,0 +1,37 @@ +# Copyright 2018 Google LLC. All rights reserved. +# Desciption: +# JTS interfaces. + +package( + default_visibility = ["//visibility:public"], +) + +java_library( + name = "providers", + srcs = glob(["*.java"]), + runtime_deps = [ + "@grpc_context//:io_grpc_grpc_context", + "@grpc_netty_all//:io_netty_netty_all", + "@io_perfmark_api//:io_perfmark_perfmark_api", + "@netty_boringssl//:io_netty_netty_tcnative_boringssl_static", + "@open_census//:io_opencensus_opencensus_contrib_http_jetty_client", + "@open_census_api//:io_opencensus_opencensus_api", + "@open_census_grpc_metrics//:io_opencensus_opencensus_contrib_grpc_metrics", + "@open_census_util//:io_opencensus_opencensus_contrib_http_util", + ], + deps = [ + ":libwvpl_cas_proxy_sdk_lib.jar", + "//google/chrome/widevine/contentpartners/v1beta1:published_devices_grpc", + "//google/chrome/widevine/contentpartners/v1beta1:published_devices_java_proto", + "//httpclient", + "//interfaces", + "@google_guice//:com_google_inject_guice", + "@json//:org_json_json", + "@com_google_protobuf//:protobuf_java", + "@google_guava//:com_google_guava_guava", + "@grpc_core//:io_grpc_grpc_core", + "@grpc_netty//:io_grpc_grpc_netty", + "@grpc_stub//:io_grpc_grpc_stub", + "@io_grpc_grpc_java//api", + ], +) diff --git a/tools/source/published_devices_client/providers/PublishedDevicesProvider.java b/tools/source/published_devices_client/providers/PublishedDevicesProvider.java new file mode 100644 index 0000000..ff5733d --- /dev/null +++ b/tools/source/published_devices_client/providers/PublishedDevicesProvider.java @@ -0,0 +1,91 @@ +// Copyright 2020 Google LLC. All rights reserved. + +package com.google.video.widevine.jts.providers; + +import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices; +import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevicesRequest; +import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevicesServiceGrpc; +import com.google.inject.Inject; +import com.google.protobuf.TextFormat; +import com.google.video.widevine.jts.httpclient.Credentials; +import com.google.video.widevine.jts.interfaces.DeviceCertificate; +import com.google.video.widevine.sdk.wvpl.WvPLBaseEnvironment; +import com.google.video.widevine.sdk.wvpl.WvPLStatusException; +import io.grpc.ManagedChannel; +import io.grpc.Metadata; +import io.grpc.netty.NettyChannelBuilder; +import io.grpc.stub.MetadataUtils; +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Provides the latest {@code PublishedDevices} data from the Widevine Published Devices Service. + * + * This implementation uses the Widevine Published Devices API, and support a gRPC method for + * retrieving PublishedDevices with an embedded Published Devices list. + */ +public class PublishedDevicesProvider implements DeviceCertificate { + private static final Logger logger = Logger.getLogger(PublishedDevicesProvider.class.getName()); + private WvPLBaseEnvironment environment = null; + private String apiServicePath = null; + private Credentials credentials = null; + + /** + * PublishedDevicesProvider constructor. + * + * @param environment A WvPLBaseEnvironment object initialized with a Service Certificate. + * @param serviceAccountPath Path to a GCP Service Account json file, used in OAUTH. + * @param apiServicePath Path to a Widevine Published Devices API service. + * @throws IOException upon failure creating OAUTH credentials. + */ + @Inject + public PublishedDevicesProvider( + WvPLBaseEnvironment environment, String serviceAccountPath, String apiServicePath) + throws IOException { + this.environment = environment; + this.apiServicePath = apiServicePath; + credentials = new Credentials(serviceAccountPath); + } + + /** + * Get the latest {@code PublishedDevices} from the Widevine Published Devices Service. + * + * @return The latest {@code PublishedDevices} data. + * @throws InterruptedException upon RPC failure. + * @throws WvPLStatusException upon WvPLBaseEnvironment errors. + */ + @Override + public PublishedDevices getPublishedDevices() throws InterruptedException, WvPLStatusException{ + ManagedChannel channel = null; + PublishedDevices devicesResponse = null; + + logger.log(Level.INFO, "Getting PublishedDevices..."); + try { + channel = createRpcChannel(apiServicePath); + Metadata metadata = new Metadata(); + String token = "Bearer " + credentials.getAccessToken(); + metadata.put(Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER), token); + PublishedDevicesServiceGrpc.PublishedDevicesServiceBlockingStub blockingStub = + PublishedDevicesServiceGrpc.newBlockingStub(channel) + .withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)); + devicesResponse = blockingStub.getPublishedDevices(PublishedDevicesRequest.parseFrom( + environment.generateDeviceStatusListRequest())); + logger.log(Level.INFO, "GRPC Call to PublishedDevicesService.GetSignedList returned:\n %s" + + TextFormat.printer().printToString(devicesResponse)); + } catch (IOException e) { + logger.log(Level.INFO, "IOException encountered trying to retrieve the signed list: " + e); + } finally { + if (channel != null) { + channel.shutdown(); + channel.awaitTermination(1, TimeUnit.SECONDS); + } + } + return devicesResponse; + } + + private static ManagedChannel createRpcChannel(String host) { + return NettyChannelBuilder.forTarget(host).build(); + } +} diff --git a/tools/source/published_devices_client/tools/BUILD b/tools/source/published_devices_client/tools/BUILD new file mode 100644 index 0000000..4e9dccb --- /dev/null +++ b/tools/source/published_devices_client/tools/BUILD @@ -0,0 +1,39 @@ +# Copyright 2019 Google LLC. All rights reserved. +# Desciption: +# JTS tools. + +package(default_visibility = ["//visibility:public"]) + +java_library( + name = "published_devices_cli_lib", + srcs = [ + "PublishedDevicesCli.java", + ], + runtime_deps = [ + "@grpc_context//:io_grpc_grpc_context", + "@grpc_netty_all//:io_netty_netty_all", + "@io_perfmark_api//:io_perfmark_perfmark_api", + "@netty_boringssl//:io_netty_netty_tcnative_boringssl_static", + "@netty_tcnative//:io_netty_netty_tcnative", + "@open_census//:io_opencensus_opencensus_contrib_http_jetty_client", + "@open_census_api//:io_opencensus_opencensus_api", + "@open_census_grpc_metrics//:io_opencensus_opencensus_contrib_grpc_metrics", + "@open_census_util//:io_opencensus_opencensus_contrib_http_util", + ], + deps = [ + "//google/chrome/widevine/contentpartners/v1beta1:published_devices_grpc", + "//google/chrome/widevine/contentpartners/v1beta1:published_devices_java_proto", + "//providers", + "//providers:libwvpl_cas_proxy_sdk_lib.jar", + "@jcommander//:com_beust_jcommander", + "@google_guava//:com_google_guava_guava", + ], +) + +java_binary( + name = "published_devices_cli", + main_class = "com.google.video.widevine.jts.tools.PublishedDevicesCli", + runtime_deps = [ + ":published_devices_cli_lib", + ], +) diff --git a/tools/source/published_devices_client/tools/PublishedDevicesCli.java b/tools/source/published_devices_client/tools/PublishedDevicesCli.java new file mode 100644 index 0000000..92219fe --- /dev/null +++ b/tools/source/published_devices_client/tools/PublishedDevicesCli.java @@ -0,0 +1,140 @@ +// Copyright 2020 Google LLC. All rights reserved. + +package com.google.video.widevine.jts.tools; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices; +import com.google.common.io.BaseEncoding; +import com.google.video.widevine.jts.providers.PublishedDevicesProvider; +import com.google.video.widevine.sdk.wvpl.WvPLCASProxyEnvironment; +import com.google.video.widevine.sdk.wvpl.WvPLStatus; +import com.google.video.widevine.sdk.wvpl.WvPLStatusException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; + +/** + * Published Devices Command Line Interface. + * + * Provides a command line interface to get the latest {@code PublishedDevices} data from the + * Widevine Published Devices Service. + * + * Default Widevine Service API path: widevine.googleapis.com. + * + * To build: + * Bazel build java/com/google/video/widevine/jts/tools:published_devices_client_deploy.jar + * + * To run: + * java -Djava.library.path=./path/to/license/sdk.so \ + * -jar /path/to/published_devices_client_deploy.jar \ + * -service_cert_path /path/to/cert_file.der \ + * -service_private_key_path /path/to/private_key.der \ + * -service_private_key_passphrase theprivatekeypassphrase + * -service_account_path /path/to/service-account.json \ + */ +public final class PublishedDevicesCli { + private WvPLCASProxyEnvironment environment = null; + private PublishedDevicesProvider publishedDevices = null; + private String serviceCertPath = null; + private String privateKeyPath = null; + private String privateKeyPassphrase = null; + + /** Command Line Flags. */ + static class Flags{ + private Flags() {} + + @Parameter(names = "-service_cert_path", description = "Path to service certificate") + private String serviceCertPath = ""; + + @Parameter(names = "-service_private_key_path", + description = "Path to private key file needed to decrypt service certificate") + private String servicePrivateKeyPath = ""; + + @Parameter(names = "-service_private_key_passphrase", + description = "Passphrase needed to decrypt the private key") + private String servicePrivateKeyPassphrase = ""; + + @Parameter(names = "-service_account_path", + description = "Path to a GCP Service Account json file") + private String serviceAccountPath = ""; + + @Parameter(names = "-api_service_path", + description = "Optional. Path to a Widevine API service.") + private String apiServicePath = "widevine.googleapis.com"; + + @Parameter(names = "-s", + description = "Save PublishedDevices file path.") + private String saveFilePath = null; + } + + public PublishedDevicesCli(String serviceCertPath, String privateKeyPath, + String privateKeyPassphrase, String serviceAccountPath, String apiServicePath) + throws Exception { + this.serviceCertPath = serviceCertPath; + this.privateKeyPath = privateKeyPath; + this.privateKeyPassphrase = privateKeyPassphrase; + initializeWvplEnvironment(); + publishedDevices = new PublishedDevicesProvider( + environment, serviceAccountPath, apiServicePath); + } + + /** + * Get the latest {@code PublishedDevices} from the Widevine Published Devices Service. + * + * @return The latest PublishedDevices data. + * @throws InterruptedException upon RPC failure. + * @throws WvPLStatusException upon WvPLBaseEnvironment errors. + */ + public PublishedDevices getPublishedDevices() throws InterruptedException, WvPLStatusException { + return publishedDevices.getPublishedDevices(); + } + + /** + * Saves PublishedDevices proto data to a file. + * + * @param saveFilePath The path to the save file. + * @param publishedDevices A PublishedDevices proto. + */ + public static void savePublishedDevicesDataToFile(String saveFilePath, + PublishedDevices publishedDevices) throws IOException { + Files.write( + Paths.get(saveFilePath), + BaseEncoding.base64Url().encode(publishedDevices.toByteArray()).getBytes(UTF_8)); + } + + public static void main(String[] args) throws Exception { + Flags flags = new Flags(); + new JCommander(flags, args); + PublishedDevicesCli devices = new PublishedDevicesCli( + flags.serviceCertPath, + flags.servicePrivateKeyPath, + flags.servicePrivateKeyPassphrase, + flags.serviceAccountPath, + flags.apiServicePath); + PublishedDevices publishedDevices = devices.getPublishedDevices(); + if (flags.saveFilePath != null) { + savePublishedDevicesDataToFile(flags.saveFilePath, publishedDevices); + } + } + + private void initializeWvplEnvironment() throws Exception { + environment = new WvPLCASProxyEnvironment(new HashMap<>()); + // Set service certificate. + WvPLStatus status = + environment.setServiceCertificate( + loadDataFromFile(serviceCertPath), + loadDataFromFile(privateKeyPath), + privateKeyPassphrase.getBytes(UTF_8)); + if (!status.getStatusCode().equals(WvPLStatus.StatusCode.OK)) { + throw new Exception("Set server certificate status: " + status); + } + } + + private static byte[] loadDataFromFile(String filePath) throws IOException { + return Files.readAllBytes(Paths.get(filePath)); + } +} diff --git a/tools/source/published_devices_delta/WORKSPACE b/tools/source/published_devices_delta/WORKSPACE new file mode 100644 index 0000000..c09fe7a --- /dev/null +++ b/tools/source/published_devices_delta/WORKSPACE @@ -0,0 +1,369 @@ +# JTS Framework WORKSPACE. + +workspace(name = "jts") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository", "git_repository") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +# In Bazel 2.0, Maven rules provided via new rules_jvm_external. +RULES_JVM_EXTERNAL_TAG = "3.1" +RULES_JVM_EXTERNAL_SHA = "e246373de2353f3d34d35814947aa8b7d0dd1a58c2f7a6c41cfeaff3007c2d14" +http_archive( + name = "rules_jvm_external", + strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG, + sha256 = RULES_JVM_EXTERNAL_SHA, + url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG, +) +load("@rules_jvm_external//:defs.bzl", "maven_install") + +# Google Guice. +maven_install( + name = "google_guice", + artifacts = ["com.google.inject:guice:4.2.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Appache core framework. +maven_install( + name = "apache_httpcore", + artifacts = ["org.apache.httpcomponents:httpcore:4.4.10"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google APIs client library +maven_install( + name = "google_api", + artifacts = ["com.google.api-client:google-api-client:1.30.2"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google HTTP Client +maven_install( + name = "google_http_client", + artifacts = ["com.google.http-client:google-http-client:1.30.2"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google HTTP Client Jackson2 Extensions +maven_install( + name = "jackson2", + artifacts = ["com.google.http-client:google-http-client-jackson2:1.31.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "jackson_core", + artifacts = ["com.fasterxml.jackson.core:jackson-core:2.10.0.pr2"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google Oauth2 API +maven_install( + name = "google_oauth2", + artifacts = ["com.google.oauth-client:google-oauth-client:1.30.1"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google Java common framework. +maven_install( + name = "google_guava", + artifacts = ["com.google.guava:guava:25.1-jre"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GRPC +git_repository( + name = "io_grpc_grpc_java", + remote = "https://github.com/grpc/grpc-java.git", + tag = "v1.23.0", +) + +# GRPC Core +maven_install( + name = "grpc_core", + artifacts = ["io.grpc:grpc-core:1.23.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GRPC Netty +maven_install( + name = "grpc_netty", + artifacts = ["io.grpc:grpc-netty:1.23.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "grpc_netty_all", + artifacts = ["io.netty:netty-all:4.1.41.Final"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GRPC Stub +maven_install( + name = "grpc_stub", + artifacts = ["io.grpc:grpc-stub:1.23.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GRPC Contenxt +maven_install( + name = "grpc_context", + artifacts = ["io.grpc:grpc-context:1.18.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# GSON +maven_install( + name = "gson", + artifacts = ["com.google.code.gson:gson:2.8.6"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Netty TcNative (for GRPC) +maven_install( + name = "netty_tcnative", + artifacts = ["io.netty:netty-tcnative:2.0.25.Final"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Netty BoringSSL +maven_install( + name = "netty_boringssl", + artifacts = ["io.netty:netty-tcnative-boringssl-static:2.0.25.Final"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Open Census (for GRPC) +maven_install( + name = "open_census_api", + artifacts = ["io.opencensus:opencensus-api:0.24.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "open_census", + artifacts = ["io.opencensus:opencensus-contrib-http-jetty-client:0.19.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "open_census_util", + artifacts = ["io.opencensus:opencensus-contrib-http-util:0.19.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +maven_install( + name = "open_census_grpc_metrics", + artifacts = ["io.opencensus:opencensus-contrib-grpc-metrics:0.24.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Perfmark (GRPC) +maven_install( + name = "io_perfmark_api", + artifacts = ["io.perfmark:perfmark-api:0.17.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Google Protobuf Protos +PROTOBUF_BUILD_FILE = """ +package(default_visibility = ["//visibility:public"]) + +PROTO_FILES = [ + "google/protobuf/descriptor.proto", +] + +filegroup( + name = "protobuf_files", + srcs = PROTO_FILES, + visibility = ["//visibility:public"], +) + +proto_library( + name = "protobuf_protos", + srcs = [":protobuf_files"], + visibility = ["//visibility:public"], + +) +""" + +git_repository( + name = "com_github_googleapis_googleapis", + remote = "https://github.com/googleapis/googleapis.git", + branch = "master", +) +load("@com_github_googleapis_googleapis//:repository_rules.bzl", "switched_rules_by_language") +switched_rules_by_language( + name = "com_google_googleapis_imports", + java = True) + +http_archive( + name = "common_protos", + build_file_content = PROTOBUF_BUILD_FILE, + strip_prefix = "protobuf-3.9.1/src", + urls = [ + "https://github.com/protocolbuffers/protobuf/releases/download/v3.9.1/protobuf-all-3.9.1.tar.gz", + ], +) + +# Java commandline framework. +maven_install( + name = "jcommander", + artifacts = ["com.beust:jcommander:1.72"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +#Javax Inject (for Guice). +maven_install( + name = "javax_inject", + artifacts = ["javax.inject:javax.inject:1"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# JSON Java. +maven_install( + name = "json", + artifacts = ["org.json:json:20090211"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# JSR305 Annotations. +maven_install( + name = "jsr305_annotations", + artifacts = ["com.google.code.findbugs:jsr305:3.0.2"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# AOP (for Guice). +maven_install( + name = "aopalliance", + artifacts = ["aopalliance:aopalliance:1.0"], + repositories = [ + "https://jcenter.bintray.com", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], +) + +# Protocol Buffer compiler. +git_repository( + name = "com_google_protobuf", + remote = "https://github.com/google/protobuf.git", + tag = "v3.9.1", +) + +bind( + name = "protobuf", + actual = "@com_google_protobuf//:protobuf", +) + +bind( + name = "protobuf_java", + actual = "@com_google_protobuf//:protobuf_java", +) + +# Loads necessary bazel rules for later consumption. +load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories") +grpc_java_repositories() + +load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") +protobuf_deps() diff --git a/tools/source/published_devices_delta/google/chrome/widevine/contentpartners/v1beta1/BUILD b/tools/source/published_devices_delta/google/chrome/widevine/contentpartners/v1beta1/BUILD new file mode 100644 index 0000000..4175520 --- /dev/null +++ b/tools/source/published_devices_delta/google/chrome/widevine/contentpartners/v1beta1/BUILD @@ -0,0 +1,40 @@ +# Copyright 2019 Google LLC. All rights reserved. + +# Published Devices protocol buffer definitions for the +# Widevine Published Devices One Platform API service. + +package(default_visibility = ["//visibility:public"]) + +load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") + +proto_library( + name = "published_devices_proto", + srcs = ["published_devices.proto"], + deps = [ + ":device_security_profiles_proto", + "@com_github_googleapis_googleapis//google/api:annotations_proto", + "@com_github_googleapis_googleapis//google/api:field_behavior_proto", + ], +) + +proto_library( + name = "device_security_profiles_proto", + srcs = ["device_security_profiles.proto"], + deps = [ + "@com_github_googleapis_googleapis//google/api:field_behavior_proto", + ], +) + +java_proto_library( + name = "published_devices_java_proto", + deps = [":published_devices_proto"], + +) + +java_grpc_library( + name = "published_devices_grpc", + srcs = [":published_devices_proto"], + deps = [ + ":published_devices_java_proto", + ], +) diff --git a/tools/source/published_devices_delta/google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto b/tools/source/published_devices_delta/google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto new file mode 100644 index 0000000..83abdc2 --- /dev/null +++ b/tools/source/published_devices_delta/google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto @@ -0,0 +1,94 @@ +// This file contains the proto definitions of DeviceSecurityProfile needed for +// the PublishedDevicesService. + +syntax = "proto3"; + +package google.chrome.widevine.contentpartners.v1beta1; + +import "google/api/field_behavior.proto"; + +option java_multiple_files = true; +option java_outer_classname = "DeviceSecurityProfilesProto"; +option java_package = "com.google.chrome.widevine.contentpartners.v1beta1"; + +// The DeviceSecurityProfileCriteria is produced by the client (a Widevine +// SDK). It is serialized and embedded in the +// ListDeviceSecurityProfilesRequest. +message DeviceSecurityProfileCriteria { + // Content provider who wants to get the DSPs. Required. + string content_provider = 1 [(google.api.field_behavior) = REQUIRED]; + // Content owners who own the DSPs. If this field is empty, return all + // DSPs that the content provider is included. Otherwise, a list of DSPs + // owned by the listed content_owners would be filtered for the requested + // provider. Optional field. + repeated string content_owners = 2 [(google.api.field_behavior) = OPTIONAL]; +} + +// A request sent to Widevine Published Server to retrieve +// the DeviceSecurityProfiles. +// (-- api-linter: core::0132::request-unknown-fields=disabled +// api-linter: core::0132::request-parent-required=disabled +// api-linter: core::0158::request-page-token-field=disabled +// api-linter: core::0158::request-page-size-field=disabled +// aip.dev/not-precedent: This is a non-standard, non-precedent API that +// cannot use pagination. It has no parent, page_size and page_token. +// Pagination is not appropriate. --) +message ListDeviceSecurityProfilesRequest { + // DeviceSecurityProfileCriteria for List request. Required. + DeviceSecurityProfileCriteria device_security_profile_criteria = 1 + [(google.api.field_behavior) = REQUIRED]; +} + +// A signed message which contains a serialized DeviceSecurityProfileList and +// the signature. +// (--GOOGLE_INTERNAL +// This message is copied from +// video/widevine/protos/public/device_security_profile_list.proto +// --) +message SignedDeviceSecurityProfiles { + // Serialized DeviceSecurityProfileList. Required. + // A device security profile list contains device security profiles + // defined by the content owner. Each DSP aggregates the device's + // capabilities, such as security profile level, minimum output requirements, + // minimum security requirements for this profile. The information is intended + // to be shared publicly. + bytes device_security_profiles = 1 [(google.api.field_behavior) = REQUIRED]; + // Signature of device_security_profiles. Signed with root + // certificate private key using RSASSA-PSS. Required. + bytes signature = 2 [(google.api.field_behavior) = REQUIRED]; + // Optional field that indicates the hash algorithm used in signature scheme. + HashAlgorithm hash_algorithm = 3 [(google.api.field_behavior) = OPTIONAL]; +} + +// A response returned from Widevine Published Server which contains a signed +// DeviceSecurityProfileList message. +// (-- api-linter: core::0132::response-unknown-fields=disabled +// api-linter: core::0158::response-repeated-first-field=disabled +// api-linter: core::0158::response-next-page-token-field=disabled +// aip.dev/not-precedent: This is a non-standard, non-precedent API that +// cannot use pagination. We serialize and sign the list data in a signed +// message, which is used in the response. The first field is not repeated +// and response has no next_page_token field. The +// SignedDeviceSecurityProfiles is intended to be consumed as a single blob. +// Pagination is not appropriate. --) +message ListDeviceSecurityProfilesResponse { + // A signed message which contains a serialized DeviceSecurityProfileList and + // the signature. + SignedDeviceSecurityProfiles signed_device_security_profiles = 1 + [(google.api.field_behavior) = REQUIRED]; +} + +// A representation of a hash algorithm used in signature. +// (--GOOGLE_INTERNAL +// This enum is copied from +// video/widevine/protos/public/hash_algorithm.proto +// --) +enum HashAlgorithm { + // Unspecified hash algorithm: SHA_256 shall be used for ECC based algorithms + // and SHA_1 shall be used otherwise. + HASH_ALGORITHM_UNSPECIFIED = 0; + // Secure Hash Algorithm 1 (SHA-1). + HASH_ALGORITHM_SHA_1 = 1; + // Secure Hash Algorithm 2 256 bits (SHA-256). + HASH_ALGORITHM_SHA_256 = 2; +} diff --git a/tools/source/published_devices_delta/google/chrome/widevine/contentpartners/v1beta1/published_devices.proto b/tools/source/published_devices_delta/google/chrome/widevine/contentpartners/v1beta1/published_devices.proto new file mode 100755 index 0000000..6483e6d --- /dev/null +++ b/tools/source/published_devices_delta/google/chrome/widevine/contentpartners/v1beta1/published_devices.proto @@ -0,0 +1,100 @@ +// This file contains the definitions needed for the PublishedDevicesService. +// The PublishedDevicesService allows clients to retrieve a signed and +// verifiable list of devices and device security profiles that support the +// Widevine Digital Rights Management (DRM) solution. +// +// (--GOOGLE_INTERNAL +// This proto is intended to support a feature of the "Widevine API" where +// external content providers will retrieve device certificate status list +// as well as device secruity profiles to achieve better and more secure +// playback experience. +// +// For more info about the service, please see design doc +// https://docs.google.com/document/d/1ZClc0HJuFlijDrdZxcR_DmNOi6Hqo7bjjEtewLnafas/edit?usp=sharing +// --) + +syntax = "proto3"; + +package google.chrome.widevine.contentpartners.v1beta1; + +import "google/api/annotations.proto"; +import "google/api/field_behavior.proto"; +import "google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto"; + +option csharp_namespace = "Google.Chrome.Widevine.ContentPartners.V1Beta1"; +option java_multiple_files = true; +option java_outer_classname = "PublishedDevicesProtos"; +option java_package = "com.google.chrome.widevine.contentpartners.v1beta1"; + +// GCWPD is an acronym for Google Chrome Widevine Published Devices. +option objc_class_prefix = "GCWPD"; + + +// This service produces a list of Widevine supported devices +// signed by a certificate that can be verified by the client. +service PublishedDevicesService { + // Return the PublishedDevices containing the list of devices and a signature. + // The request is used to authenticate the client. + rpc GetPublishedDevices(PublishedDevicesRequest) returns (PublishedDevices) { + + option (google.api.http) = { + post: "/v1beta1/publishedDevices:getSignedBatch" + body: "*" + }; + } + + // Return the ListDeviceSecurityProfilesResponse containing a list of + // device security profiles. + rpc ListDeviceSecurityProfiles(ListDeviceSecurityProfilesRequest) + returns (ListDeviceSecurityProfilesResponse) { + + option (google.api.http) = { + get: "/v1beta1/deviceSecurityProfiles:listDeviceSecurityProfiles" + }; + } +} + +// The SdkClientInformation is produced by the client (a Widevine SDK). It is +// serialized and embedded in the PublishedDevicesRequest. It is used to +// declare attributes of the client's SDK including the Widevine-issued service +// certificate that is used by the client. +message SdkClientInformation { + // The version of sdk. Required. + string sdk_version = 1; + // POSIX time, in seconds, when this request was created. Required. + uint64 sdk_time_seconds = 2; + // The serialized service certificate used to sign the request. Required. + bytes service_certificate = 3; +} + +// A signed request sent to Widevine Provisioning Server (keysmith) to retrieve +// the PublishedDevices. +message PublishedDevicesRequest { + // A serialized SdkClientInformation proto. Required. + bytes sdk_client_information = 1; + + // This is the SHA256 digest, PKCS#7 padded signature of the + // sdk_client_information field. This signature uses the + // RSA private key corresponding to the server certificate. Required. + bytes signature = 2; + + // Optional field that indicates the hash algorithm used in signature scheme. + HashAlgorithm hash_algorithm = 3 [(google.api.field_behavior) = OPTIONAL]; +} + +// Contains a serialized DeviceCertificateStatusList and the signature. +message PublishedDevices { + // Serialized DeviceCertificateStatusList. Required. + // A device certificate status list contains information about various + // device series information such as the make, model and status (RELEASED, + // IN_TESTING, REVOKED, etc).The information is intended to be shared + // publicly. + bytes published_devices = 1; + + // Signature of device_certificate_status_list_request. Signed with root + // certificate private key using RSASSA-PSS. Required. + bytes signature = 2; + + // Optional field that indicates the hash algorithm used in signature scheme. + HashAlgorithm hash_algorithm = 3 [(google.api.field_behavior) = OPTIONAL]; +} diff --git a/tools/source/published_devices_delta/tools/BUILD b/tools/source/published_devices_delta/tools/BUILD new file mode 100644 index 0000000..fd75ed8 --- /dev/null +++ b/tools/source/published_devices_delta/tools/BUILD @@ -0,0 +1,41 @@ +# Copyright 2019 Google LLC. All rights reserved. +# Desciption: +# JTS tools. + +package(default_visibility = ["//visibility:public"]) + +java_library( + name = "published_devices_delta_lib", + srcs = [ + "PublishedDevicesDeltaWrapper.java", + "PublishedDevicesWrapper.java", + ], + deps = [ + "//google/chrome/widevine/contentpartners/v1beta1:published_devices_java_proto", + "@com_google_protobuf//:protobuf_java", + "//video/widevine/protos/public:device_certificate_status_java_proto", + "//video/widevine/protos/public:device_certificate_status_proto", + "//video/widevine/protos/public:published_devices_delta_java_proto", + "//video/widevine/protos/public:published_devices_delta_proto", + "@google_guava//:com_google_guava_guava", + ], +) + +java_binary( + name = "published_devices_delta", + srcs = [ + "PublishedDevicesMain.java", + ], + main_class = "com.google.video.widevine.jts.tools.PublishedDevicesMain", + deps = [ + ":published_devices_delta_lib", + "@com_google_protobuf//:protobuf_java", + "@jcommander//:com_beust_jcommander", + "@json//:org_json_json", + "//video/widevine/protos/public:device_certificate_status_java_proto", + "//video/widevine/protos/public:device_certificate_status_proto", + "//video/widevine/protos/public:published_devices_delta_java_proto", + "//video/widevine/protos/public:published_devices_delta_proto", + "@google_guava//:com_google_guava_guava", + ], +) diff --git a/tools/source/published_devices_delta/tools/PublishedDevicesDeltaWrapper.java b/tools/source/published_devices_delta/tools/PublishedDevicesDeltaWrapper.java new file mode 100644 index 0000000..51628d4 --- /dev/null +++ b/tools/source/published_devices_delta/tools/PublishedDevicesDeltaWrapper.java @@ -0,0 +1,250 @@ +// Copyright 2020 Google LLC. All rights reserved. + +package com.google.video.widevine.jts.tools; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices; +import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.video.widevine.protos.DeviceCertificateStatusProtos.DeviceCertificateStatus; +import com.google.video.widevine.protos.DeviceCertificateStatusProtos.PublishedDevicesList; +import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta; +import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta.Header; +import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta.Modified; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** Published Devices Delta Wrapper class to get {@link PublishedDevicesDelta}. */ +public final class PublishedDevicesDeltaWrapper { + private PublishedDevicesList originalList = null; + private PublishedDevicesList newList = null; + private PublishedDevicesDelta publishedDevicesDelta = null; + private final Map dcslAddedMap = new LinkedHashMap<>(); + private final Map dcslRemovedMap = new LinkedHashMap<>(); + private final Map dcslModifiedMap = new LinkedHashMap<>(); + static final int MAJOR_VERSION = 1; + static final int MINOR_VERSION = 1; + static final int RELEASE = 0; + + /** + * PublishedDevicesDeltaWrapper constructor. The input is two byte array serialized + * PublishedDevices proto. + * + * @param publishedDevicesInBytes1 first serialized PublishedDevices proto in bytes. + * @param publishedDevicesInBytes2 second serialized PublishedDevices proto in bytes. + * @throws InvalidProtocolBufferException if failed to parse published devices or if failed to + * parse PublishedDevicesList. + */ + public PublishedDevicesDeltaWrapper( + byte[] publishedDevicesInBytes1, byte[] publishedDevicesInBytes2) + throws InvalidProtocolBufferException { + checkNotNull(publishedDevicesInBytes1, "'publishedDevicesInBytes1' must not be null"); + checkNotNull(publishedDevicesInBytes2, "'publishedDevicesInBytes2' must not be null"); + PublishedDevices publishedDevices1 = + PublishedDevices.parseFrom(publishedDevicesInBytes1, ExtensionRegistry.getEmptyRegistry()); + PublishedDevices publishedDevices2 = + PublishedDevices.parseFrom(publishedDevicesInBytes2, ExtensionRegistry.getEmptyRegistry()); + parsePublishedDevicesList(publishedDevices1, publishedDevices2); + this.publishedDevicesDelta = createPublishedDevicesDelta(originalList, newList); + createPublishedDevicesDeltaInfo(publishedDevicesDelta); + } + + /** + * PublishedDevicesDeltaWrapper constructor. The input is two PublishedDevices protos. + * + * @param publishedDevices1 first PublishedDevices proto. + * @param publishedDevices2 second PublishedDevices proto. + * @throws InvalidProtocolBufferException if failed to parse PublishedDevicesList from published + * devices. + */ + public PublishedDevicesDeltaWrapper( + PublishedDevices publishedDevices1, PublishedDevices publishedDevices2) + throws InvalidProtocolBufferException { + checkNotNull(publishedDevices1, "'publishedDevices1' must not be null"); + checkNotNull(publishedDevices2, "'publishedDevices2' must not be null"); + parsePublishedDevicesList(publishedDevices1, publishedDevices2); + this.publishedDevicesDelta = createPublishedDevicesDelta(originalList, newList); + createPublishedDevicesDeltaInfo(publishedDevicesDelta); + } + + /** + * PublishedDevicesDeltaWrapper constructor. The input is PublishedDevicesDelta proto. + * + * @param publishedDevicesDelta PublishedDevicesDeltaWrapper proto. + */ + public PublishedDevicesDeltaWrapper(PublishedDevicesDelta publishedDevicesDelta) { + checkNotNull(publishedDevicesDelta, "'delta' must not be null"); + this.publishedDevicesDelta = publishedDevicesDelta; + createPublishedDevicesDeltaInfo(publishedDevicesDelta); + } + + /** Returns {@link PublishedDevicesDelta} of originalPublishedDevices and newPublishedDevices. */ + public PublishedDevicesDelta getDelta() { + return publishedDevicesDelta; + } + + /** + * Returns {@link PublishedDevicesDelta} of originalPublishedDevices and newPublishedDevices. + * + * @param originalList original list in PublishedDevicesList proto + * @param newList new list in PublishedDevicesList proto + */ + static PublishedDevicesDelta createPublishedDevicesDelta( + PublishedDevicesList originalList, PublishedDevicesList newList) { + // Construct PublishedDevicesDelta. + PublishedDevicesDelta.Builder deltaBuilder = PublishedDevicesDelta.newBuilder(); + // Construct Header object. + Header header = + Header.newBuilder() + .setPrevCreationTimeSeconds(originalList.getCreationTimeSeconds()) + .setNewCreationTimeSeconds(newList.getCreationTimeSeconds()) + .build(); + deltaBuilder.setHeader(header); + + // Add removed, added and modified field in to delta. + List prevDCSL = originalList.getDeviceCertificateStatusList(); + List newDcsl = newList.getDeviceCertificateStatusList(); + Map dcslMap = new LinkedHashMap<>(); + // Add all the original DCSLs into the map. + for (DeviceCertificateStatus dcsl : prevDCSL) { + dcslMap.put(dcsl.getDeviceInfo().getSystemId(), dcsl); + } + + for (DeviceCertificateStatus dcsl : newDcsl) { + int systemId = dcsl.getDeviceInfo().getSystemId(); + if (dcslMap.containsKey(systemId) && !dcsl.equals(dcslMap.get(systemId))) { + deltaBuilder.addModifiedBuilder().setPrevDevice(dcslMap.get(systemId)).setNewDevice(dcsl); + } else if (!dcslMap.containsKey(systemId)) { + // Add the new DCSL into added field in PublishedDevicesDeltaWrapper. + deltaBuilder.addAdded(dcsl); + } + // Remove the iterated DCSL from the map. + dcslMap.remove(systemId); + } + // Add the original DCSL into removed field in PublishedDevicesDeltaWrapper. + if (!dcslMap.isEmpty()) { + deltaBuilder.addAllRemoved(dcslMap.values()); + } + + return deltaBuilder.build(); + } + + /** + * Returns the formatted text output of the {@link PublishedDevicesDelta}. + * + * @return String String format of publishedDevices. + */ + public static String toString(PublishedDevicesDelta delta) { + return delta.toString(); + } + + /** Parse {@link PublishedDevicesList} from {@link PublishedDevices}. */ + private void parsePublishedDevicesList( + PublishedDevices publishedDevices1, PublishedDevices publishedDevices2) + throws InvalidProtocolBufferException { + // Parse PublishedDevicesList proto. + originalList = + PublishedDevicesList.parseFrom( + publishedDevices1.getPublishedDevices(), ExtensionRegistry.getEmptyRegistry()); + newList = + PublishedDevicesList.parseFrom( + publishedDevices2.getPublishedDevices(), ExtensionRegistry.getEmptyRegistry()); + + // Swap the PublishedDevicesList list if originalList is newer than newList. + if (originalList.getCreationTimeSeconds() > newList.getCreationTimeSeconds()) { + PublishedDevicesList temp = newList; + newList = originalList; + originalList = temp; + } + } + + /** + * Get {@link DeviceCertificateStatus} of the specific system_id. + * + * @param systemId Device system_id. + * @return DeviceCertificateStatus Returns DeviceCertificateStatus of the specific system_id if it + * is added. Otherwise it will return null. + */ + public DeviceCertificateStatus getAddedDeviceCertificateStatus(int systemId) { + return dcslAddedMap.get(systemId); + } + + /** + * Get {@link DeviceCertificateStatus} of the specific system_id. + * + * @param systemId Device system_id. + * @return DeviceCertificateStatus Returns the DeviceCertificateStatus of the specific system_id + * if it is removed.Otherwise it will return null. + */ + public DeviceCertificateStatus getRemovedDeviceCertificateStatus(int systemId) { + return dcslRemovedMap.get(systemId); + } + + /** + * Get {@link Modified} of the specific system_id. Return null if not found. + * + * @param systemId Device system_id. + * @return Modified Returns ModifiedDeviceCertificateStatus of the specific system_id. Return null + * if not found. + */ + public Modified getModifiedDeviceCertificateStatus(int systemId) { + return dcslModifiedMap.get(systemId); + } + + /** + * Get count of added DeviceCertificateStatus in delta. + * + * @return a list of system_ids for added DeviceCertificateStatus in delta. + */ + public List getAddedDevices() { + return new ArrayList<>(dcslAddedMap.keySet()); + } + + /** + * Get count of modified DeviceCertificateStatus in delta. + * + * @return a list of system_ids for modified DeviceCertificateStatus in delta. + */ + public List getModifiedDevices() { + return new ArrayList<>(dcslRemovedMap.keySet()); + } + + /** + * Get list of system ids for removed DeviceCertificateStatus in delta. + * + * @return a list of system_ids for removed DeviceCertificateStatus in delta. + */ + public List getRemovedDevices() { + return new ArrayList<>(dcslModifiedMap.keySet()); + } + + /** + * Get the version of Published Devices Release. + * + * @return the version of Published Devices Release as a String. + */ + public String getVersion() { + return MAJOR_VERSION + "." + MINOR_VERSION + "." + RELEASE; + } + + /** + * Parse PublishedDevicesDeltaWrapper to get AddedMap, RemovedMap and ModifiedMap for + * PublishedDevicesList. + * + * @param publishedDevicesDelta PublishedDevicesDelta delta. + */ + private void createPublishedDevicesDeltaInfo(PublishedDevicesDelta publishedDevicesDelta) { + for (DeviceCertificateStatus status : publishedDevicesDelta.getAddedList()) { + dcslAddedMap.put(status.getDeviceInfo().getSystemId(), status); + } + for (DeviceCertificateStatus status : publishedDevicesDelta.getRemovedList()) { + dcslRemovedMap.put(status.getDeviceInfo().getSystemId(), status); + } + for (Modified status : publishedDevicesDelta.getModifiedList()) { + dcslModifiedMap.put(status.getPrevDevice().getDeviceInfo().getSystemId(), status); + } + } +} diff --git a/tools/source/published_devices_delta/tools/PublishedDevicesMain.java b/tools/source/published_devices_delta/tools/PublishedDevicesMain.java new file mode 100644 index 0000000..4709723 --- /dev/null +++ b/tools/source/published_devices_delta/tools/PublishedDevicesMain.java @@ -0,0 +1,238 @@ +// Copyright 2020 Google LLC. All rights reserved. +package com.google.video.widevine.jts.tools; + +import static com.google.common.io.BaseEncoding.base64; +import static com.google.common.io.BaseEncoding.base64Url; + +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.video.widevine.protos.DeviceCertificateStatusProtos.DeviceCertificateStatus; +import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Published Devices command line tool. + * + *

Provides a command line tool to get the diff between two PublishedDevices Proto, parse the + * PublishedDevices and PublishedDevicesDelta. + * + *

To build: Bazel build tools:published_devices_delta_deploy.jar + * + *

To run: java -jar /path/to/published_devices_lib_deploy.jar -new_published_devices_path path + * -original_published_devices_path path -print + * + *

To run: java -jar /path/to/published_devices_lib_deploy.jar -new_published_devices_path path + * -original_published_devices_path path -system_id 100 -get_system_ids + * + *

To run: java -jar /path/to/published_devices_lib_deploy.jar -query path -system_id 100 + */ +final class PublishedDevicesMain { + private static final Logger logger = Logger.getLogger(PublishedDevicesMain.class.getName()); + private static final int ZERO_SYSTEM_ID = 0; + private static final String JSON_NAME = "signedList"; + /** Command Line Flags. */ + static class Flags { + private Flags() {} + + @Parameter( + names = "-original_published_devices_path", + description = "Path to original PublishedDevices file") + private String originalPublishedDevicesPath = null; + + @Parameter( + names = "-new_published_devices_path", + description = "Path to new PublishedDevices file") + private String newPublishedDevicesPath = null; + + @Parameter( + names = "-print", + description = + "Setting to true, if content provider want to print the published devices in String.") + private boolean print = false; + + @Parameter(names = "-query", description = "Parse published devices file.") + private String query = null; + + @Parameter(names = "-system_id", description = "Device system-id.") + private int systemId = ZERO_SYSTEM_ID; + + @Parameter( + names = "-get_system_ids", + description = + "Boolean to get list of system_ids in added/removed/modified PublishedDevicesList.") + private boolean getSystenIdsList = false; + } + + /** Main function to run Published Devices Delta command line tool. */ + public static void main(String[] args) { + Flags flags = new Flags(); + new JCommander(flags, args); + if (flags.newPublishedDevicesPath != null && flags.originalPublishedDevicesPath != null) { + parsePublishedDevicesDelta(flags); + } else if (flags.query != null) { + try { + byte[] publishedDevices = getPublishedDevicesAsBytes(flags.query); + checkLoadFileResult(flags.query, publishedDevices); + PublishedDevicesWrapper wrapper = new PublishedDevicesWrapper(publishedDevices); + if (flags.systemId != ZERO_SYSTEM_ID) { + DeviceCertificateStatus deviceCertificateStatus = + wrapper.getDeviceCertificateStatus(flags.systemId); + if (deviceCertificateStatus == null) { + logger.log( + Level.SEVERE, + flags.systemId + + " (system-id) does not found in PublishedDevicesList from " + + flags.query); + System.exit(1); + } + System.out.println(deviceCertificateStatus); + // TODO(b/160253740): Add ProvisonedStatus, ProvisionedDeviceInfo and function. + } + } catch (InvalidProtocolBufferException e) { + logger.log( + Level.SEVERE, + "InvalidProtocolBufferException encountered to parse device certificate status list" + + " or published devices proto:" + + e); + } catch (IOException e) { + logger.log( + Level.SEVERE, "IOException encountered trying to open published devices file: " + e); + } + } else if (flags.originalPublishedDevicesPath != null + || flags.newPublishedDevicesPath != null) { + logger.log( + Level.SEVERE, + "Both originalPublishedDevicesPath and newPublishedDevicesPath should be specified."); + } + } + + /** Parse the argument related to PublishedDevicesDelta. */ + private static void parsePublishedDevicesDelta(Flags flags) { + try { + byte[] originalPublishedDevices = + getPublishedDevicesAsBytes(flags.originalPublishedDevicesPath); + byte[] newPublishedDevices = getPublishedDevicesAsBytes(flags.newPublishedDevicesPath); + checkLoadFileResult(flags.originalPublishedDevicesPath, originalPublishedDevices); + checkLoadFileResult(flags.newPublishedDevicesPath, newPublishedDevices); + PublishedDevicesDeltaWrapper devices = + new PublishedDevicesDeltaWrapper(originalPublishedDevices, newPublishedDevices); + PublishedDevicesDelta delta = devices.getDelta(); + if (flags.print) { + System.out.println(delta); + } + parseDeltaInfo(devices, flags); + } catch (IOException e) { + logger.log( + Level.SEVERE, "IOException encountered trying to open published devices files: " + e); + } + } + + /** Parse the argument related to PublishedDevicesDelta. */ + private static void parseDeltaInfo( + PublishedDevicesDeltaWrapper publishedDevicesDelta, Flags flags) { + if (flags.systemId != 0) { + if (publishedDevicesDelta.getAddedDeviceCertificateStatus(flags.systemId) != null) { + System.out.println( + flags.systemId + " system-id is found in added field of published devices delta."); + System.out.println(publishedDevicesDelta.getAddedDeviceCertificateStatus(flags.systemId)); + + } else if (publishedDevicesDelta.getRemovedDeviceCertificateStatus(flags.systemId) != null) { + System.out.println( + flags.systemId + " system-id is found in removed field of published devices delta."); + System.out.println(publishedDevicesDelta.getRemovedDeviceCertificateStatus(flags.systemId)); + } else if (publishedDevicesDelta.getModifiedDeviceCertificateStatus(flags.systemId) != null) { + System.out.println( + flags.systemId + " system-id is found in modified field of published devices delta."); + System.out.println( + publishedDevicesDelta.getModifiedDeviceCertificateStatus(flags.systemId)); + } else { + logger.log(Level.SEVERE, flags.systemId + "does not found in the PublishedDevicesDelta."); + } + } + if (flags.getSystenIdsList) { + System.out.println( + "List of system_id for added published devices in published devices delta: " + + publishedDevicesDelta.getAddedDevices()); + System.out.println( + "List of system_id for removed published devices in published devices delta: " + + publishedDevicesDelta.getRemovedDevices()); + System.out.println( + "List of system_id for removed published devices in published devices delta: " + + publishedDevicesDelta.getModifiedDevices()); + } + } + + private static void checkLoadFileResult(String filePath, byte[] result) { + if (result == null) { + logger.log(Level.SEVERE, "Fail to load the file:" + filePath); + System.exit(1); + } + } + + /** + * Load published devices Json file into string. + * + * @param filePath file path in String. + * @return byte array file content in String. + * @throws IOException if failed to read the file. + */ + public static byte[] getPublishedDevicesAsBytes(String filePath) throws IOException { + String result = loadFile(filePath); + if (result == null) { + return null; + } + String requestBody = ""; + try { + // Parse both PublishedDevices v1 output. + JSONObject obj = new JSONObject(result); + requestBody = obj.getString(JSON_NAME); + } catch (JSONException e) { + // Parse both PublishedDevices v2 output. + requestBody = result; + } + byte[] serializedDCSL = base64Decode(requestBody); + + return serializedDCSL; + } + + /** + * Load file into string. + * + * @param filePath file path in String. + * @return String file content in String. + * @throws IOException if failed to read the file. + */ + public static String loadFile(String filePath) throws IOException { + StringBuilder result = new StringBuilder(); + List input = Files.readAllLines(Paths.get(filePath)); + for (String element : input) { + result.append(element); + } + return result.toString(); + } + + /** + * Decodes a base64-encoded string or web-safe base64-encoded string. + * + * @param base64EncodedData base64 encode data in String. + * @return byte[] decoded string in byte array. + */ + public static byte[] base64Decode(String base64EncodedData) { + try { + return base64().decode(base64EncodedData); + } catch (IllegalArgumentException e) { + // Do nothing. Try the url safe base64 decode next. + } + return base64Url().decode(base64EncodedData); + } + + private PublishedDevicesMain() {} +} diff --git a/tools/source/published_devices_delta/tools/PublishedDevicesWrapper.java b/tools/source/published_devices_delta/tools/PublishedDevicesWrapper.java new file mode 100644 index 0000000..d781bac --- /dev/null +++ b/tools/source/published_devices_delta/tools/PublishedDevicesWrapper.java @@ -0,0 +1,104 @@ +// Copyright 2020 Google LLC. All rights reserved. +package com.google.video.widevine.jts.tools; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.chrome.widevine.contentpartners.v1beta1.PublishedDevices; +import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.video.widevine.protos.DeviceCertificateStatusProtos.DeviceCertificateStatus; +import com.google.video.widevine.protos.DeviceCertificateStatusProtos.PublishedDevicesList; +import com.google.video.widevine.protos.PublishedDevicesDeltaProtos.PublishedDevicesDelta; +import java.util.LinkedHashMap; +import java.util.Map; + +/** Wrap the PublishedDevices proto in PublishedDevicesWrapper. */ +final class PublishedDevicesWrapper { + private PublishedDevices publishedDevices = null; + private PublishedDevicesList publishedDevicesList = null; + private final Map dcslMap = new LinkedHashMap<>(); + + /** Constructor to create PublishedDevicesWrapper object with {@link PublishedDevices} */ + public PublishedDevicesWrapper(PublishedDevices publishedDevices) + throws InvalidProtocolBufferException { + checkNotNull(publishedDevices, "'published devices' must not be null"); + this.publishedDevices = publishedDevices; + parsePublishedDevicesList(); + } + + /** + * Constructor to create PublishedDevicesWrapper object with byte array from {@link + * PublishedDevices} serialized proto. + */ + public PublishedDevicesWrapper(byte[] publishedDevicesInfo) + throws InvalidProtocolBufferException { + checkNotNull(publishedDevicesInfo, "'published devices' must not be null"); + publishedDevices = + PublishedDevices.parseFrom(publishedDevicesInfo, ExtensionRegistry.getEmptyRegistry()); + parsePublishedDevicesList(); + } + + private void parsePublishedDevicesList() throws InvalidProtocolBufferException { + publishedDevicesList = + PublishedDevicesList.parseFrom( + publishedDevices.getPublishedDevices(), ExtensionRegistry.getEmptyRegistry()); + + // Add all the original DCSLs into the map. + for (DeviceCertificateStatus dcsl : publishedDevicesList.getDeviceCertificateStatusList()) { + dcslMap.put(dcsl.getDeviceInfo().getSystemId(), dcsl); + } + } + + /** + * Get PublishedDevicesList . + * + * @return {@link PublishedDevicesList} field in {@link PublishedDevices}. + */ + public PublishedDevicesList getPublishedDevicesList() { + + return publishedDevicesList; + } + /** + * Get DeviceCertificateStatus for specific systemId. + * + * @param systemId systemId in Integer. + * @return {@link DeviceCertificateStatus} for specific systemId. + */ + public DeviceCertificateStatus getDeviceCertificateStatus(int systemId) { + return dcslMap.get(systemId); + } + + /** + * Get the size of PublishedDevicesList. + * + * @return int Size of PublishedDevicesList. + */ + public int getSize() { + return publishedDevicesList.getDeviceCertificateStatusCount(); + } + + /** + * Return PublishedDevicesList as a String. + * + * @return {@link PublishedDevicesList} in String. + */ + @Override + public String toString() { + return publishedDevicesList.toString(); + } + + /** + * Get {@link PublishedDevicesDelta} by getting delta of new PublishedDevices with current + * PublishedDevices. + * + * @param newPublishedDevices PublishedDevices proto. + * @return {@link PublishedDevicesDelta}. + * @throws InvalidProtocolBufferException if failed to parse published devices. + */ + public PublishedDevicesDelta getPublishedDevicesDelta(PublishedDevices newPublishedDevices) + throws InvalidProtocolBufferException { + PublishedDevicesDeltaWrapper delta = + new PublishedDevicesDeltaWrapper(this.publishedDevices, newPublishedDevices); + return delta.getDelta(); + } +} diff --git a/tools/source/published_devices_delta/video/widevine/protos/public/BUILD b/tools/source/published_devices_delta/video/widevine/protos/public/BUILD new file mode 100644 index 0000000..e4c94f5 --- /dev/null +++ b/tools/source/published_devices_delta/video/widevine/protos/public/BUILD @@ -0,0 +1,299 @@ +# Copyright 2017 Google LLC. All rights reserved. + +# Protocol buffer definitions for Widevine Services License Server SDK. + +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "wvdrm_binary_release_files", + srcs = glob(["**"]), +) + +filegroup( + name = "wvpl_binary_release_files", + srcs = [":exported_wvpl_license_server_sdk_proto"], +) + +proto_library( + name = "exported_wvpl_license_server_sdk_proto", + srcs = [ + "client_identification.proto", + "errors.proto", + "hash_algorithm.proto", + "license_protocol.proto", + "license_server_sdk.proto", + "provisioned_device_info.proto", + "remote_attestation.proto", + "sdk_license_data_config.proto", + "signed_drm_certificate.proto", + "verified_media_pipeline.proto", + "widevine_pssh.proto", + ], +) + +proto_library( + name = "exported_wvdrm_license_server_sdk_proto", + srcs = [ + "client_identification.proto", + "device_certificate_status.proto", + "drm_certificate.proto", + "errors.proto", + "hash_algorithm.proto", + "license_protocol.proto", + "license_server_sdk.proto", + "provisioned_device_info.proto", + "remote_attestation.proto", + "sdk_license_data_config.proto", + "signed_drm_certificate.proto", + "verified_media_pipeline.proto", + "widevine_pssh.proto", + ], +) + +java_proto_library( + name = "exported_wvpl_license_server_sdk_java_proto", + deps = [":exported_wvpl_license_server_sdk_proto"], +) + +java_proto_library( + name = "exported_wvdrm_license_server_sdk_java_proto", + deps = [":exported_wvdrm_license_server_sdk_proto"], +) + +proto_library( + name = "client_identification_proto", + srcs = ["client_identification.proto"], +) + +cc_proto_library( + name = "client_identification_cc_proto", + deps = [":client_identification_proto"], +) + +java_proto_library( + name = "client_identification_java_proto", + deps = [":client_identification_proto"], +) + +proto_library( + name = "device_certificate_status_proto", + srcs = ["device_certificate_status.proto"], + deps = [ + ":hash_algorithm_proto", + ":provisioned_device_info_proto", + ], +) + +cc_proto_library( + name = "device_common_cc_proto", + deps = [":device_common_proto"], +) + +java_proto_library( + name = "device_common_java_proto", + deps = [":device_common_proto"], +) + +proto_library( + name = "device_common_proto", + srcs = ["device_common.proto"], +) + +cc_proto_library( + name = "device_certificate_status_cc_proto", + deps = [":device_certificate_status_proto"], +) + +java_proto_library( + name = "device_certificate_status_java_proto", + deps = [":device_certificate_status_proto"], +) + +proto_library( + name = "drm_certificate_proto", + srcs = ["drm_certificate.proto"], +) + +cc_proto_library( + name = "drm_certificate_cc_proto", + deps = [":drm_certificate_proto"], +) + +java_proto_library( + name = "drm_certificate_java_proto", + deps = [":drm_certificate_proto"], +) + +proto_library( + name = "errors_proto", + srcs = ["errors.proto"], + deps = [], +) + +cc_proto_library( + name = "errors_cc_proto", + deps = [":errors_proto"], +) + +java_proto_library( + name = "errors_java_proto", + deps = [":errors_proto"], +) + +proto_library( + name = "license_protocol_proto", + srcs = ["license_protocol.proto"], + deps = [ + ":client_identification_proto", + ":drm_certificate_proto", + ":hash_algorithm_proto", + ":remote_attestation_proto", + ], +) + +cc_proto_library( + name = "license_protocol_cc_proto", + deps = [":license_protocol_proto"], +) + +java_proto_library( + name = "license_protocol_java_proto", + deps = [":license_protocol_proto"], +) + +proto_library( + name = "license_server_sdk_proto", + srcs = ["license_server_sdk.proto"], + deps = [ + ":license_protocol_proto", + ":widevine_pssh_proto", + ], +) + +cc_proto_library( + name = "license_server_sdk_cc_proto", + deps = [":license_server_sdk_proto"], +) + +java_proto_library( + name = "license_server_sdk_java_proto", + deps = [":license_server_sdk_proto"], +) + +proto_library( + name = "provisioned_device_info_proto", + srcs = ["provisioned_device_info.proto"], + deps = [":device_common_proto"], +) + +cc_proto_library( + name = "provisioned_device_info_cc_proto", + deps = [":provisioned_device_info_proto"], +) + +java_proto_library( + name = "provisioned_device_info_java_proto", + deps = [":provisioned_device_info_proto"], +) + +proto_library( + name = "published_devices_delta_proto", + srcs = ["published_devices_delta.proto"], + deps = [":device_certificate_status_proto"], +) + +cc_proto_library( + name = "published_devices_delta_cc_proto", + deps = [":published_devices_delta_proto"], +) + +java_proto_library( + name = "published_devices_delta_java_proto", + deps = [":published_devices_delta_proto"], +) + +proto_library( + name = "remote_attestation_proto", + srcs = ["remote_attestation.proto"], + deps = [":client_identification_proto"], +) + +cc_proto_library( + name = "remote_attestation_cc_proto", + deps = [":remote_attestation_proto"], +) + +java_proto_library( + name = "remote_attestation_java_proto", + deps = [":remote_attestation_proto"], +) + +proto_library( + name = "sdk_license_data_config_proto_base", + srcs = ["sdk_license_data_config.proto"], + deps = [ + ":license_protocol_proto", + ":license_server_sdk_proto", + ], +) + +java_proto_library( + name = "sdk_license_data_config_java_proto", + deps = [":sdk_license_data_config_proto_base"], +) + +proto_library( + name = "signed_drm_certificate_proto", + srcs = ["signed_drm_certificate.proto"], +) + +java_proto_library( + name = "signed_drm_certificate_java_proto", + deps = [":signed_drm_certificate_proto"], +) + +cc_proto_library( + name = "signed_drm_certificate_cc_proto", + deps = [":signed_drm_certificate_proto"], +) + +proto_library( + name = "verified_media_pipeline_proto", + srcs = ["verified_media_pipeline.proto"], + deps = [":hash_algorithm_proto"], +) + +cc_proto_library( + name = "verified_media_pipeline_cc_proto", + deps = [":verified_media_pipeline_proto"], +) + +proto_library( + name = "widevine_pssh_proto", + srcs = ["widevine_pssh.proto"], +) + +cc_proto_library( + name = "widevine_pssh_cc_proto", + deps = [":widevine_pssh_proto"], +) + +java_proto_library( + name = "widevine_pssh_java_proto", + deps = [":widevine_pssh_proto"], +) + +proto_library( + name = "hash_algorithm_proto", + srcs = ["hash_algorithm.proto"], +) + +cc_proto_library( + name = "hash_algorithm_cc_proto", + deps = [":hash_algorithm_proto"], +) + +java_proto_library( + name = "hash_algorithm_java_proto", + deps = [":hash_algorithm_proto"], +) diff --git a/tools/source/published_devices_delta/video/widevine/protos/public/device_certificate_status.proto b/tools/source/published_devices_delta/video/widevine/protos/public/device_certificate_status.proto new file mode 100644 index 0000000..7f01e43 --- /dev/null +++ b/tools/source/published_devices_delta/video/widevine/protos/public/device_certificate_status.proto @@ -0,0 +1,93 @@ +// Copyright 2017 Google LLC. All rights reserved. +// +// Author: tinskip@google.com (Thomas Inskip) +// +// Description: +// Device certificate status list object definitions. + +syntax = "proto2"; + +package video_widevine; + +import "video/widevine/protos/public/hash_algorithm.proto"; +import "video/widevine/protos/public/provisioned_device_info.proto"; + +option java_outer_classname = "DeviceCertificateStatusProtos"; +option java_package = "com.google.video.widevine.protos"; + +// Contains DRM and OEM certificate status and device information for a +// specific system ID. +// TODO(tinskip): Move this to its own file. +message DeviceCertificateStatus { + enum DeprecatedStatus { + DEPRECATED_VALID = 0; + DEPRECATED_REVOKED = 1; + } + enum Status { + STATUS_UNKNOWN = 0; + STATUS_IN_TESTING = 10; // Pre-release, active device. + STATUS_RELEASED = 20; // Released, active device. + STATUS_TEST_ONLY = 30; // Development-only device. + STATUS_REVOKED = 40; // Revoked device. + } + + message RevokedIdentifiers { + // Contains a sorted list of DRM serial numbers that are revoked. + repeated bytes revoked_certificate_serial_numbers = 1; + // Contains a sorted list of revoked_unique_id_hashes that are revoked. + // These identifiers are hash values of the root of trust identifier. + // For a keybox, hash = SHA256(KeyboxUniqueID || SecretSauce) where + // SecretSauce is a Widevine owned secret. For Provisioning 3.0, hash = + // SHA256(X509SerialNumber|| SecretSauce) where SecretSauce is a Widevine + // owned secret. + repeated bytes revoked_unique_id_hashes = 2; + } + + // Serial number of the intermediate DrmCertificate to which this + // message refers. Required. + optional bytes drm_serial_number = 1; + // Status of the certificate. Optional & deprecated in favor of |status| + // below. + optional DeprecatedStatus deprecated_status = 2 [default = DEPRECATED_VALID]; + // Device model information about the device to which the intermediate + // certificate(s) correspond. + optional ProvisionedDeviceInfo device_info = 4; + // Serial number of the OEM X.509 intermediate certificate for this type + // of device. Present only if the device is OEM-provisioned. + optional bytes oem_serial_number = 5; + // Status of the device. Optional. + optional Status status = 6 [default = STATUS_UNKNOWN]; + + // RevokedIdentifiers collect all the serial_numbers or unique_id_hashes used + // for individual drm certificate revocation. + optional RevokedIdentifiers revoked_identifiers = 7; +} + +// List of DeviceCertificateStatus. Used to propagate certificate revocation +// status and device information. +message DeviceCertificateStatusList { + // POSIX time, in seconds, when the list was created. Required. + optional uint32 creation_time_seconds = 1; + // DeviceCertificateStatus for each system ID. + repeated DeviceCertificateStatus certificate_status = 2; +} + +// List of DeviceCertificateStatus. Used to propagate certificate revocation +// status and device information. (Used in published devices library) +message PublishedDevicesList { + // POSIX time, in seconds, when the list was created. Required. + optional uint32 creation_time_seconds = 1; + // DeviceCertificateStatus for each system ID. + repeated DeviceCertificateStatus device_certificate_status = 2; +} + +// Signed CertificateStatusList +message SignedDeviceCertificateStatusList { + // Serialized DeviceCertificateStatusList. Required. + optional bytes certificate_status_list = 1; + // Signature of certificate_status_list. Signed with root certificate private + // key using RSASSA-PSS. Required. + optional bytes signature = 2; + // Optional field that indicates the hash algorithm used in signature scheme. + optional HashAlgorithmProto hash_algorithm = 3; +} diff --git a/tools/source/published_devices_delta/video/widevine/protos/public/device_common.proto b/tools/source/published_devices_delta/video/widevine/protos/public/device_common.proto new file mode 100644 index 0000000..f7e5428 --- /dev/null +++ b/tools/source/published_devices_delta/video/widevine/protos/public/device_common.proto @@ -0,0 +1,169 @@ +// Copyright 2020 Google LLC. All rights reserved. +// +// This file contains device-related definitions that are common to both the +// legacy device management service and the new devices service. Eventually, +// we may merge the contents of this file into other files. + +syntax = "proto3"; + +package video_widevine; + +option java_package = "com.google.video.widevine.protos"; + +// MOE:begin_strip + // See http://go/go-api-flag. +// MOE:end_strip + +// Allows additional make/models to be associated with a system_id. +message DeviceModel { + // ModelStatus is used to specify how confident we are that this + // make/model/year combination is allowed by the device manufacturer. + // VERIFIED indicates that the manufacturer confirmed that it is correct. + // UNVERIFIED means that we have sufficient data to believe it is correct, + // but the manufacturer has not confirmed. + // UNKNOWN indicates that we do not have sufficient information to indicate + // whether or not the device is allowed by the manufacturer. + // REJECTED indicates that the manufacturer explicitly disallowed the use + // of the make/model/year combination. + enum ModelStatus { + MODEL_STATUS_UNSPECIFIED = 0; + MODEL_STATUS_VERIFIED = 1; + MODEL_STATUS_UNVERIFIED = 2; + MODEL_STATUS_UNKNOWN = 4; + MODEL_STATUS_REJECTED = 3; + } + // Represents the device manufacturer. Typically, this will be Philips, LG, + // Sharp, etc. + string manufacturer = 1; + // Model of the device. + string model_name = 2; + // The expected release year of the make/model combination. Optional. + uint32 model_year = 3; + // The model status of this make and model. + ModelStatus status = 4; +} + +// DeviceState defines the current state of the device. It is used in +// licensing to determine if a (classic or MDRM/CENC) license should be +// issued. The status affects if and how a device record is shown in +// keysmith's CertificateStatusList. +// +// States: +// DEVICE_STATE_UNKNOWN: This should not be used. +// It only indicates that a state has not been set. +// IN_TESTING: The first valid state of a device record. A newly created +// device should be in this state until the device is considered +// "released". In this state a device should only be supported on test +// services (e.g. UAT license service). +// PRE_RELEASE: The state of a device when it's ready to be used with +// production services. In this state a device can receive production +// classic and MDRM/CENC licenses. The device will also be listed in +// keysmith's certificate status list. The device data will be +// available for sharing with internal partners only. +// RELEASED: Indicates that the device is available on the store shelves. +// The device data will be available for sharing with external partners. +// DELETED: Indicates that the device was manually disabled and should +// not be used for any test or production services. The device should +// not appear in the device certificate status list. Customers will +// not be able to see or utilize this state when managing their devices. +// TEST_ONLY: Indicates that this device was never intended for production +// but can be used for test purposes. The device will be listed in the +// certificate status list as a test device. +// REVOKED: Indicates that the device was revoked. No test or production +// service should honor requests (classic nor MDRM/CENC) from one of +// these devices. The device serial number and its REVOKED status will +// appear in keysmith's certificate status list. +// +// Devices in the above states have the following behaviors in widevince +// services: +// +// Licensing | Certificate | Cert | Cert | Test | +// State Prod | UAT | Provisioning | Listed | status | device | redact +// -- -- -- -- -- -- -- -- +// IN_TESTING No Yes Yes Yes VALID true yes +// TEST_ONLY No Yes Yes Yes VALID true no +// PRE_RELEASE Yes Yes Yes Yes VALID false yes +// RELEASED Yes Yes Yes Yes VALID false no +// REVOKED No No No Yes REVOKED false no +// DELETED No No No No n/a n/a n/a +enum DeviceState { + DEVICE_STATE_UNKNOWN = 0; + IN_TESTING = 1; + RELEASED = 2; + DELETED = 3; + TEST_ONLY = 4; + REVOKED = 5; + PRE_RELEASE = 6; +} + +// Specifies the device type, or form factor of a device. +enum DeviceType { + DEVICE_TYPE_UNSPECIFIED = 0; + DEVICE_TYPE_PHONE = 1; + DEVICE_TYPE_TV = 2; + DEVICE_TYPE_TABLET = 3; + DEVICE_TYPE_GAMING_CONSOLE = 4; + DEVICE_TYPE_SET_TOP_BOX = 5; + DEVICE_TYPE_VIDEO_DONGLE = 6; + DEVICE_TYPE_PC = 7; + DEVICE_TYPE_AUTO = 8; + DEVICE_TYPE_WEARABLE = 9; + DEVICE_TYPE_CONNECTED_AUDIO_DEVICE = 10; + DEVICE_TYPE_SMART_DISPLAY = 11; + // Legacy identifier for records that were created for SoC integration. + DEVICE_TYPE_SOC = 12; +} + +// Specifies the platform and OS of the device. +enum Platform { + PLATFORM_UNSPECIFIED = 0; + PLATFORM_CHROMECAST = 1; + PLATFORM_FUCHSIA = 2; + PLATFORM_IOS = 3; + PLATFORM_IPAD_OS = 4; + PLATFORM_TV_OS = 5; + PLATFORM_ANDROID = 6; + PLATFORM_WINDOWS = 7; + PLATFORM_CHROME_OS = 8; + PLATFORM_MAC_OS = 9; + PLATFORM_LINUX = 10; + PLATFORM_WEB_OS = 11; + PLATFORM_TIZEN = 12; + PLATFORM_FIRE_OS = 13; + PLATFORM_ROKU = 14; + PLATFORM_PLAYSTATION = 15; + PLATFORM_XBOX = 16; + PLATFORM_KAIOS = 17; + PLATFORM_RDK = 18; + PLATFORM_OTHER = 19; +} + +// This is used for tri-state answers. Yes-TEE, Yes-REE, No. +// This has to be in device_common to avoid import conflicts between security +// profiles and device security profiles. +enum OsOptionalSupport { + OS_OPTIONAL_SUPPORT_UNSPECIFIED = 0; + YES_TEE = 1; + YES_REE = 2; + NO_SUPPORT = 3; +} + +// Version of High-bandwidth Digital Content Protection (HDCP). +// This has to be in device_common to avoid import conflicts between security +// profiles and device security profiles. +enum HdcpVersion { + HDCP_VERSION_UNSPECIFIED = 0; + HDCP_V1 = 1; + HDCP_V2 = 2; + HDCP_V2_1 = 3; + HDCP_V2_2 = 4; + HDCP_V2_3 = 5; +} + +// Widevine device security level. +enum DeviceSecurityLevel { + SECURITY_LEVEL_UNSPECIFIED = 0; + LEVEL_1 = 1; + LEVEL_2 = 2; + LEVEL_3 = 3; +} diff --git a/tools/source/published_devices_delta/video/widevine/protos/public/hash_algorithm.proto b/tools/source/published_devices_delta/video/widevine/protos/public/hash_algorithm.proto new file mode 100644 index 0000000..a0a17ea --- /dev/null +++ b/tools/source/published_devices_delta/video/widevine/protos/public/hash_algorithm.proto @@ -0,0 +1,15 @@ +// Copyright 2020 Google LLC. All rights reserved. + +syntax = "proto3"; + +package video_widevine; + +// LINT.IfChange +enum HashAlgorithmProto { + // Unspecified hash algorithm: SHA_256 shall be used for ECC based algorithms + // and SHA_1 shall be used otherwise. + HASH_ALGORITHM_UNSPECIFIED = 0; + HASH_ALGORITHM_SHA_1 = 1; + HASH_ALGORITHM_SHA_256 = 2; +} +// LINT.ThenChange(//depot/google3/google/chrome/widevine/contentpartners/v1beta1/device_security_profiles.proto) diff --git a/tools/source/published_devices_delta/video/widevine/protos/public/provisioned_device_info.proto b/tools/source/published_devices_delta/video/widevine/protos/public/provisioned_device_info.proto new file mode 100644 index 0000000..8415bce --- /dev/null +++ b/tools/source/published_devices_delta/video/widevine/protos/public/provisioned_device_info.proto @@ -0,0 +1,78 @@ +// Copyright 2016 Google LLC. All rights reserved. + +// Description: +// Provisioned device info format definitions. + +syntax = "proto2"; + +package video_widevine; + +import "video/widevine/protos/public/device_common.proto"; + +option java_package = "com.google.video.widevine.protos"; +option java_outer_classname = "ProvisionedDeviceInfoProto"; + +// MOE:begin_strip + // See http://go/go-api-flag. +// MOE:end_strip + +// Contains device model information for a provisioned device. +message ProvisionedDeviceInfo { + enum WvSecurityLevel { + // Defined in Widevine Security Integration Guide for DASH on Android: + // http://doc/1Zum-fcJeoIw6KG1kDP_KepIE5h9gAZg0PaMtemBvk9c/edit#heading=h.1t3h5sf + LEVEL_UNSPECIFIED = 0; + LEVEL_1 = 1; + LEVEL_2 = 2; + LEVEL_3 = 3; + } + // Widevine initial provisioning / bootstrapping method. DRM certificates are + // required for retrieving licenses, so if a DRM certificate is not initially + // provisioned, then the provisioned credentials will be used to provision + // a DRM certificate via the Widevine Provisioning Service. + enum ProvisioningMethod { + // Don't use this. + PROVISIONING_METHOD_UNSPECIFIED = 0; + // Factory-provisioned device-unique keybox. + FACTORY_KEYBOX = 1; + // Factory-provisioned device-unique OEM certificate. + FACTORY_OEM_DEVICE_CERTIFICATE = 2; + // Factory-provisioned model-group OEM certificate. + FACTORY_OEM_GROUP_CERTIFICATE = 3; + // Factory-provisioned model-group DRM certificate (Level-3 "baked in"). + FACTORY_DRM_GROUP_CERTIFICATE = 4; + // OTA-provisioned keybox (Level-1 ARC++). + OTA_KEYBOX = 5; + // OTA-provisioned device-unique OEM certificate. + OTA_OEM_DEVICE_CERTIFICATE = 6; + // OTA-provisioned model-group OEM certificate. + OTA_OEM_GROUP_CERTIFICATE = 7; + // OTA-provisioned device-unique DRM certificate (Bedrock). + OTA_DRM_DEVICE_CERTIFICATE = 8; + // OTA-provisioned device-unique OEM certificate (Beanstalk). + OTA_OEM_DEVICE_CERTIFICATE_SIGMA_210 = 9; + } + + // Widevine system ID for the device. Mandatory. + optional uint32 system_id = 1; + // Name of system-on-a-chip. Optional. + optional string soc = 2; + // First registered manufacturer. Optional. + optional string manufacturer = 3; + // First registered manufacturer's model name. Matches "brand" in device + // metadata. Optional. + optional string model = 4; + // First registered type of device (Phone, Tablet, TV, etc). + optional string device_type = 5; + // First registered device model year. Optional. + optional uint32 model_year = 6; + // Widevine-defined security level. Optional. + optional WvSecurityLevel security_level = 7 [default = LEVEL_UNSPECIFIED]; + // True if the certificate corresponds to a test (non production) device. + // Optional. + optional bool test_device = 8 [default = false]; + // Indicates the type of device root of trust which was factory provisioned. + optional ProvisioningMethod provisioning_method = 9; + // A list of ModelInfo using the same system_id. + repeated DeviceModel model_info = 10; +} diff --git a/tools/source/published_devices_delta/video/widevine/protos/public/published_devices_delta.proto b/tools/source/published_devices_delta/video/widevine/protos/public/published_devices_delta.proto new file mode 100644 index 0000000..36b2d43 --- /dev/null +++ b/tools/source/published_devices_delta/video/widevine/protos/public/published_devices_delta.proto @@ -0,0 +1,36 @@ +// Copyright 2020 Google LLC. All rights reserved. +// +// Description: +// PublishedDevicesDelta object definitions. + +syntax = "proto2"; + +package video_widevine; + +import "video/widevine/protos/public/device_certificate_status.proto"; + +option java_outer_classname = "PublishedDevicesDeltaProtos"; +option java_package = "com.google.video.widevine.protos"; + +// Contains lists of DeviceCertificateStatus for added or removed or modified +// devices. Used to find delta of two PublishedDevices. +message PublishedDevicesDelta { + message Header { + optional uint32 prev_creation_time_seconds = 1; + optional uint32 new_creation_time_seconds = 2; + } + + message Modified { + optional DeviceCertificateStatus prev_device = 1; + optional DeviceCertificateStatus new_device = 2; + } + + // POSIX time, in seconds, show the delta of creation_time_seconds. Optional. + optional Header header = 1; + // List of added DeviceCertificateStatus. + repeated DeviceCertificateStatus added = 2; + // List of removed DeviceCertificateStatus. + repeated DeviceCertificateStatus removed = 3; + // List of modified DeviceCertificateStatus. + repeated Modified modified = 4; +}