# Copyright (C) 2022 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("android_app_certificate.bzl", "AndroidAppCertificateInfo") AndroidAppKeystoreInfo = provider( "Info needed for Android app keystores", fields = { "keystore": "JKS .keystore file housing certificate info", }, ) def _pk8_to_private_pem(ctx, openssl, pk8_file, private_pem_file): """Converts a .pk8 private key file in DER format to a .pem private key file in PEM format.""" args = ctx.actions.args() args.add("pkcs8") args.add_all(["-in", pk8_file]) args.add_all(["-inform", "DER"]) args.add_all(["-outform", "PEM"]) args.add_all(["-out", private_pem_file]) args.add("-nocrypt") # don't bother encrypting this private key since it is just an intermediate file ctx.actions.run( inputs = [pk8_file], executable = openssl, outputs = [private_pem_file], arguments = [args], mnemonic = "CreatePrivPEM", ) def _pem_to_pk12(ctx, openssl, certificate_pem, private_key_pem, pk12_file): """Converts an X.509 certificate and private key pair of PEM files to a single PKCS12 keystore file.""" args = ctx.actions.args() args.add("pkcs12") args.add("-export") args.add_all(["-in", certificate_pem]) args.add_all(["-inkey", private_key_pem]) args.add_all(["-out", pk12_file]) args.add_all(["-name", "android"]) # openssl requires a password and will request a # password from STDIN if we don't supply one here args.add_all(["-passout", "pass:android"]) ctx.actions.run( inputs = [ certificate_pem, private_key_pem, ], executable = openssl, outputs = [pk12_file], arguments = [args], mnemonic = "CreatePK12", ) def _pk12_to_keystore(ctx, pk12_file, keystore_file): """Converts a PKCS12 keystore file to a JKS keystore file.""" java_runtime = ctx.attr._java_runtime[java_common.JavaRuntimeInfo] keytool = paths.join(java_runtime.java_home, "bin", "keytool") args = ctx.actions.args() args.add("-importkeystore") args.add_all(["-destkeystore", keystore_file]) args.add_all(["-srckeystore", pk12_file]) args.add_all(["-srcstoretype", "PKCS12"]) args.add_all(["-srcstorepass", "android"]) # apksigner expects keystores provided by the debug_signing_keys attribute # to be secured with the password "android" args.add_all(["-deststorepass", "android"]) ctx.actions.run( inputs = [pk12_file], executable = keytool, tools = [java_runtime.files], outputs = [keystore_file], arguments = [args], mnemonic = "CreateKeystore", ) def _android_app_keystore_rule_impl(ctx): openssl = ctx.executable._openssl private_pem = ctx.actions.declare_file(ctx.attr.name + ".priv.pem") pk12 = ctx.actions.declare_file(ctx.attr.name + ".pk12") keystore = ctx.actions.declare_file(ctx.attr.name + ".keystore") pk8_file = ctx.attr.certificate[AndroidAppCertificateInfo].pk8 pem_file = ctx.attr.certificate[AndroidAppCertificateInfo].pem _pk8_to_private_pem(ctx, openssl, pk8_file, private_pem) _pem_to_pk12(ctx, openssl, pem_file, private_pem, pk12) _pk12_to_keystore(ctx, pk12, keystore) return [ AndroidAppKeystoreInfo( keystore = keystore, ), DefaultInfo(files = depset(direct = [keystore])), ] """Converts an android_app_certificate (i.e. pem/pk8 pair) into a JKS keystore""" android_app_keystore = rule( implementation = _android_app_keystore_rule_impl, attrs = { "certificate": attr.label(mandatory = True, providers = [AndroidAppCertificateInfo]), "_openssl": attr.label( default = Label("//prebuilts/build-tools:linux-x86/bin/openssl"), allow_single_file = True, executable = True, cfg = "exec", doc = "An OpenSSL compatible tool.", ), "_java_runtime": attr.label( default = Label("@bazel_tools//tools/jdk:current_java_runtime"), cfg = "exec", providers = [java_common.JavaRuntimeInfo], ), }, provides = [AndroidAppKeystoreInfo], )