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