Skip to content

Commit 972b1a1

Browse files
committed
add flags to allow the override of the keys used to sign and encrypt a binary for the boards that support the secure boot
1 parent 6303ba3 commit 972b1a1

File tree

8 files changed

+292
-53
lines changed

8 files changed

+292
-53
lines changed

cli/arguments/arguments.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,15 @@ func CheckFlagsConflicts(command *cobra.Command, flagNames ...string) {
3737
feedback.Errorf(tr("Can't use %s flags at the same time.", "--"+strings.Join(flagNames, " "+tr("and")+" --")))
3838
os.Exit(errorcodes.ErrBadArgument)
3939
}
40+
41+
// CheckFlagsMandatory is a helper function useful to report errors when at least one flag is not used in a group of "required" flags
42+
func CheckFlagsMandatory(command *cobra.Command, flagNames ...string) {
43+
for _, flagName := range flagNames {
44+
if command.Flag(flagName).Changed {
45+
continue
46+
} else {
47+
feedback.Errorf(tr("Please use also %s flag when using %s flags at the same time.", "--"+flagName, "--"+strings.Join(flagNames, " "+tr("and")+" --")))
48+
os.Exit(errorcodes.ErrBadArgument)
49+
}
50+
}
51+
}

cli/compile/compile.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ var (
5353
buildCachePath string // Builds of 'core.a' are saved into this path to be cached and reused.
5454
buildPath string // Path where to save compiled files.
5555
buildProperties []string // List of custom build properties separated by commas. Or can be used multiple times for multiple properties.
56+
keysDir string // The path of the dir where to search for the custom keys to sign and encrypt a binary. Used only by the platforms that supports it
57+
signKeyName string // The name of the custom signing key to use to sign a binary during the compile process. Used only by the platforms that supports it
58+
encryptKeyName string // The name of the custom encryption key to use to encrypt a binary during the compile process. Used only by the platforms that supports it
5659
warnings string // Used to tell gcc which warning level to use.
5760
verbose bool // Turns on verbose mode.
5861
quiet bool // Suppresses almost every output.
@@ -84,7 +87,8 @@ func NewCommand() *cobra.Command {
8487
" " + os.Args[0] + " compile -b arduino:avr:uno /home/user/Arduino/MySketch\n" +
8588
" " + os.Args[0] + ` compile -b arduino:avr:uno --build-property "build.extra_flags=\"-DMY_DEFINE=\"hello world\"\"" /home/user/Arduino/MySketch` + "\n" +
8689
" " + os.Args[0] + ` compile -b arduino:avr:uno --build-property "build.extra_flags=-DPIN=2 \"-DMY_DEFINE=\"hello world\"\"" /home/user/Arduino/MySketch` + "\n" +
87-
" " + os.Args[0] + ` compile -b arduino:avr:uno --build-property build.extra_flags=-DPIN=2 --build-property "compiler.cpp.extra_flags=\"-DSSID=\"hello world\"\"" /home/user/Arduino/MySketch` + "\n",
90+
" " + os.Args[0] + ` compile -b arduino:avr:uno --build-property build.extra_flags=-DPIN=2 --build-property "compiler.cpp.extra_flags=\"-DSSID=\"hello world\"\"" /home/user/Arduino/MySketch` + "\n" +
91+
" " + os.Args[0] + ` compile -b arduino:mbed_portenta:envie_m7:security=sien --keys-input-dir /home/user/Arduino/keys --sign-key-name ecsdsa-p256-signing-key.pem --encrypt-key-name ecsdsa-p256-encrypt-key.pem /home/user/Arduino/MySketch` + "\n",
8892
Args: cobra.MaximumNArgs(1),
8993
Run: runCompileCommand,
9094
}
@@ -100,6 +104,12 @@ func NewCommand() *cobra.Command {
100104
tr("List of custom build properties separated by commas. Or can be used multiple times for multiple properties."))
101105
compileCommand.Flags().StringArrayVar(&buildProperties, "build-property", []string{},
102106
tr("Override a build property with a custom value. Can be used multiple times for multiple properties."))
107+
compileCommand.Flags().StringVar(&keysDir, "keys-input-dir", "",
108+
tr("The path of the dir where to search for the custom keys to sign and encrypt a binary. Used only by the platforms that supports it"))
109+
compileCommand.Flags().StringVar(&signKeyName, "sign-key-name", "",
110+
tr("The name of the custom signing key to use to sign a binary during the compile process. Used only by the platforms that supports it"))
111+
compileCommand.Flags().StringVar(&encryptKeyName, "encrypt-key-name", "",
112+
tr("The name of the custom encryption key to use to encrypt a binary during the compile process. Used only by the platforms that supports it"))
103113
compileCommand.Flags().StringVar(&warnings, "warnings", "none",
104114
tr(`Optional, can be: %s. Used to tell gcc which warning level to use (-W flag).`, "none, default, more, all"))
105115
compileCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, tr("Optional, turns on verbose mode."))
@@ -142,6 +152,10 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
142152

