xref: /aosp_15_r20/build/soong/apex/key.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright (C) 2018 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
15package apex
16
17import (
18	"fmt"
19
20	"android/soong/android"
21	"github.com/google/blueprint/proptools"
22)
23
24var String = proptools.String
25
26func init() {
27	registerApexKeyBuildComponents(android.InitRegistrationContext)
28}
29
30func registerApexKeyBuildComponents(ctx android.RegistrationContext) {
31	ctx.RegisterModuleType("apex_key", ApexKeyFactory)
32}
33
34type apexKey struct {
35	android.ModuleBase
36
37	properties apexKeyProperties
38
39	publicKeyFile  android.Path
40	privateKeyFile android.Path
41}
42
43type apexKeyProperties struct {
44	// Path or module to the public key file in avbpubkey format. Installed to the device.
45	// Base name of the file is used as the ID for the key.
46	Public_key *string `android:"path"`
47	// Path or module to the private key file in pem format. Used to sign APEXs.
48	Private_key *string `android:"path"`
49
50	// Whether this key is installable to one of the partitions. Defualt: true.
51	Installable *bool
52}
53
54func ApexKeyFactory() android.Module {
55	module := &apexKey{}
56	module.AddProperties(&module.properties)
57	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
58	return module
59}
60
61func (m *apexKey) installable() bool {
62	return false
63}
64
65func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) {
66	// If the keys are from other modules (i.e. :module syntax) respect it.
67	// Otherwise, try to locate the key files in the default cert dir or
68	// in the local module dir
69	if android.SrcIsModule(String(m.properties.Public_key)) != "" {
70		m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
71	} else {
72		m.publicKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key))
73		// If not found, fall back to the local key pairs
74		if !android.ExistentPathForSource(ctx, m.publicKeyFile.String()).Valid() {
75			m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
76		}
77	}
78
79	if android.SrcIsModule(String(m.properties.Private_key)) != "" {
80		m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
81	} else {
82		m.privateKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key))
83		if !android.ExistentPathForSource(ctx, m.privateKeyFile.String()).Valid() {
84			m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
85		}
86	}
87
88	pubKeyName := m.publicKeyFile.Base()[0 : len(m.publicKeyFile.Base())-len(m.publicKeyFile.Ext())]
89	privKeyName := m.privateKeyFile.Base()[0 : len(m.privateKeyFile.Base())-len(m.privateKeyFile.Ext())]
90
91	if m.properties.Public_key != nil && m.properties.Private_key != nil && pubKeyName != privKeyName {
92		ctx.ModuleErrorf("public_key %q (keyname:%q) and private_key %q (keyname:%q) do not have same keyname",
93			m.publicKeyFile.String(), pubKeyName, m.privateKeyFile, privKeyName)
94		return
95	}
96}
97
98type apexKeyEntry struct {
99	name                 string
100	presigned            bool
101	publicKey            string
102	privateKey           string
103	containerCertificate string
104	containerPrivateKey  string
105	partition            string
106	signTool             string
107}
108
109func (e apexKeyEntry) String() string {
110	signTool := ""
111	if e.signTool != "" {
112		signTool = fmt.Sprintf(" sign_tool=%q", e.signTool)
113	}
114	format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q%s\n"
115	if e.presigned {
116		return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition, signTool)
117	} else {
118		return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition, signTool)
119	}
120}
121
122func apexKeyEntryFor(ctx android.ModuleContext, module android.Module) apexKeyEntry {
123	switch m := module.(type) {
124	case *apexBundle:
125		pem, key := m.getCertificateAndPrivateKey(ctx)
126		return apexKeyEntry{
127			name:                 m.Name() + ".apex",
128			presigned:            false,
129			publicKey:            m.publicKeyFile.String(),
130			privateKey:           m.privateKeyFile.String(),
131			containerCertificate: pem.String(),
132			containerPrivateKey:  key.String(),
133			partition:            m.PartitionTag(ctx.DeviceConfig()),
134			signTool:             proptools.String(m.properties.Custom_sign_tool),
135		}
136	case *Prebuilt:
137		return apexKeyEntry{
138			name:      m.InstallFilename(),
139			presigned: true,
140			partition: m.PartitionTag(ctx.DeviceConfig()),
141		}
142	case *ApexSet:
143		return apexKeyEntry{
144			name:      m.InstallFilename(),
145			presigned: true,
146			partition: m.PartitionTag(ctx.DeviceConfig()),
147		}
148	}
149	panic(fmt.Errorf("unknown type(%t) for apexKeyEntry", module))
150}
151
152func writeApexKeys(ctx android.ModuleContext, module android.Module) android.WritablePath {
153	path := android.PathForModuleOut(ctx, "apexkeys.txt")
154	entry := apexKeyEntryFor(ctx, module)
155	android.WriteFileRuleVerbatim(ctx, path, entry.String())
156	return path
157}
158