Java 7 Certificates

alan_trewartha
New Contributor III

I have a web application that uses Java 7 and wanted to get it 'pre-approved' - which used to be easy with Apple's Java 6 as the certificates were originally distributed with MCX back in the day (which would now be done into the system keystore via Casper certificate distribution).

But I don't think there's a way to do this for Java 7 is there? I was feeling very pleased when I found the 'system' certificate store at

/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/trusted.certs

and have got myself as far as importing a cert with keytool

keytool -importcert -noprompt -file mynewcert -keystore trusted.certs

But that requires an inline interactive password setting. Is there a better way of going around doing this. It's a lot of work when I could just e-mail everyone saying "when it comes up the first time tick the OK, and don't ask again" and that will put it in their user home (~/Application Support/Oracle/Java/Deployment/security/trusted.certs)

1 ACCEPTED SOLUTION

NowAllTheTime
Contributor III

This is the command that we have been trying; it accepts the command, but Java doesn't actually show our imported certs in the keystore GUI:

/Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/bin/keytool -importcert -keystore /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/jre/lib/security/cacerts -storepass changeit -alias YOURALIAS -noprompt -file /path/to/your/cert.cer

I haven't tried importing into 'trusted.certs' but maybe that also uses the default '-storepass changeit' I don't know if that helps at all in your case, but it's worth a shot. The documentation on enterprise management of the OS X Java 7 client is pretty weak. We've had to riff off of the Windows documentation for most of our implementation.

View solution in original post

10 REPLIES 10

NowAllTheTime
Contributor III

This is the command that we have been trying; it accepts the command, but Java doesn't actually show our imported certs in the keystore GUI:

/Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/bin/keytool -importcert -keystore /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/jre/lib/security/cacerts -storepass changeit -alias YOURALIAS -noprompt -file /path/to/your/cert.cer

I haven't tried importing into 'trusted.certs' but maybe that also uses the default '-storepass changeit' I don't know if that helps at all in your case, but it's worth a shot. The documentation on enterprise management of the OS X Java 7 client is pretty weak. We've had to riff off of the Windows documentation for most of our implementation.

alan_trewartha
New Contributor III

STOREPASS - thank you, that did it. staring me in the face in the -help command there. I think that did it.