143153
sketchPath := arguments.InitSketchPath(path)
144154

155+
if keysDir != "" || signKeyName != "" || encryptKeyName != "" {
156+
arguments.CheckFlagsMandatory(cmd, "keys-input-dir", "sign-key-name", "encrypt-key-name")
157+
}
158+
145159
var overrides map[string]string
146160
if sourceOverrides != "" {
147161
data, err := paths.New(sourceOverrides).ReadFile()
@@ -198,6 +212,9 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
198212
CreateCompilationDatabaseOnly: compilationDatabaseOnly,
199213
SourceOverride: overrides,
200214
Library: library,
215+
Keysdir: keysDir,
216+
Signkeyname: signKeyName,
217+
Encryptkeyname: encryptKeyName,
201218
}
202219
compileStdOut := new(bytes.Buffer)
203220
compileStdErr := new(bytes.Buffer)

commands/compile/compile.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,34 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream
118118
Package: fqbn.Package,
119119
PlatformArchitecture: fqbn.PlatformArch,
120120
})
121-
if targetPlatform == nil || pm.GetInstalledPlatformRelease(targetPlatform) == nil {
121+
InstalledPlatformRelease := pm.GetInstalledPlatformRelease(targetPlatform)
122+
if targetPlatform == nil || InstalledPlatformRelease == nil {
122123
return nil, &arduino.PlatformNotFoundError{
123124
Platform: fmt.Sprintf("%s:%s", fqbn.Package, fqbn.PlatformArch),
124125
Cause: fmt.Errorf(tr("platform not installed")),
125126
}
126127
}
127128

129+
// At the current time we do not have a way of knowing if a board supports the secure boot or not,
130+
// so, if the flags to override the default keys are used, we try override the corresponding property in the properties.txt nonetheless.
131+
// It's not possible to use the default name for the keys since there could be more tools to sign and encrypt.
132+
// So it's mandatory to use all the tree flags to sign and encrypt the binary
133+
if req.Keysdir != "" && req.Signkeyname != "" && req.Encryptkeyname != "" {
134+
keysDirPath := paths.New(req.Keysdir)
135+
if !keysDirPath.IsDir() {
136+
return nil, &arduino.NotFoundError{Message: tr("The path specified is not a directory: %s", keysDirPath), Cause: err}
137+
}
138+
signKeyPath := keysDirPath.Join(req.GetSignkeyname())
139+
if !signKeyPath.Exist() {
140+
return nil, &arduino.NotFoundError{Message: tr("The path of the specified signing key do not exist: %s", signKeyPath), Cause: err}
141+
}
142+
encryptKeyPath := keysDirPath.Join(req.GetEncryptkeyname())
143+
if !encryptKeyPath.Exist() {
144+
return nil, &arduino.NotFoundError{Message: tr("The path of the specified encription key do not exist: %s", encryptKeyPath), Cause: err}
145+
}
146+
ReplaceSecurityKeys(InstalledPlatformRelease.Properties, req.Keysdir, req.Signkeyname, req.Encryptkeyname)
147+
}
148+
128149
builderCtx := &types.Context{}
129150
builderCtx.PackageManager = pm
130151
builderCtx.FQBN = fqbn
@@ -296,3 +317,29 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream
296317

297318
return r, nil
298319
}
320+
321+
// ReplaceSecurityKeys function will override the properties representing the security keys specified in the platform.txt file of a platform with the ones provided by the user.
322+
// The keys are stored in the keyDir
323+
// signKeyName is the key used to sign a binary
324+
// encryptKeyName is the key used to encrypt it
325+
func ReplaceSecurityKeys(properties *properties.Map, keysDir, signKeyName, encryptKeyName string) {
326+
toolsProps := properties.SubTree("tools").FirstLevelOf()
327+
for toolName, toolProps := range toolsProps {
328+
// switch o else o select
329+
if toolProps.ContainsKey("keys.path") {
330+
key := "tools." + toolName + ".keys.path"
331+
properties.Set(key, keysDir)
332+
logrus.Tracef("Overriding Property: %s: %s", key, keysDir)
333+
}
334+
if toolProps.ContainsKey("sign.name") {
335+
key := "tools." + toolName + ".sign.name"
336+
properties.Set(key, signKeyName)
337+
logrus.Tracef("Overriding Property: %s: %s", key, signKeyName)
338+
}
339+
if toolProps.ContainsKey("encrypt.name") {
340+
key := "tools." + toolName + ".encrypt.name"
341+
properties.Set(key, encryptKeyName)
342+
logrus.Tracef("Overriding Property: %s: %s", key, encryptKeyName)
343+
}
344+
}
345+
}

0 commit comments

Comments
 (0)