Skip to content

Commit

Permalink
remove keytool and use java binary to generate cacerts
Browse files Browse the repository at this point in the history
  • Loading branch information
thesayyn committed Dec 6, 2023
1 parent 5594c82 commit f3b0139
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 100 deletions.
9 changes: 8 additions & 1 deletion .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@ common --enable_bzlmod
# https://bazelbuild.slack.com/archives/C014RARENH0/p1691158021917459?thread_ts=1691156601.420349&cid=C014RARENH0
common --check_direct_dependencies=off

# Enable platform specific options
build --enable_platform_specific_config

# Use a hermetic Java version
build --java_runtime_version=remotejdk_17
build --java_runtime_version=remotejdk_11

# Newer versions jdk creates collisions on /tmp
# See: https://github.com/bazelbuild/bazel/issues/3236
# https://github.com/GoogleContainerTools/rules_distroless/actions/runs/7118944984/job/19382981899?pr=9#step:8:51
common:linux --sandbox_tmpfs_path=/tmp

# Load any settings specific to the current user.
# .bazelrc.user should appear in .gitignore so that settings are not shared with team members
Expand Down
11 changes: 10 additions & 1 deletion distroless/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library")

exports_files([
"cacerts.sh",
"java_keystore.sh",
])

java_binary(
name = "keystore_binary",
srcs = ["JavaKeyStore.java"],
javacopts = [
"-Xlint:-options",
],
main_class = "JavaKeyStore",
visibility = ["//visibility:public"],
)

