Skip to content

Commit ff52859

Browse files
author
Alexey Semenyuk
committed
8285624: jpackage fails to create exe, msi when Windows OS is in FIPS mode
Reviewed-by: almatvee
1 parent 3741c98 commit ff52859

File tree

3 files changed

+97
-48
lines changed

3 files changed

+97
-48
lines changed

src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -258,6 +258,10 @@ private Path compileWix3(WixSource wixSource) throws IOException {
258258
"-out", wixObj.toString()
259259
));
260260

261+
if (toolset.needFipsParameter()) {
262+
cmdline.add("-fips");
263+
}
264+
261265
addWixVariblesToCommandLine(wixSource.variables, cmdline);
262266

263267
execute(cmdline);

src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java

Lines changed: 82 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -56,36 +56,56 @@ public enum WixTool {
5656
this.minimalVersion = minimalVersion;
5757
}
5858

59-
static final class ToolInfo {
59+
interface ToolInfo {
60+
Path path();
61+
DottedVersion version();
62+
}
63+
64+
interface CandleInfo extends ToolInfo {
65+
boolean fips();
66+
}
6067

61-
ToolInfo(Path path, String version) {
62-
this.path = path;
63-
this.version = DottedVersion.lazy(version);
68+
private record DefaultToolInfo(Path path, DottedVersion version) implements ToolInfo {
69+
DefaultToolInfo {
70+
Objects.requireNonNull(path);
71+
Objects.requireNonNull(version);
6472
}
6573

66-
final Path path;
67-
final DottedVersion version;
74+
DefaultToolInfo(Path path, String version) {
75+
this(path, DottedVersion.lazy(version));
76+
}
77+
}
78+
79+
private record DefaultCandleInfo(Path path, DottedVersion version, boolean fips) implements CandleInfo {
80+
DefaultCandleInfo {
81+
Objects.requireNonNull(path);
82+
Objects.requireNonNull(version);
83+
}
84+
85+
DefaultCandleInfo(ToolInfo info, boolean fips) {
86+
this(info.path(), info.version(), fips);
87+
}
6888
}
6989

7090
static WixToolset createToolset() throws ConfigException {
7191
Function<List<ToolLookupResult>, Map<WixTool, ToolInfo>> conv = lookupResults -> {
7292
return lookupResults.stream().filter(ToolLookupResult::isValid).collect(Collectors.
7393
groupingBy(lookupResult -> {
74-
return lookupResult.getInfo().version.toString();
94+
return lookupResult.info().version().toString();
7595
})).values().stream().filter(sameVersionLookupResults -> {
7696
Set<WixTool> sameVersionTools = sameVersionLookupResults.stream().map(
77-
ToolLookupResult::getTool).collect(Collectors.toSet());
97+
ToolLookupResult::tool).collect(Collectors.toSet());
7898
if (sameVersionTools.equals(Set.of(Candle3)) || sameVersionTools.equals(Set.of(
7999
Light3))) {
80100
// There is only one tool from WiX v3 toolset of some version available. Discard it.
81101
return false;
82102
} else {
83103
return true;
84104
}
85-
}).flatMap(List::stream).collect(Collectors.toMap(ToolLookupResult::getTool,
86-
ToolLookupResult::getInfo, (ToolInfo x, ToolInfo y) -> {
105+
}).flatMap(List::stream).collect(Collectors.toMap(ToolLookupResult::tool,
106+
ToolLookupResult::info, (ToolInfo x, ToolInfo y) -> {
87107
return Stream.of(x, y).sorted(Comparator.comparing((ToolInfo toolInfo) -> {
88-
return toolInfo.version.toComponentsString();
108+
return toolInfo.version().toComponentsString();
89109
}).reversed()).findFirst().get();
90110
}));
91111
};
@@ -99,8 +119,8 @@ static WixToolset createToolset() throws ConfigException {
99119
};
100120

101121
var toolsInPath = Stream.of(values()).map(tool -> {
102-
return new ToolLookupResult(tool, null);
103-
}).toList();
122+
return ToolLookupResult.lookup(tool, Optional.empty());
123+
}).filter(Optional::isPresent).map(Optional::get).toList();
104124

105125
// Try to build a toolset from tools in the PATH first.
106126
var toolset = createToolset.apply(toolsInPath);
@@ -111,9 +131,9 @@ static WixToolset createToolset() throws ConfigException {
111131
// Look up for WiX tools in known locations.
112132
var toolsInKnownWiXDirs = findWixInstallDirs().stream().map(dir -> {
113133
return Stream.of(values()).map(tool -> {
114-
return new ToolLookupResult(tool, dir);
134+
return ToolLookupResult.lookup(tool, Optional.of(dir));
115135
});
116-
}).flatMap(Function.identity()).toList();
136+
}).flatMap(Function.identity()).filter(Optional::isPresent).map(Optional::get).toList();
117137

