blob: cc66a131f125640eb1ccdbcb27e69b282e89eea9 [file] [log] [blame]
Jiyong Parkff1458f2018-10-12 21:49:38 +09001// 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"
Jiyong Parkff1458f2018-10-12 21:49:38 +090019
20 "android/soong/android"
Spandan Das7701d5f2024-12-17 17:52:26 +000021 "github.com/google/blueprint"
Jiyong Parkff1458f2018-10-12 21:49:38 +090022 "github.com/google/blueprint/proptools"
23)
24
25var String = proptools.String
26
27func init() {
Paul Duffin667893c2021-03-09 22:34:13 +000028 registerApexKeyBuildComponents(android.InitRegistrationContext)
29}
30
31func registerApexKeyBuildComponents(ctx android.RegistrationContext) {
32 ctx.RegisterModuleType("apex_key", ApexKeyFactory)
Spandan Das7701d5f2024-12-17 17:52:26 +000033 ctx.RegisterParallelSingletonModuleType("all_apex_certs", allApexCertsFactory)
Jiyong Parkff1458f2018-10-12 21:49:38 +090034}
35
Yu Liu0a37d422025-02-13 02:05:00 +000036type ApexKeyInfo struct {
37 PublicKeyFile android.Path
38 PrivateKeyFile android.Path
39}
40
41var ApexKeyInfoProvider = blueprint.NewProvider[ApexKeyInfo]()
42
Jiyong Parkff1458f2018-10-12 21:49:38 +090043type apexKey struct {
44 android.ModuleBase
45
46 properties apexKeyProperties
47
Jaewoong Jung18aefc12020-12-21 09:11:10 -080048 publicKeyFile android.Path
49 privateKeyFile android.Path
Jiyong Parkff1458f2018-10-12 21:49:38 +090050}
51
52type apexKeyProperties struct {
Jiyong Park67882562019-03-21 01:11:21 +090053 // Path or module to the public key file in avbpubkey format. Installed to the device.
Jiyong Parkff1458f2018-10-12 21:49:38 +090054 // Base name of the file is used as the ID for the key.
Jiyong Park67882562019-03-21 01:11:21 +090055 Public_key *string `android:"path"`
56 // Path or module to the private key file in pem format. Used to sign APEXs.
57 Private_key *string `android:"path"`
Jiyong Park50d99202018-12-27 13:32:34 +090058
59 // Whether this key is installable to one of the partitions. Defualt: true.
60 Installable *bool
Jiyong Parkff1458f2018-10-12 21:49:38 +090061}
62
Jiyong Parkd1063c12019-07-17 20:08:41 +090063func ApexKeyFactory() android.Module {
Jiyong Parkff1458f2018-10-12 21:49:38 +090064 module := &apexKey{}
65 module.AddProperties(&module.properties)
Jooyung Han8d4a1f02023-08-23 13:54:08 +090066 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
Jiyong Parkff1458f2018-10-12 21:49:38 +090067 return module
68}
69
Jiyong Park50d99202018-12-27 13:32:34 +090070func (m *apexKey) installable() bool {
Jiyong Park42cca6c2019-04-01 11:15:50 +090071 return false
Jiyong Park50d99202018-12-27 13:32:34 +090072}
73
Jiyong Parkff1458f2018-10-12 21:49:38 +090074func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Jiyong Park67882562019-03-21 01:11:21 +090075 // If the keys are from other modules (i.e. :module syntax) respect it.
76 // Otherwise, try to locate the key files in the default cert dir or
77 // in the local module dir
78 if android.SrcIsModule(String(m.properties.Public_key)) != "" {
Jaewoong Jung18aefc12020-12-21 09:11:10 -080079 m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
Jiyong Park67882562019-03-21 01:11:21 +090080 } else {
Jaewoong Jung18aefc12020-12-21 09:11:10 -080081 m.publicKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key))
Jiyong Park67882562019-03-21 01:11:21 +090082 // If not found, fall back to the local key pairs
Jaewoong Jung18aefc12020-12-21 09:11:10 -080083 if !android.ExistentPathForSource(ctx, m.publicKeyFile.String()).Valid() {
84 m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
Jiyong Park67882562019-03-21 01:11:21 +090085 }
Jiyong Park9335a262018-12-24 11:31:58 +090086 }
Jiyong Park67882562019-03-21 01:11:21 +090087
88 if android.SrcIsModule(String(m.properties.Private_key)) != "" {
Jaewoong Jung18aefc12020-12-21 09:11:10 -080089 m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
Jiyong Park67882562019-03-21 01:11:21 +090090 } else {
Jaewoong Jung18aefc12020-12-21 09:11:10 -080091 m.privateKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key))
92 if !android.ExistentPathForSource(ctx, m.privateKeyFile.String()).Valid() {
93 m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
Jiyong Park67882562019-03-21 01:11:21 +090094 }
Jiyong Park9335a262018-12-24 11:31:58 +090095 }
Jiyong Parkff1458f2018-10-12 21:49:38 +090096
Jaewoong Jung18aefc12020-12-21 09:11:10 -080097 pubKeyName := m.publicKeyFile.Base()[0 : len(m.publicKeyFile.Base())-len(m.publicKeyFile.Ext())]
98 privKeyName := m.privateKeyFile.Base()[0 : len(m.privateKeyFile.Base())-len(m.privateKeyFile.Ext())]
Jiyong Parkff1458f2018-10-12 21:49:38 +090099
Jaewoong Jung939ebd52019-03-26 15:07:36 -0700100 if m.properties.Public_key != nil && m.properties.Private_key != nil && pubKeyName != privKeyName {
Jiyong Parkff1458f2018-10-12 21:49:38 +0900101 ctx.ModuleErrorf("public_key %q (keyname:%q) and private_key %q (keyname:%q) do not have same keyname",
Jaewoong Jung18aefc12020-12-21 09:11:10 -0800102 m.publicKeyFile.String(), pubKeyName, m.privateKeyFile, privKeyName)
Jiyong Parkff1458f2018-10-12 21:49:38 +0900103 return
104 }
Yu Liu0a37d422025-02-13 02:05:00 +0000105
106 android.SetProvider(ctx, ApexKeyInfoProvider, ApexKeyInfo{
107 PublicKeyFile: m.publicKeyFile,
108 PrivateKeyFile: m.privateKeyFile,
109 })
Jiyong Parkff1458f2018-10-12 21:49:38 +0900110}
Jiyong Park0ca3ce82019-02-18 15:25:04 +0900111
Jooyung Han2cf35e72023-10-30 11:17:16 +0900112type apexKeyEntry struct {
113 name string
114 presigned bool
115 publicKey string
116 privateKey string
117 containerCertificate string
118 containerPrivateKey string
119 partition string
120 signTool string
121}
122
123func (e apexKeyEntry) String() string {
124 signTool := ""
125 if e.signTool != "" {
126 signTool = fmt.Sprintf(" sign_tool=%q", e.signTool)
127 }
128 format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q%s\n"
129 if e.presigned {
130 return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition, signTool)
131 } else {
132 return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition, signTool)
133 }
134}
135
Jooyung Han286957d2023-10-30 16:17:56 +0900136func apexKeyEntryFor(ctx android.ModuleContext, module android.Module) apexKeyEntry {
Jooyung Han2cf35e72023-10-30 11:17:16 +0900137 switch m := module.(type) {
138 case *apexBundle:
139 pem, key := m.getCertificateAndPrivateKey(ctx)
140 return apexKeyEntry{
141 name: m.Name() + ".apex",
142 presigned: false,
143 publicKey: m.publicKeyFile.String(),
144 privateKey: m.privateKeyFile.String(),
145 containerCertificate: pem.String(),
146 containerPrivateKey: key.String(),
147 partition: m.PartitionTag(ctx.DeviceConfig()),
148 signTool: proptools.String(m.properties.Custom_sign_tool),
149 }
150 case *Prebuilt:
151 return apexKeyEntry{
152 name: m.InstallFilename(),
153 presigned: true,
154 partition: m.PartitionTag(ctx.DeviceConfig()),
155 }
156 case *ApexSet:
157 return apexKeyEntry{
158 name: m.InstallFilename(),
159 presigned: true,
160 partition: m.PartitionTag(ctx.DeviceConfig()),
161 }
162 }
163 panic(fmt.Errorf("unknown type(%t) for apexKeyEntry", module))
164}
165
Jooyung Han286957d2023-10-30 16:17:56 +0900166func writeApexKeys(ctx android.ModuleContext, module android.Module) android.WritablePath {
167 path := android.PathForModuleOut(ctx, "apexkeys.txt")
168 entry := apexKeyEntryFor(ctx, module)
169 android.WriteFileRuleVerbatim(ctx, path, entry.String())
170 return path
Jiyong Park0ca3ce82019-02-18 15:25:04 +0900171}
Spandan Das7701d5f2024-12-17 17:52:26 +0000172
173var (
174 pemToDer = pctx.AndroidStaticRule("pem_to_der",
175 blueprint.RuleParams{
176 Command: `openssl x509 -inform PEM -outform DER -in $in -out $out`,
177 Description: "Convert certificate from PEM to DER format",
178 },
179 )
180)
181
182// all_apex_certs is a singleton module that collects the certs of all apexes in the tree.
183// It provides two types of output files
184// 1. .pem: This is usually the checked-in x509 certificate in PEM format
185// 2. .der: This is DER format of the certificate, and is generated from the PEM certificate using `openssl x509`
186func allApexCertsFactory() android.SingletonModule {
187 m := &allApexCerts{}
188 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
189 return m
190}
191
192type allApexCerts struct {
193 android.SingletonModuleBase
194}
195
196func (_ *allApexCerts) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Spandan Dasef1a1fd2025-01-03 19:43:38 +0000197 var avbpubkeys android.Paths
Spandan Das7701d5f2024-12-17 17:52:26 +0000198 var certificatesPem android.Paths
199 ctx.VisitDirectDeps(func(m android.Module) {
200 if apex, ok := m.(*apexBundle); ok {
201 pem, _ := apex.getCertificateAndPrivateKey(ctx)
202 if !android.ExistentPathForSource(ctx, pem.String()).Valid() {
203 if ctx.Config().AllowMissingDependencies() {
204 return
205 } else {
206 ctx.ModuleErrorf("Path %s is not valid\n", pem.String())
207 }
208 }
209 certificatesPem = append(certificatesPem, pem)
Spandan Dasef1a1fd2025-01-03 19:43:38 +0000210 // avbpubkey for signing the apex payload
211 avbpubkeys = append(avbpubkeys, apex.publicKeyFile)
Spandan Das7701d5f2024-12-17 17:52:26 +0000212 }
213 })
214 certificatesPem = android.SortedUniquePaths(certificatesPem) // For hermiticity
Spandan Dasef1a1fd2025-01-03 19:43:38 +0000215 avbpubkeys = android.SortedUniquePaths(avbpubkeys) // For hermiticity
Spandan Das7701d5f2024-12-17 17:52:26 +0000216 var certificatesDer android.Paths
217 for index, certificatePem := range certificatesPem {
218 certificateDer := android.PathForModuleOut(ctx, fmt.Sprintf("x509.%v.der", index))
219 ctx.Build(pctx, android.BuildParams{
220 Rule: pemToDer,
221 Input: certificatePem,
222 Output: certificateDer,
223 })
224 certificatesDer = append(certificatesDer, certificateDer)
225 }
226 ctx.SetOutputFiles(certificatesPem, ".pem")
227 ctx.SetOutputFiles(certificatesDer, ".der")
Spandan Dasef1a1fd2025-01-03 19:43:38 +0000228 ctx.SetOutputFiles(avbpubkeys, ".avbpubkey")
Spandan Das7701d5f2024-12-17 17:52:26 +0000229}
230
231func (_ *allApexCerts) GenerateSingletonBuildActions(ctx android.SingletonContext) {
232}