bzl_library(
name = "cacerts",
srcs = ["cacerts.bzl"],
Expand Down
117 changes: 117 additions & 0 deletions distroless/private/JavaKeyStore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@

// Parts taken from https://github.com/openjdk/jdk17u-dev/blob/a028120220f6fd28e39fe0f6190eb1f5da6a788d/make/jdk/src/classes/build/tools/generatecacerts/GenerateCacerts.java
// https://github.com/GoogleContainerTools/distroless/tree/b1e2203eceb9cc91de0500d71c648e346e1d7b89/cacerts/jksutil
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.security.auth.x500.X500Principal;

/**
* Generate cacerts
*/
class JavaKeyStore {

private static final int MAGIC = 0xfeedfeed;
private static final int VERSION = 0x02;
private static final int TRUSTED_CERT_TAG = 0x02;
private static final char[] PASSWORD = "changeit".toCharArray();
private static final String SALT = "Mighty Aphrodite";

public static void main(String[] args) throws Exception {
try (FileOutputStream output = new FileOutputStream(args[0])) {
store(output, Arrays.copyOfRange(args, 1, args.length));
}
}

public static void store(OutputStream stream, String[] entries)
throws IOException, NoSuchAlgorithmException, CertificateException {
byte[] encoded; // the certificate encoding
CertificateFactory cf = CertificateFactory.getInstance("X509");

MessageDigest md = getPreKeyedHash(PASSWORD);
DataOutputStream dos = new DataOutputStream(new DigestOutputStream(stream, md));

HashMap<String, X509Certificate> certs = new HashMap<String, X509Certificate>();

for (String entry : entries) {
try (InputStream fis = Files.newInputStream(Path.of(entry))) {
for (Certificate rcert : cf.generateCertificates(fis)) {
X509Certificate cert = (X509Certificate) rcert;
String alias = cert.getSubjectX500Principal().getName(X500Principal.CANONICAL);
certs.put(alias, cert);
}
}
}

dos.writeInt(MAGIC);
dos.writeInt(VERSION);
dos.writeInt(certs.size());

for (Entry<String, X509Certificate> entry : certs.entrySet()) {

X509Certificate cert = entry.getValue();
String alias = entry.getKey();

dos.writeInt(TRUSTED_CERT_TAG);

// Write the alias
dos.writeUTF(alias);

// Write the (entry creation) date, which is notBefore of the cert
dos.writeLong(cert.getNotBefore().getTime());

// Write the trusted certificate
encoded = cert.getEncoded();
dos.writeUTF(cert.getType());
dos.writeInt(encoded.length);
dos.write(encoded);
}

/*
* Write the keyed hash which is used to detect tampering with
* the keystore (such as deleting or modifying key or
* certificate entries).
*/
byte[] digest = md.digest();

dos.write(digest);
dos.flush();
}

private static MessageDigest getPreKeyedHash(char[] password)
throws NoSuchAlgorithmException, UnsupportedEncodingException {

MessageDigest md = MessageDigest.getInstance("SHA");
byte[] passwdBytes = convertToBytes(password);
md.update(passwdBytes);
Arrays.fill(passwdBytes, (byte) 0x00);
md.update(SALT.getBytes("UTF8"));
return md;
}

private static byte[] convertToBytes(char[] password) {
int i, j;
byte[] passwdBytes = new byte[password.length * 2];
for (i = 0, j = 0; i < password.length; i++) {
passwdBytes[j++] = (byte) (password[i] >> 8);
passwdBytes[j++] = (byte) password[i];
}
return passwdBytes;
}
}
28 changes: 3 additions & 25 deletions distroless/private/java_keystore.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,15 @@ _DOC = """Create a java keystore (database) of cryptographic keys, X.509 certifi
Currently only public X.509 are supported as part of the PUBLIC API contract.
"""

def _find_keytool(java):
for f in java.java_runtime.files.to_list():
if f.basename == "keytool":
return f
fail("java toolchain does not contain `keytool`.")

def _java_keystore_impl(ctx):
jdk = ctx.toolchains["@bazel_tools//tools/jdk:toolchain_type"]
coreutils = ctx.toolchains["@aspect_bazel_lib//lib:coreutils_toolchain_type"]
bsdtar = ctx.toolchains[tar_lib.TOOLCHAIN_TYPE]
keytool = _find_keytool(jdk.java)

jks = ctx.actions.declare_file(ctx.attr.name + ".jks")

args = ctx.actions.args()

args.add(bsdtar.tarinfo.binary)
args.add(keytool)
args.add(coreutils.coreutils_info.bin)
args.add(jks)
args.add_all(ctx.files.certificates)

ctx.actions.run(
executable = ctx.executable._java_keystore_sh,
tools = depset(
[keytool, coreutils.coreutils_info.bin],
transitive = [bsdtar.default.files],
),
executable = ctx.executable._java_keystore,
inputs = ctx.files.certificates,
outputs = [jks],
arguments = [args],
Expand All @@ -55,11 +36,10 @@ def _java_keystore_impl(ctx):
java_keystore = rule(
doc = _DOC,
attrs = {
"_java_keystore_sh": attr.label(
allow_single_file = True,
"_java_keystore": attr.label(
executable = True,
cfg = "exec",
default = ":java_keystore.sh",
default = ":keystore_binary",
),
"certificates": attr.label_list(
allow_files = True,
Expand All @@ -70,7 +50,5 @@ java_keystore = rule(
implementation = _java_keystore_impl,
toolchains = [
tar_lib.TOOLCHAIN_TYPE,
"@bazel_tools//tools/jdk:toolchain_type",
"@aspect_bazel_lib//lib:coreutils_toolchain_type",
],
)
25 changes: 0 additions & 25 deletions distroless/private/java_keystore.sh

This file was deleted.

2 changes: 1 addition & 1 deletion examples/java_keystore/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ assert_tar_listing(
./etc/ssl time=1672560000.0 mode=755 gid=0 uid=0 type=dir
./etc/ssl/certs time=1672560000.0 mode=755 gid=0 uid=0 type=dir
./etc/ssl/certs/java time=1672560000.0 mode=755 gid=0 uid=0 type=dir
./etc/ssl/certs/java/cacerts nlink=0 time=1672560000.0 mode=755 gid=0 uid=0 type=file size=6214 cksum=53117108 sha1digest=c84a267b4b57f6e9c18773e26c78da66091c7ea8
./etc/ssl/certs/java/cacerts nlink=0 time=1672560000.0 mode=755 gid=0 uid=0 type=file size=5349 cksum=3752477219 sha1digest=015078faa5537fcabb6c7e73fe2dedf8241b106d
""",
)
94 changes: 47 additions & 47 deletions examples/java_keystore/expected.jks.output
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Keystore type: PKCS12
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 5 entries

Alias name: c=us,o=amazon,cn=amazonrootca1
Creation date: Dec 1, 2023
Alias name: cn=amazon root ca 1,o=amazon,c=us
Creation date: May 26, 2015
Entry type: trustedCertEntry

-----BEGIN CERTIFICATE-----
Expand Down Expand Up @@ -33,8 +33,8 @@ rqXRfboQnoZsG4q5WTP468SQvvG5
*******************************************


Alias name: c=us,o=digicertinc,ou=www.digicert.com,cn=digicertassuredidrootca
Creation date: Dec 1, 2023
Alias name: cn=digicert assured id root ca,ou=www.digicert.com,o=digicert inc,c=us
Creation date: Nov 10, 2006
Entry type: trustedCertEntry

-----BEGIN CERTIFICATE-----
Expand Down Expand Up @@ -65,46 +65,8 @@ H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
*******************************************


Alias name: c=us,o=verisign,inc.,ou=verisigntrustnetwork,ou=(c)2008verisign,inc.-forauthorizeduseonly,cn=verisignuniversalrootcertificationauthority
Creation date: Dec 1, 2023
Entry type: trustedCertEntry

-----BEGIN CERTIFICATE-----
MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
7M2CYfE45k+XmCpajQ==
-----END CERTIFICATE-----


*******************************************
*******************************************


Alias name: ou=globalsignrootca-r2,o=globalsign,cn=globalsign
Creation date: Dec 1, 2023
Alias name: cn=globalsign,o=globalsign,ou=globalsign root ca - r2
Creation date: Dec 15, 2006
Entry type: trustedCertEntry

-----BEGIN CERTIFICATE-----
Expand Down Expand Up @@ -135,8 +97,8 @@ TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
*******************************************


Alias name: ou=globalsignrootca-r3,o=globalsign,cn=globalsign
Creation date: Dec 1, 2023
Alias name: cn=globalsign,o=globalsign,ou=globalsign root ca - r3
Creation date: Mar 18, 2009
Entry type: trustedCertEntry

-----BEGIN CERTIFICATE-----
Expand Down Expand Up @@ -166,3 +128,41 @@ WD9f
*******************************************


Alias name: cn=verisign universal root certification authority,ou=(c) 2008 verisign\, inc. - for authorized use only,ou=verisign trust network,o=verisign\, inc.,c=us
Creation date: Apr 2, 2008
Entry type: trustedCertEntry

-----BEGIN CERTIFICATE-----
MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
7M2CYfE45k+XmCpajQ==
-----END CERTIFICATE-----


*******************************************
*******************************************


0 comments on commit f3b0139

Please sign in to comment.