(Oddly it looks like the java 7 install we have is confined to the Library/Internet Plug-Ins/JavaAppletPlugin.plugin and there's nothing in /Library/Java/JavaVirtualMachines)

alan_trewartha
New Contributor III

That answered my immediate issue - but annoyingly though I now have a deployment-ready way to get the certificate into the java 7 'system keystore' it still prompts the user and after approving it manually you end up with the same certitifcate in both user and system pane :-(

lg-jbarclay
New Contributor II

I wrote this quick and dirty Python script for handling this problem. It assumes that the certificate you want to add to the user's trusted.certs keystore exists in /private/tmp.

#!/usr/bin/env python

'''
This script allows you to import a certificate into
the Oracle Java trusted.certs keystore.

Created by James Barclay on 2014-03-10.

'''

from __future__ import print_function

import os
import plistlib
import subprocess
import sys

# Constants
ALIAS            = 'your_alias'
INTERNET_PLUGINS = '/Library/Internet Plug-Ins'
JAVA_CERT        = '/private/tmp/your_cert.cer'

JAVA_WEB_PLUGIN  = os.path.join(INTERNET_PLUGINS, 'JavaAppletPlugin.plugin')

def get_console_user():
    '''Returns the currently logged-in user as
    a string, even if running as EUID root.'''
    if os.geteuid() == 0:
        console_user = subprocess.check_output(['/usr/bin/stat',
                                                '-f%Su',
                                                '/dev/console']).strip()
    else:
        import getpass
        console_user = getpass.getuser()

    return console_user

def determine_java_vendor(info_plist):
    '''Determine Java vendor. Takes the path to
    a Java Info.plist file and returns a string
    of the Java vendor's name.'''
    java_vendor = None
    try:
        pl = plistlib.readPlist(info_plist)
        java_vendor = pl['CFBundleIdentifier'].split('.')[1]

    except KeyError:
        print('CFBundleIdentifer does not exist in %s.' % info_plist)

    except IOError:
        print('%s does not exist!' % info_plist)

    return java_vendor

def get_keytool_path(java_vendor):
    '''Returns the path to the keytool command-
    line utility.'''
    keytool_path = None
    if java_vendor == 'oracle':
        keytool_path = os.path.join(JAVA_WEB_PLUGIN, 'Contents/Home/bin/keytool')
    elif java_vendor == 'apple':
        keytool_path = '/usr/bin/keytool'

    return keytool_path

def cert_in_keystore(keytool, keystore, store_pass, alias):
    '''Returns True if the specified certificate
    alias exists in the specified keystore.'''
    try:
        if os.path.exists(keystore):
            rc = subprocess.check_call([keytool,
                                        '-list',
                                        '-keystore',
                                        keystore,
                                        '-storepass',
                                        store_pass,
                                        '-alias',
                                        alias])
            if rc == 0:
                return True

    except subprocess.CalledProcessError, e:
        print('An error occurred when attempting to locate alias '%s' in %s. Probably ok. Error: %s' % (alias, keystore, e))

def add_cert_to_java_trusted_certs(keytool, store_pass, cert, keystore):
    '''Adds the specified certificate to the specified
    Java cacerts keystore.'''
    try:
        subprocess.check_output([keytool,
                                 '-import',
                                 '-v',
                                 '-noprompt',
                                 '-storepass',
                                 store_pass,
                                 '-alias',
                                 ALIAS,
                                 '-keystore',
                                 keystore,
                                 '-trustcacerts',
                                 '-file',
                                 cert])
    except subprocess.CalledProcessError, e:
        print('An error occurred when attempting to add %s to %s. Error: %s.' % (cert, keystore, e))

def main():
    real_java_path = os.path.realpath(JAVA_WEB_PLUGIN)
    java_info_plist = os.path.join(real_java_path, 'Contents/Info.plist')
    java_vendor = determine_java_vendor(java_info_plist)
    trusted_certs = '/Users/%s/Library/Application Support/Oracle/Java/Deployment/security/trusted.certs' % get_console_user()

    keytool = os.path.join(JAVA_WEB_PLUGIN, 'Contents/Home/bin/keytool')
    if not os.path.isfile(keytool):
        keytool = '/usr/bin/keytool'

    store_pass = ''
    if not os.path.isfile(trusted_certs):
        store_pass = 'changeit'

    if os.path.exists(JAVA_CERT):
        if java_vendor == 'oracle':
            if cert_in_keystore(keytool, trusted_certs, store_pass, ALIAS):
                print('%s already exists in %s. Exiting now.' % (ALIAS, trusted_certs))
                sys.exit(1)
            else:
                print('Using %s to add %s to %s.' % (keytool, JAVA_CERT, trusted_certs))
                add_cert_to_java_trusted_certs(keytool, store_pass, JAVA_CERT, trusted_certs)
        elif java_vendor == 'apple':
            print('Unable to add certificate to trusted.certs. Modify com.apple.java.security.plist instead.')
            sys.exit(1)
        else:
            print('Unable to continue. Unknown Java vendor: %s.' % java_vendor)
            sys.exit(1)
    else:
        print('%s does not exist! Exiting now.' % JAVA_CERT)
        sys.exit(1)

if __name__ == '__main__':
    main()

NowAllTheTime
Contributor III

Huh, I haven't tried setting it via the internet plug-ins path. I'll try that and see if it solves my problem. That's frustrating that it got you a little closer but still ends up with users getting prompted. JAVA!!!!

lunddal
Contributor

@alan.trewartha: the JRE is contained in the Internet plug-in. Jason references the JDK.

We import into /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts btw.

alan_trewartha
New Contributor III

Thanks for clearing that up for me, and i'll try the cacerts file instead

alan_trewartha
New Contributor III

I got it into the cacerts file - it appears listed as both "Signer CA" and "Secure Site CA". But amazingly I still get prompted to go through manually adding it in the 'user realm' and end up with it there under "Trusted certificates" too.

For anyone playing along at home, the "cacert" file has a default password of "changeit" (or "changeme" on some earlier versions) (which jason already mentioned! d'oh)

NowAllTheTime
Contributor III

Ok, so I adjust my command to the following and it is working everywhere I need it:

sudo /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/keytool -importcert -keystore /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts -storepass changeit -alias YOURALIAS -noprompt -file /path/to/your/cert.cer

We are also utilizing the DeploymentRuleSet.jar which allows us to whitelist websites, which might be something you need to stop getting that prompt.

Here are the instructions we followed for how to create the whitelist):

http://kylebubp.com/2013/11/use-java-whitelisting-to-further-secure-your-organization/

The only thing that we did differently from this document was placing the DeploymentRuleSet.jar in /Library/Application Support/Oracle/Java/Deployment/ instead of /etc/.java/deployment/

alan_trewartha
New Contributor III

I thought I'd give that new style whitelist JAR a shot, but I got a bit unstuck at the jar signing. looks like it would give us good control of this sort of thing - as would importing it properly into the system certs properly if I understood what I was doing and could spot what I was doing wrong in the first place!