118138
// Build a toolset found in the PATH and in known locations.
119139
var allFoundTools = Stream.of(toolsInPath, toolsInKnownWiXDirs).flatMap(List::stream).filter(
@@ -128,8 +148,8 @@ static WixToolset createToolset() throws ConfigException {
128148
var toolOldVerErr = allFoundTools.stream().map(lookupResult -> {
129149
if (lookupResult.versionTooOld) {
130150
return new ConfigException(MessageFormat.format(I18N.getString(
131-
"message.wrong-tool-version"), lookupResult.getInfo().path,
132-
lookupResult.getInfo().version, lookupResult.getTool().minimalVersion),
151+
"message.wrong-tool-version"), lookupResult.info().path(),
152+
lookupResult.info().version(), lookupResult.tool().minimalVersion),
133153
I18N.getString("error.no-wix-tools.advice"));
134154
} else {
135155
return null;
@@ -144,11 +164,18 @@ static WixToolset createToolset() throws ConfigException {
144164
}
145165
}
146166

147-
private static class ToolLookupResult {
167+
private record ToolLookupResult(WixTool tool, ToolInfo info, boolean versionTooOld) {
168+
169+
ToolLookupResult {
170+
Objects.requireNonNull(tool);
171+
Objects.requireNonNull(info);
172+
}
148173

149-
ToolLookupResult(WixTool tool, Path lookupDir) {
174+
static Optional<ToolLookupResult> lookup(WixTool tool, Optional<Path> lookupDir) {
175+
Objects.requireNonNull(tool);
176+
Objects.requireNonNull(lookupDir);
150177

151-
final Path toolPath = Optional.ofNullable(lookupDir).map(p -> p.resolve(
178+
final Path toolPath = lookupDir.map(p -> p.resolve(
152179
tool.toolFileName)).orElse(tool.toolFileName);
153180

154181
final boolean[] tooOld = new boolean[1];
@@ -165,7 +192,19 @@ private static class ToolLookupResult {
165192
final Function<Stream<String>, String> versionParser;
166193

167194
if (Set.of(Candle3, Light3).contains(tool)) {
168-
validator.setCommandLine("/?");
195+
final String printVersionArg;
196+
if (tool == Candle3) {
197+
// Add '-fips' to make "candle.exe" print help message and return
198+
// 0 exit code instead of returning error exit code and printing
199+
// "error CNDL0308 : The Federal Information Processing Standard (FIPS) appears to be enabled on the machine..."
200+
// error message if FIPS is enabled.
201+
// If FIPS is disabled, passing '-fips' parameter still makes
202+
// "candle.exe" print help message and return 0 exit code.
203+
printVersionArg = "-fips";
204+
} else {
205+
printVersionArg = "-?";
206+
}
207+
validator.setCommandLine(printVersionArg);
169208
versionParser = output -> {
170209
String firstLineOfOutput = output.findFirst().orElse("");
171210
int separatorIdx = firstLineOfOutput.lastIndexOf(' ');
@@ -186,36 +225,35 @@ private static class ToolLookupResult {
186225
return parsedVersion[0];
187226
});
188227

189-
this.tool = tool;
190228
if (validator.validate() == null) {
191229
// Tool found
192-
this.versionTooOld = tooOld[0];
193-
this.info = new ToolInfo(toolPath, parsedVersion[0]);
230+
ToolInfo info = new DefaultToolInfo(toolPath, parsedVersion[0]);
231+
if (tool == Candle3) {
232+
// Detect FIPS mode
233+
var fips = false;
234+
try {
235+
final var exec = Executor.of(toolPath.toString(), "-?").setQuiet(true).saveOutput(true);
236+
final var exitCode = exec.execute();
237+
if (exitCode != 0 /* 308 */) {
238+
final var output = exec.getOutput();
239+
if (!output.isEmpty() && output.get(0).contains("error CNDL0308")) {
240+
fips = true;
241+
}
242+
}
243+
} catch (IOException ex) {
244+
Log.verbose(ex);
245+
}
246+
info = new DefaultCandleInfo(info, fips);
247+
}
248+
return Optional.of(new ToolLookupResult(tool, info, tooOld[0]));
194249
} else {
195-
this.versionTooOld = false;
196-
this.info = null;
250+
return Optional.empty();
197251
}
198252
}
199253

200-
WixTool getTool() {
201-
return tool;
202-
}
203-
204-
ToolInfo getInfo() {
205-
return info;
206-
}
207-
208254
boolean isValid() {
209-
return info != null && !versionTooOld;
255+
return !versionTooOld;
210256
}
211-
212-
boolean isVersionTooOld() {
213-
return versionTooOld;
214-
}
215-
216-
private final WixTool tool;
217-
private final ToolInfo info;
218-
private final boolean versionTooOld;
219257
}
220258

221259
private static Path getSystemDir(String envVar, String knownDir) {

src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -60,11 +60,18 @@ WixToolsetType getType() {
6060
}
6161

6262
Path getToolPath(WixTool tool) {
63-
return tools.get(tool).path;
63+
return tools.get(tool).path();
6464
}
6565

6666
DottedVersion getVersion() {
67-
return tools.values().iterator().next().version;
67+
return tools.values().iterator().next().version();
68+
}
69+
70+
boolean needFipsParameter() {
71+
return tools.values().stream()
72+
.filter(WixTool.CandleInfo.class::isInstance)
73+
.map(WixTool.CandleInfo.class::cast)
74+
.anyMatch(WixTool.CandleInfo::fips);
6875
}
6976

7077
static WixToolset create(Set<WixTool> requiredTools, Map<WixTool, WixTool.ToolInfo> allTools) {

0 commit comments

Comments
 (0)