# Copyright (C) 2021 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. load("@bazel_skylib//lib:paths.bzl", "paths") load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") AndroidAppCertificateInfo = provider( "Info needed for Android app certificates", fields = { "pem": "Certificate .pem file", "pk8": "Certificate .pk8 file", "key_name": "Key name", }, ) NoAndroidAppCertificateInfo = provider( "A provider that indicates this target is NOT an android app certificate. It's used as the default value for an apex's certificate override.", ) def _no_android_app_certificate_rule_impl(_ctx): return [NoAndroidAppCertificateInfo()] no_android_app_certificate = rule( implementation = _no_android_app_certificate_rule_impl, ) def _android_app_certificate_rule_impl(ctx): cert_name = ctx.attr.certificate pk8 = ctx.file.pk8 pem = ctx.file.pem return [ AndroidAppCertificateInfo(pem = pem, pk8 = pk8, key_name = cert_name), ] _android_app_certificate = rule( implementation = _android_app_certificate_rule_impl, attrs = { "pem": attr.label(mandatory = True, allow_single_file = [".pem"]), "pk8": attr.label(mandatory = True, allow_single_file = [".pk8"]), "certificate": attr.string(mandatory = True), }, ) def android_app_certificate( name, certificate, **kwargs): "Bazel macro to correspond with the Android app certificate Soong module." _android_app_certificate( name = name, pem = certificate + ".x509.pem", pk8 = certificate + ".pk8", certificate = certificate, **kwargs ) def _search_cert_files(cert_name, cert_filegroup): pk8 = None pem = None files = cert_filegroup[DefaultInfo].files.to_list() # For overriding to a specific *file* in a provided directory with cert_name in the actual filename for f in files: if f.basename == cert_name + ".pk8": pk8 = f elif f.basename == cert_name + ".x509.pem": pem = f if not pk8: fail("Could not find .pk8 file for the module '%s' in the list: %s" % (cert_name, files)) if not pem: fail("Could not find .x509.pem file for the module '%s' in the list: %s" % (cert_name, files)) return pk8, pem default_cert_directory = "build/make/target/product/security" def _android_app_certificate_with_default_cert_impl(ctx): product_var_cert = ctx.attr._default_app_certificate[BuildSettingInfo].value cert_name = ctx.attr.cert_name if cert_name and product_var_cert: cert_dir = paths.dirname(product_var_cert) elif cert_name: cert_dir = default_cert_directory elif product_var_cert: cert_name = paths.basename(product_var_cert) cert_dir = paths.dirname(product_var_cert) else: cert_name = "testkey" cert_dir = default_cert_directory if cert_dir != default_cert_directory: filegroup_to_search = ctx.attr._default_app_certificate_filegroup else: filegroup_to_search = ctx.attr._hardcoded_certs pk8, pem = _search_cert_files(cert_name, filegroup_to_search) return [ AndroidAppCertificateInfo( pk8 = pk8, pem = pem, key_name = "//" + cert_dir + ":" + cert_name, ), ] android_app_certificate_with_default_cert = rule( doc = """ This rule is the equivalent of an android_app_certificate, but uses the certificate with the given name from a certain folder, or the default certificate. Modules can give a simple name of a certificate instead of a full label to an android_app_certificate. This certificate will be looked for either in the package determined by the DefaultAppCertificate product config variable, or the hardcoded default directory. (build/make/target/product/security) If a name is not given, it will fall back to using the certificate termined by DefaultAppCertificate. (DefaultAppCertificate can function as both the default certificate to use if none is specified, and the folder to look for certificates in) If neither the name nor DefaultAppCertificate is given, build/make/target/product/security/testkey.{pem,pk8} will be used. Since this rule is intended to be used from other macros, it's common to have multiple android_app_certificate targets pointing to the same pem/pk8 files. """, implementation = _android_app_certificate_with_default_cert_impl, attrs = { "cert_name": attr.string(), "_default_app_certificate": attr.label( default = "//build/bazel/product_config:default_app_certificate", ), "_default_app_certificate_filegroup": attr.label( default = "//build/bazel/product_config:default_app_certificate_filegroup", ), "_hardcoded_certs": attr.label( default = "//build/make/target/product/security:android_certificate_directory", ), "_apex_name": attr.label( default = "//build/bazel/rules/apex:apex_name", doc = "Name of apex this certificate signs.", ), }, )