xref: /aosp_15_r20/build/bazel/rules/android/android_app_certificate.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
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