changeset 10819:e93e46dabb83

8195074: Improve signing mechanism on Mac 10.12+ Reviewed-by: kcr
author vdrozdov
date Thu, 25 Jan 2018 11:44:19 -0800
parents 7460c802051f
children 3361ad25093b
files modules/jdk.packager/src/main/java/com/oracle/tools/packager/IOUtils.java modules/jdk.packager/src/main/java/com/oracle/tools/packager/Platform.java modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacAppStoreBundler.java modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacPkgBundler.java modules/jdk.packager/src/main/java/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.java modules/jdk.packager/src/main/resources/com/oracle/tools/packager/mac/MacPkgBundler.properties modules/jdk.packager/src/main/resources/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.properties
diffstat 7 files changed, 148 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/modules/jdk.packager/src/main/java/com/oracle/tools/packager/IOUtils.java	Wed Jan 24 17:45:39 2018 -0800
+++ b/modules/jdk.packager/src/main/java/com/oracle/tools/packager/IOUtils.java	Thu Jan 25 11:44:19 2018 -0800
@@ -219,7 +219,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    public static int execute(Object ... args) throws IOException, InterruptedException {
+    private static Process startProcess(Object... args) throws IOException {
         final ArrayList<String> argsList = new ArrayList<>();
         for (Object a : args) {
             if (a instanceof List) {
@@ -228,7 +228,30 @@
                 argsList.add((String)a);
             }
         }
-        final Process p = Runtime.getRuntime().exec(argsList.toArray(new String[argsList.size()]));
+
+        return Runtime.getRuntime().exec(argsList.toArray(new String[argsList.size()]));
+    }
+
+    private static void logErrorStream(Process p) {
+        final BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream()));
+        Thread t = new Thread(() -> {
+            try {
+                String line;
+                while ((line = err.readLine()) != null) {
+                    Log.error(line);
+                }
+            } catch (IOException ioe) {
+                Log.verbose(ioe);
+            }
+        });
+        t.setDaemon(true);
+        t.start();
+    }
+
+    @SuppressWarnings("unchecked")
+    public static int execute(Object ... args) throws IOException, InterruptedException {
+        final Process p = startProcess(args);
+
         final BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
         Thread t = new Thread(() -> {
             try {
@@ -242,20 +265,38 @@
         });
         t.setDaemon(true);
         t.start();
-        final BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream()));
-        t = new Thread(() -> {
+
+        logErrorStream(p);
+        return p.waitFor();
+    }
+
+    public static int getProcessOutput(List<String> result, Object... args)
+            throws IOException, InterruptedException {
+        final Process p = startProcess(args);
+
+        List<String> list = new ArrayList<>();
+        final BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
+        Thread t = new Thread(() -> {
             try {
                 String line;
-                while ((line = err.readLine()) != null) {
-                    Log.error(line);
+                while ((line = in.readLine()) != null) {
+                    list.add(line);
                 }
             } catch (IOException ioe) {
-                Log.verbose(ioe);
+                com.oracle.tools.packager.Log.verbose(ioe);
             }
         });
         t.setDaemon(true);
         t.start();
-        return p.waitFor();
+
+        logErrorStream(p);
+
+        int ret = p.waitFor();
+
+        result.clear();
+        result.addAll(list);
+
+        return ret;
     }
 
     //no good test if we are running pre-JRE7
--- a/modules/jdk.packager/src/main/java/com/oracle/tools/packager/Platform.java	Wed Jan 24 17:45:39 2018 -0800
+++ b/modules/jdk.packager/src/main/java/com/oracle/tools/packager/Platform.java	Thu Jan 25 11:44:19 2018 -0800
@@ -76,7 +76,7 @@
             majorVersion = Integer.parseInt(parts[0]);
 
             if (parts.length > 1) {
-                minorVersion = Integer.parseInt(parts[0]);
+                minorVersion = Integer.parseInt(parts[1]);
             }
             else {
                 minorVersion = -1;
--- a/modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacAppStoreBundler.java	Wed Jan 24 17:45:39 2018 -0800
+++ b/modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacAppStoreBundler.java	Thu Jan 25 11:44:19 2018 -0800
@@ -144,6 +144,11 @@
         try {
             appImageDir.mkdirs();
 
+            try {
+                MacAppImageBuilder.addNewKeychain(p);
+            } catch (InterruptedException e) {
+                Log.error(e.getMessage());
+            }
             // first, make sure we don't use the local signing key
             p.put(DEVELOPER_ID_APP_SIGNING_KEY.getID(), null);
             File appLocation = prepareAppBundle(p);
@@ -156,6 +161,8 @@
             String inheritEntitlements = getConfig_Inherit_Entitlements(p).toString();
 
             MacAppImageBuilder.signAppBundle(p, appLocation.toPath(), signingIdentity, identifierPrefix, entitlementsFile, inheritEntitlements);
+            MacAppImageBuilder.restoreKeychainList(p);
+
             ProcessBuilder pb;
 
             // create the final pkg file
--- a/modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacPkgBundler.java	Wed Jan 24 17:45:39 2018 -0800
+++ b/modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacPkgBundler.java	Thu Jan 25 11:44:19 2018 -0800
@@ -30,6 +30,7 @@
 import com.oracle.tools.packager.Log;
 import com.oracle.tools.packager.ConfigException;
 import com.oracle.tools.packager.IOUtils;
+import com.oracle.tools.packager.Platform;
 import com.oracle.tools.packager.RelativeFileSet;
 import com.oracle.tools.packager.UnsupportedPlatformException;
 
@@ -396,6 +397,11 @@
     private File createPKG(Map<String, ? super Object> params, File outdir, File appLocation) {
         //generic find attempt
         try {
+            if (Platform.getMajorVersion() > 10 ||
+                (Platform.getMajorVersion() == 10 && Platform.getMinorVersion() >= 12)) {
+                // we need this for OS X 10.12+
+                Log.info(I18N.getString("message.signing.pkg"));
+            }
             String daemonLocation = DAEMON_IMAGE_BUILD_ROOT.fetchFrom(params) + "/" + APP_NAME.fetchFrom(params) + ".daemon";
 
             File appPKG = getPackages_AppPackage(params);
--- a/modules/jdk.packager/src/main/java/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.java	Wed Jan 24 17:45:39 2018 -0800
+++ b/modules/jdk.packager/src/main/java/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.java	Thu Jan 25 11:44:19 2018 -0800
@@ -28,6 +28,7 @@
 import com.oracle.tools.packager.BundlerParamInfo;
 import com.oracle.tools.packager.IOUtils;
 import com.oracle.tools.packager.Log;
+import com.oracle.tools.packager.Platform;
 import com.oracle.tools.packager.RelativeFileSet;
 import com.oracle.tools.packager.StandardBundlerParam;
 import com.oracle.tools.packager.mac.MacResources;
@@ -92,6 +93,8 @@
 
     private final Map<String, ? super Object> params;
 
+    private static List<String> keyChains;
+
     private static Map<String, String> getMacCategories() {
         Map<String, String> map = new HashMap<>();
         map.put("Business", "public.app-category.business");
@@ -415,10 +418,16 @@
 
         // maybe sign
         if (Optional.ofNullable(SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) {
+            try {
+                addNewKeychain(params);
+            } catch (InterruptedException e) {
+                Log.error(e.getMessage());
+            }
             String signingIdentity = DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params);
             if (signingIdentity != null) {
                 signAppBundle(params, root, signingIdentity, BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params), null, null);
             }
+            restoreKeychainList(params);
         }
     }
 
@@ -719,6 +728,79 @@
         }
     }
 
+    public static void addNewKeychain(Map<String, ? super Object> params)
+                                    throws IOException, InterruptedException {
+        if (Platform.getMajorVersion() < 10 ||
+            (Platform.getMajorVersion() == 10 && Platform.getMinorVersion() < 12)) {
+            // we need this for OS X 10.12+
+            return;
+        }
+
+        String keyChain = SIGNING_KEYCHAIN.fetchFrom(params);
+        if (keyChain == null || keyChain.isEmpty()) {
+            return;
+        }
+
+        // get current keychain list
+        String keyChainPath = new File (keyChain).getAbsolutePath().toString();
+        List<String> keychainList = new ArrayList<>();
+        int ret = IOUtils.getProcessOutput(keychainList, "security", "list-keychains");
+        if (ret != 0) {
+            Log.error(I18N.getString("message.keychain.error"));
+            return;
+        }
+
+        boolean contains = keychainList.stream().anyMatch(
+                    str -> str.trim().equals("\""+keyChainPath.trim()+"\""));
+        if (contains) {
+            // keychain is already added in the search list
+            return;
+        }
+
+        keyChains = new ArrayList<>();
+        // remove "
+        keychainList.forEach((String s) -> {
+            String path = s.trim();
+            if (path.startsWith("\"") && path.endsWith("\"")) {
+                path = path.substring(1, path.length()-1);
+            }
+            keyChains.add(path);
+        });
+
+        List<String> args = new ArrayList<>();
+        args.add("security");
+        args.add("list-keychains");
+        args.add("-s");
+
+        args.addAll(keyChains);
+        args.add(keyChain);
+
+        ProcessBuilder  pb = new ProcessBuilder(args);
+        IOUtils.exec(pb, VERBOSE.fetchFrom(params));
+    }
+
+    public static void restoreKeychainList(Map<String, ? super Object> params) throws IOException{
+        if (Platform.getMajorVersion() < 10 ||
+            (Platform.getMajorVersion() == 10 && Platform.getMinorVersion() < 12)) {
+            // we need this for OS X 10.12+
+            return;
+        }
+
+        if (keyChains == null || keyChains.isEmpty()) {
+            return;
+        }
+
+        List<String> args = new ArrayList<>();
+        args.add("security");
+        args.add("list-keychains");
+        args.add("-s");
+
+        args.addAll(keyChains);
+
+        ProcessBuilder  pb = new ProcessBuilder(args);
+        IOUtils.exec(pb, VERBOSE.fetchFrom(params));
+    }
+
     public static void signAppBundle(Map<String, ? super Object> params, Path appLocation, String signingIdentity, String identifierPrefix, String entitlementsFile, String inheritedEntitlements) throws IOException {
         AtomicReference<IOException> toThrow = new AtomicReference<>();
         String appExecutable = "/Contents/MacOS/" + APP_NAME.fetchFrom(params);
--- a/modules/jdk.packager/src/main/resources/com/oracle/tools/packager/mac/MacPkgBundler.properties	Wed Jan 24 17:45:39 2018 -0800
+++ b/modules/jdk.packager/src/main/resources/com/oracle/tools/packager/mac/MacPkgBundler.properties	Thu Jan 25 11:44:19 2018 -0800
@@ -33,3 +33,4 @@
 message.preparing-distribution-dist=Preparing distribution.dist\: {0}
 message.config-save-location=Config files are saved to {0}. Use them to customize package.
 message.intermediate-image-location=[DEBUG] Intermediate application bundle image\: {0}
+message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trust" for your certificate using "Keychain Access" tool.
--- a/modules/jdk.packager/src/main/resources/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.properties	Wed Jan 24 17:45:39 2018 -0800
+++ b/modules/jdk.packager/src/main/resources/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.properties	Thu Jan 25 11:44:19 2018 -0800
@@ -70,4 +70,5 @@
 message.using-custom-resource-from-file=Using custom package resource {0} (loaded from file {1})
 message.using-custom-resource-from-classpath=Using custom package resource {0} (loaded from {1})
 message.using-default-resource-from-classpath=Using default package resource {0} (add {1} to the class path to customize)
-message.ignoring.symlink=Warning: codesign is skipping the symlink {0}
\ No newline at end of file
+message.ignoring.symlink=Warning: codesign is skipping the symlink {0}
+message.keychain.error=Error: unable to get keychain list.
\ No newline at end of file