Skip to content

Commit 0ebdde9

Browse files
Sort out signing.
1 parent 8bc74d3 commit 0ebdde9

15 files changed

+283
-179
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package jdk.jpackage.internal;
26+
27+
import java.nio.file.Path;
28+
import java.util.Objects;
29+
import java.util.Optional;
30+
import jdk.jpackage.internal.model.AppImageSigningConfig;
31+
import jdk.jpackage.internal.model.ConfigException;
32+
import jdk.jpackage.internal.model.LauncherStartupInfo;
33+
34+
final class AppImageSigningConfigBuilder {
35+
36+
AppImageSigningConfigBuilder(SigningIdentityBuilder signingIdentityBuilder) {
37+
this.signingIdentityBuilder = Objects.requireNonNull(signingIdentityBuilder);
38+
}
39+
40+
AppImageSigningConfigBuilder entitlements(Path v) {
41+
entitlements = v;
42+
return this;
43+
}
44+
45+
AppImageSigningConfigBuilder entitlementsResourceName(String v) {
46+
entitlementsResourceName = v;
47+
return this;
48+
}
49+
50+
AppImageSigningConfigBuilder signingIdentifierPrefix(LauncherStartupInfo mainLauncherStartupInfo) {
51+
final var pkgName = mainLauncherStartupInfo.packageName();
52+
if (!pkgName.isEmpty()) {
53+
signingIdentifierPrefix(pkgName + ".");
54+
} else {
55+
signingIdentifierPrefix(mainLauncherStartupInfo.simpleClassName() + ".");
56+
}
57+
return this;
58+
}
59+
60+
AppImageSigningConfigBuilder signingIdentifierPrefix(String v) {
61+
signingIdentifierPrefix = v;
62+
return this;
63+
}
64+
65+
Optional<AppImageSigningConfig> create() throws ConfigException {
66+
final var identityCfg = signingIdentityBuilder.create();
67+
if (identityCfg.isEmpty()) {
68+
return Optional.empty();
69+
} else {
70+
final var validatedEntitlements = validatedEntitlements();
71+
return identityCfg.map(cfg -> {
72+
return new AppImageSigningConfig.Stub(cfg.identity(), signingIdentifierPrefix,
73+
validatedEntitlements, cfg.keychain().map(Keychain::name),
74+
Optional.ofNullable(entitlementsResourceName).orElse("sandbox.plist"));
75+
});
76+
}
77+
}
78+
79+
private Optional<Path> validatedEntitlements() throws ConfigException {
80+
return Optional.ofNullable(entitlements);
81+
}
82+
83+
private SigningIdentityBuilder signingIdentityBuilder;
84+
private Path entitlements;
85+
private String entitlementsResourceName;
86+
private String signingIdentifierPrefix;
87+
}

src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CodesignConfig.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,40 @@
2727
import java.nio.file.Path;
2828
import java.util.ArrayList;
2929
import java.util.List;
30+
import java.util.Objects;
3031
import java.util.Optional;
31-
import jdk.jpackage.internal.model.SigningConfig;
32+
import jdk.jpackage.internal.model.AppImageSigningConfig;
3233
import jdk.jpackage.internal.model.SigningIdentity;
3334
import jdk.jpackage.internal.util.PathUtils;
3435

3536

