1# Copyright (C) 2021 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15load("@bazel_skylib//lib:paths.bzl", "paths") 16load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 17 18AndroidAppCertificateInfo = provider( 19 "Info needed for Android app certificates", 20 fields = { 21 "pem": "Certificate .pem file", 22 "pk8": "Certificate .pk8 file", 23 "key_name": "Key name", 24 }, 25) 26 27NoAndroidAppCertificateInfo = provider( 28 "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.", 29) 30 31def _no_android_app_certificate_rule_impl(_ctx): 32 return [NoAndroidAppCertificateInfo()] 33 34no_android_app_certificate = rule( 35 implementation = _no_android_app_certificate_rule_impl, 36) 37 38def _android_app_certificate_rule_impl(ctx): 39 cert_name = ctx.attr.certificate 40 pk8 = ctx.file.pk8 41 pem = ctx.file.pem 42 43 return [ 44 AndroidAppCertificateInfo(pem = pem, pk8 = pk8, key_name = cert_name), 45 ] 46 47_android_app_certificate = rule( 48 implementation = _android_app_certificate_rule_impl, 49 attrs = { 50 "pem": attr.label(mandatory = True, allow_single_file = [".pem"]), 51 "pk8": attr.label(mandatory = True, allow_single_file = [".pk8"]), 52 "certificate": attr.string(mandatory = True), 53 }, 54) 55 56def android_app_certificate( 57 name, 58 certificate, 59 **kwargs): 60 "Bazel macro to correspond with the Android app certificate Soong module." 61 62 _android_app_certificate( 63 name = name, 64 pem = certificate + ".x509.pem", 65 pk8 = certificate + ".pk8", 66 certificate = certificate, 67 **kwargs 68 ) 69 70def _search_cert_files(cert_name, cert_filegroup): 71 pk8 = None 72 pem = None 73 files = cert_filegroup[DefaultInfo].files.to_list() 74 75 # For overriding to a specific *file* in a provided directory with cert_name in the actual filename 76 for f in files: 77 if f.basename == cert_name + ".pk8": 78 pk8 = f 79 elif f.basename == cert_name + ".x509.pem": 80 pem = f 81 82 if not pk8: 83 fail("Could not find .pk8 file for the module '%s' in the list: %s" % (cert_name, files)) 84 if not pem: 85 fail("Could not find .x509.pem file for the module '%s' in the list: %s" % (cert_name, files)) 86 87 return pk8, pem 88 89default_cert_directory = "build/make/target/product/security" 90 91def _android_app_certificate_with_default_cert_impl(ctx): 92 product_var_cert = ctx.attr._default_app_certificate[BuildSettingInfo].value 93 94 cert_name = ctx.attr.cert_name 95 96 if cert_name and product_var_cert: 97 cert_dir = paths.dirname(product_var_cert) 98 elif cert_name: 99 cert_dir = default_cert_directory 100 elif product_var_cert: 101 cert_name = paths.basename(product_var_cert) 102 cert_dir = paths.dirname(product_var_cert) 103 else: 104 cert_name = "testkey" 105 cert_dir = default_cert_directory 106 107 if cert_dir != default_cert_directory: 108 filegroup_to_search = ctx.attr._default_app_certificate_filegroup 109 else: 110 filegroup_to_search = ctx.attr._hardcoded_certs 111 112 pk8, pem = _search_cert_files(cert_name, filegroup_to_search) 113 114 return [ 115 AndroidAppCertificateInfo( 116 pk8 = pk8, 117 pem = pem, 118 key_name = "//" + cert_dir + ":" + cert_name, 119 ), 120 ] 121 122android_app_certificate_with_default_cert = rule( 123 doc = """ 124 This rule is the equivalent of an android_app_certificate, but uses the 125 certificate with the given name from a certain folder, or the default 126 certificate. 127 128 Modules can give a simple name of a certificate instead of a full label to 129 an android_app_certificate. This certificate will be looked for either in 130 the package determined by the DefaultAppCertificate product config variable, 131 or the hardcoded default directory. (build/make/target/product/security) 132 133 If a name is not given, it will fall back to using the certificate termined 134 by DefaultAppCertificate. (DefaultAppCertificate can function as both the 135 default certificate to use if none is specified, and the folder to look for 136 certificates in) 137 138 If neither the name nor DefaultAppCertificate is given, 139 build/make/target/product/security/testkey.{pem,pk8} will be used. 140 141 Since this rule is intended to be used from other macros, it's common to have 142 multiple android_app_certificate targets pointing to the same pem/pk8 files. 143 """, 144 implementation = _android_app_certificate_with_default_cert_impl, 145 attrs = { 146 "cert_name": attr.string(), 147 "_default_app_certificate": attr.label( 148 default = "//build/bazel/product_config:default_app_certificate", 149 ), 150 "_default_app_certificate_filegroup": attr.label( 151 default = "//build/bazel/product_config:default_app_certificate_filegroup", 152 ), 153 "_hardcoded_certs": attr.label( 154 default = "//build/make/target/product/security:android_certificate_directory", 155 ), 156 "_apex_name": attr.label( 157 default = "//build/bazel/rules/apex:apex_name", 158 doc = "Name of apex this certificate signs.", 159 ), 160 }, 161) 162