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" 22 "github.com/google/blueprint/proptools" 23) 24 25var String = proptools.String 26 27func init() { 28 registerApexKeyBuildComponents(android.InitRegistrationContext) 29} 30 31func registerApexKeyBuildComponents(ctx android.RegistrationContext) { 32 ctx.RegisterModuleType("apex_key", ApexKeyFactory) 33 ctx.RegisterParallelSingletonModuleType("all_apex_certs", allApexCertsFactory) 34} 35 36type ApexKeyInfo struct { 37 PublicKeyFile android.Path 38 PrivateKeyFile android.Path 39} 40 41var ApexKeyInfoProvider = blueprint.NewProvider[ApexKeyInfo]() 42 43type apexKey struct { 44 android.ModuleBase 45 46 properties apexKeyProperties 47 48 publicKeyFile android.Path 49 privateKeyFile android.Path 50} 51 52type apexKeyProperties struct { 53 // Path or module to the public key file in avbpubkey format. Installed to the device. 54 // Base name of the file is used as the ID for the key. 55 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"` 58 59 // Whether this key is installable to one of the partitions. Defualt: true. 60 Installable *bool 61} 62 63func ApexKeyFactory() android.Module { 64 module := &apexKey{} 65 module.AddProperties(&module.properties) 66 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) 67 return module 68} 69 70func (m *apexKey) installable() bool { 71 return false 72} 73 74func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) { 75 // 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)) != "" { 79 m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key)) 80 } else { 81 m.publicKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key)) 82 // If not found, fall back to the local key pairs 83 if !android.ExistentPathForSource(ctx, m.publicKeyFile.String()).Valid() { 84 m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key)) 85 } 86 } 87 88 if android.SrcIsModule(String(m.properties.Private_key)) != "" { 89 m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key)) 90 } else { 91 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)) 94 } 95 } 96 97 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())] 99 100 if m.properties.Public_key != nil && m.properties.Private_key != nil && pubKeyName != privKeyName { 101 ctx.ModuleErrorf("public_key %q (keyname:%q) and private_key %q (keyname:%q) do not have same keyname", 102 m.publicKeyFile.String(), pubKeyName, m.privateKeyFile, privKeyName) 103 return 104 } 105 106 android.SetProvider(ctx, ApexKeyInfoProvider, ApexKeyInfo{ 107 PublicKeyFile: m.publicKeyFile, 108 PrivateKeyFile: m.privateKeyFile, 109 }) 110} 111 112type 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 136func apexKeyEntryFor(ctx android.ModuleContext, module android.Module) apexKeyEntry { 137 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 166func 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 171} 172 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) { 197 var avbpubkeys android.Paths 198 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) 210 // avbpubkey for signing the apex payload 211 avbpubkeys = append(avbpubkeys, apex.publicKeyFile) 212 } 213 }) 214 certificatesPem = android.SortedUniquePaths(certificatesPem) // For hermiticity 215 avbpubkeys = android.SortedUniquePaths(avbpubkeys) // For hermiticity 216 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") 228 ctx.SetOutputFiles(avbpubkeys, ".avbpubkey") 229} 230 231func (_ *allApexCerts) GenerateSingletonBuildActions(ctx android.SingletonContext) { 232} 233