36-
record CodesignConfig(Optional<SigningIdentity> identity,
37+
record CodesignConfig(Optional<SigningIdentity> identity, Optional<String> identifierPrefix,
3738
Optional<Path> entitlements, Optional<Keychain> keychain) {
3839

40+
CodesignConfig {
41+
Objects.requireNonNull(identity);
42+
Objects.requireNonNull(identifierPrefix);
43+
Objects.requireNonNull(entitlements);
44+
Objects.requireNonNull(keychain);
45+
46+
if (identity.isPresent() != identifierPrefix.isPresent()) {
47+
throw new IllegalArgumentException("Signing identity and identifier prefix mismatch");
48+
}
49+
50+
identifierPrefix.ifPresent(v -> {
51+
if (!v.endsWith(".")) {
52+
throw new IllegalArgumentException("Invalid identifier prefix");
53+
}
54+
});
55+
}
56+
3957
static final class Builder {
4058

4159
private Builder() {
4260
}
4361

4462
CodesignConfig create() {
45-
return new CodesignConfig(Optional.ofNullable(identity),
63+
return new CodesignConfig(Optional.ofNullable(identity), Optional.ofNullable(identifierPrefix),
4664
Optional.ofNullable(entitlements), Optional.ofNullable(keychain));
4765
}
4866

@@ -56,6 +74,11 @@ Builder identity(SigningIdentity v) {
5674
return this;
5775
}
5876

77+
Builder identifierPrefix(String v) {
78+
identifierPrefix = v;
79+
return this;
80+
}
81+
5982
Builder keychain(String v) {
6083
return keychain(new Keychain(v));
6184
}
@@ -65,19 +88,22 @@ Builder keychain(Keychain v) {
6588
return this;
6689
}
6790

68-
Builder from(SigningConfig v) {
69-
return identity(v.identity().orElse(null))
91+
Builder from(AppImageSigningConfig v) {
92+
return identity(v.identity())
93+
.identifierPrefix(v.identifierPrefix())
7094
.entitlements(v.entitlements().orElse(null))
7195
.keychain(v.keychain().orElse(null));
7296
}
7397

7498
Builder from(CodesignConfig v) {
7599
return identity(v.identity().orElse(null))
100+
.identifierPrefix(v.identifierPrefix().orElse(null))
76101
.entitlements(v.entitlements().orElse(null))
77102
.keychain(v.keychain().orElse(null));
78103
}
79104

80105
private SigningIdentity identity;
106+
private String identifierPrefix;
81107
private Path entitlements;
82108
private Keychain keychain;
83109
}
@@ -91,8 +117,8 @@ List<String> toCodesignArgs() {
91117

92118
if (identity.isPresent()) {
93119
args.addAll(List.of("--timestamp", "--options", "runtime"));
94-
identity.flatMap(SigningIdentity::prefix).ifPresent(identifierPrefix -> {
95-
args.addAll(List.of("--prefix", identifierPrefix));
120+
identifierPrefix.ifPresent(v -> {
121+
args.addAll(List.of("--prefix", v));
96122
});
97123
keychain.map(Keychain::asCliArg).ifPresent(k -> args.addAll(List.of("--keychain", k)));
98124
entitlements.map(PathUtils::normalizedAbsolutePathString).ifPresent(e -> args.addAll(List.of("--entitlements", e)));

src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import jdk.jpackage.internal.model.Launcher;
3535
import jdk.jpackage.internal.model.MacApplication;
3636
import jdk.jpackage.internal.model.MacApplicationMixin;
37-
import jdk.jpackage.internal.model.SigningConfig;
37+
import jdk.jpackage.internal.model.AppImageSigningConfig;
3838

3939
final class MacApplicationBuilder {
4040

@@ -83,7 +83,7 @@ MacApplicationBuilder externalInfoPlistFile(Path v) {
8383
return this;
8484
}
8585

86-
MacApplicationBuilder signingBuilder(SigningConfigBuilder v) {
86+
MacApplicationBuilder signingBuilder(AppImageSigningConfigBuilder v) {
8787
signingBuilder = v;
8888
return this;
8989
}
@@ -154,7 +154,7 @@ private MacApplicationBuilder createCopyForExternalInfoPlistFile() throws Config
154154
}
155155
}
156156

157-
private Optional<SigningConfig> createSigningConfig() throws ConfigException {
157+
private Optional<AppImageSigningConfig> createSigningConfig() throws ConfigException {
158158
if (signingBuilder != null) {
159159
return signingBuilder.create();
160160
} else {
@@ -224,7 +224,7 @@ private record Defaults(String category) {
224224
private String category;
225225
private boolean appStore;
226226
private Path externalInfoPlistFile;
227-
private SigningConfigBuilder signingBuilder;
227+
private AppImageSigningConfigBuilder signingBuilder;
228228

229229
private final Application app;
230230

src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacCertificateUtils.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@
2525

2626
package jdk.jpackage.internal;
2727

28-
import static jdk.jpackage.internal.util.CollectionUtils.toCollectionUBW;
2928
import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier;
3029

30+
import java.io.BufferedInputStream;
3131
import java.io.ByteArrayInputStream;
3232
import java.nio.charset.StandardCharsets;
3333
import java.security.MessageDigest;
34+
import java.security.cert.CertificateException;
3435
import java.security.cert.CertificateFactory;
3536
import java.security.cert.X509Certificate;
3637
import java.util.ArrayList;
@@ -51,7 +52,7 @@ public static Collection<X509Certificate> findCertificates(Optional<Keychain> ke
5152
args.add("-p"); // PEM format
5253
keychain.map(Keychain::asCliArg).ifPresent(args::add);
5354

54-
return toCollectionUBW(toSupplier(() -> {
55+
return toSupplier(() -> {
5556
final var output = Executor.of(args.toArray(String[]::new))
5657
.setQuiet(true).saveOutput(true).executeExpectSuccess()
5758
.getOutput();
@@ -61,11 +62,24 @@ public static Collection<X509Certificate> findCertificates(Optional<Keychain> ke
6162
MacCertificateUtils::append,
6263
MacCertificateUtils::append).toString().getBytes(StandardCharsets.US_ASCII);
6364

64-
try (var in = new ByteArrayInputStream(pemCertificatesBuffer)) {
65-
final var cf = CertificateFactory.getInstance("X.509");
66-
return cf.generateCertificates(in);
65+
final var cf = CertificateFactory.getInstance("X.509");
66+
67+
Collection<X509Certificate> certs = new ArrayList<>();
68+
69+
try (var in = new BufferedInputStream(new ByteArrayInputStream(pemCertificatesBuffer))) {
70+
while (in.available() > 0) {
71+
final X509Certificate cert;
72+
try {
73+
cert = (X509Certificate)cf.generateCertificate(in);
74+
} catch (CertificateException ex) {
75+
// Not a valid X505 certificate, silently ignore.
76+
continue;
77+
}
78+
certs.add(cert);
79+
}
6780
}
68-
}).get());
81+
return certs;
82+
}).get();
6983
}
7084

7185
record CertificateHash(byte[] value) {

src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
import java.util.Optional;
5757
import java.util.function.Predicate;
5858
import jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo;
59-
import jdk.jpackage.internal.SigningConfigBuilder.StandardCertificateSelector;
59+
import jdk.jpackage.internal.SigningIdentityBuilder.StandardCertificateSelector;
6060
import jdk.jpackage.internal.model.Application;
6161
import jdk.jpackage.internal.model.ApplicationLaunchers;
6262
import jdk.jpackage.internal.model.ConfigException;
@@ -130,25 +130,29 @@ private static MacApplication createMacApplication(
130130
appBuilder.appStore(appStore);
131131

132132
if (sign) {
133-
final var signingBuilder = createSigningConfigBuilder(params, app);
134-
if (appStore) {
135-
signingBuilder.entitlementsResourceName("entitlements.plist");
136-
}
137-
138-
ENTITLEMENTS.copyInto(params, signingBuilder::entitlements);
139-
APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentity);
140-
133+
final var signingIdentityBuilder = createSigningIdentityBuilder(params, app);
134+
APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingIdentityBuilder::signingIdentity);
141135
SIGNING_KEY_USER.findIn(params).ifPresent(userName -> {
142-
final StandardCertificateSelector filter;
136+
final StandardCertificateSelector domain;
143137
if (appStore) {
144-
filter = StandardCertificateSelector.APP_STORE_APP_IMAGE;
138+
domain = StandardCertificateSelector.APP_STORE_APP_IMAGE;
145139
} else {
146-
filter = StandardCertificateSelector.APP_IMAGE;
140+
domain = StandardCertificateSelector.APP_IMAGE;
147141
}
148142

149-
signingBuilder.addCertificateSelectors(StandardCertificateSelector.create(userName, filter));
143+
signingIdentityBuilder.certificateSelector(StandardCertificateSelector.create(userName, domain));
150144
});
151145

146+
final var signingBuilder = new AppImageSigningConfigBuilder(signingIdentityBuilder);
147+
if (appStore) {
148+
signingBuilder.entitlementsResourceName("entitlements.plist");
149+
}
150+
151+
app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(signingBuilder::signingIdentifierPrefix);
152+
SIGN_IDENTIFIER_PREFIX.copyInto(params, signingBuilder::signingIdentifierPrefix);
153+
154+
ENTITLEMENTS.copyInto(params, signingBuilder::entitlements);
155+
152156
appBuilder.signingBuilder(signingBuilder);
153157
}
154158

@@ -195,32 +199,27 @@ private static MacPkgPackage createMacPkgPackage(
195199
final boolean appStore = APP_STORE.findIn(params).orElse(false);
196200

197201
if (sign) {
198-
final var signingBuilder = createSigningConfigBuilder(params, app);
199-
INSTALLER_SIGN_IDENTITY.copyInto(params, signingBuilder::signingIdentity);
200-
202+
final var signingIdentityBuilder = createSigningIdentityBuilder(params, app);
203+
INSTALLER_SIGN_IDENTITY.copyInto(params, signingIdentityBuilder::signingIdentity);
201204
SIGNING_KEY_USER.findIn(params).ifPresent(userName -> {
202-
final List<StandardCertificateSelector> filters;
205+
final StandardCertificateSelector domain;
203206
if (appStore) {
204-
filters = List.of(StandardCertificateSelector.APP_STORE_PKG_INSTALLER);
207+
domain = StandardCertificateSelector.APP_STORE_PKG_INSTALLER;
205208
} else {
206-
filters = List.of(StandardCertificateSelector.PKG_INSTALLER);
209+
domain = StandardCertificateSelector.PKG_INSTALLER;
207210
}
208211

209-
for (final var filter : filters) {
210-
signingBuilder.addCertificateSelectors(StandardCertificateSelector.create(userName, filter));
211-
}
212+
signingIdentityBuilder.certificateSelector(StandardCertificateSelector.create(userName, domain));
212213
});
213214

214-
pkgBuilder.signingBuilder(signingBuilder);
215+
pkgBuilder.signingBuilder(signingIdentityBuilder);
215216
}
216217

217218
return pkgBuilder.create();
218219
}
219220

220-
private static SigningConfigBuilder createSigningConfigBuilder(Map<String, ? super Object> params, Application app) {
221-
final var builder = new SigningConfigBuilder();
222-
app.mainLauncher().flatMap(Launcher::startupInfo).ifPresent(builder::signingIdentityPrefix);
223-
BUNDLE_ID_SIGNING_PREFIX.copyInto(params, builder::signingIdentityPrefix);
221+
private static SigningIdentityBuilder createSigningIdentityBuilder(Map<String, ? super Object> params, Application app) {
222+
final var builder = new SigningIdentityBuilder();
224223
SIGNING_KEYCHAIN.copyInto(params, builder::keychain);
225224
return builder;
226225
}
@@ -264,7 +263,7 @@ private static MacFileAssociation createMacFa(FileAssociation fa, Map<String, ?
264263
static final BundlerParamInfo<String> MAC_CF_BUNDLE_IDENTIFIER = createStringBundlerParam(
265264
Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId());
266265

267-
static final BundlerParamInfo<String> BUNDLE_ID_SIGNING_PREFIX = createStringBundlerParam(
266+
static final BundlerParamInfo<String> SIGN_IDENTIFIER_PREFIX = createStringBundlerParam(
268267
Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId());
269268

270269
static final BundlerParamInfo<String> APP_IMAGE_SIGN_IDENTITY = createStringBundlerParam(

0 commit comments

Comments
 (0)