CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-elasticsearch--elasticsearch-ssl-config

SSL/TLS configuration library for Elasticsearch providing comprehensive security management utilities.

Pending
Overview
Eval results
Files

utilities.mddocs/

SSL Utilities

Comprehensive utility functions for keystore operations, PEM file parsing, certificate handling, SSL-related tasks, and low-level ASN.1/DER parsing with extensive validation and error handling.

Capabilities

KeyStore Utilities

Comprehensive utilities for keystore manipulation, type detection, and key/trust manager creation.

/**
 * Utility methods for working with KeyStore instances
 */
public final class KeyStoreUtil {
    /**
     * Infers keystore type from file path extension
     * @param path keystore file path
     * @return inferred keystore type (JKS, PKCS12, etc.)
     */
    public static String inferKeyStoreType(String path);
    
    /**
     * Reads a keystore from file with specified type and password
     * @param path path to keystore file
     * @param ksType keystore type (JKS, PKCS12, etc.)
     * @param password keystore password
     * @return loaded KeyStore instance
     * @throws GeneralSecurityException if keystore loading fails
     * @throws IOException if file reading fails
     */
    public static KeyStore readKeyStore(Path path, String ksType, char[] password) 
        throws GeneralSecurityException, IOException;
    
    /**
     * Builds a keystore from certificate chain and private key
     * @param certificateChain collection of certificates (first should be end entity)
     * @param privateKey private key corresponding to end entity certificate
     * @param password password for keystore and private key protection
     * @return KeyStore containing the certificate chain and private key
     * @throws GeneralSecurityException if keystore creation fails
     */
    public static KeyStore buildKeyStore(Collection<Certificate> certificateChain, 
                                        PrivateKey privateKey, char[] password) 
        throws GeneralSecurityException;
    
    /**
     * Filters keystore entries based on predicate
     * @param store original keystore
     * @param filter predicate to test keystore entries
     * @return new KeyStore containing only entries that match the filter
     */
    public static KeyStore filter(KeyStore store, Predicate<KeyStoreEntry> filter);
    
    /**
     * Builds a truststore from collection of certificates
     * @param certificates trusted certificates to include
     * @return KeyStore configured as truststore
     * @throws GeneralSecurityException if truststore creation fails
     */
    public static KeyStore buildTrustStore(Iterable<Certificate> certificates) 
        throws GeneralSecurityException;
    
    /**
     * Builds a truststore with specific type from certificates
     * @param certificates trusted certificates to include
     * @param type keystore type for truststore
     * @return KeyStore of specified type configured as truststore
     * @throws GeneralSecurityException if truststore creation fails
     */
    public static KeyStore buildTrustStore(Iterable<Certificate> certificates, String type) 
        throws GeneralSecurityException;
    
    /**
     * Creates key manager from certificate chain and private key
     * @param certificateChain certificate chain (end entity first)
     * @param privateKey private key for end entity certificate
     * @param password password for key protection
     * @return configured X509ExtendedKeyManager
     * @throws GeneralSecurityException if key manager creation fails
     * @throws IOException if certificate/key processing fails
     */
    public static X509ExtendedKeyManager createKeyManager(Certificate[] certificateChain, 
                                                         PrivateKey privateKey, char[] password) 
        throws GeneralSecurityException, IOException;
    
    /**
     * Creates key manager from keystore
     * @param keyStore keystore containing private keys and certificates
     * @param password password for private key access
     * @param algorithm key manager algorithm (e.g., "SunX509", "PKIX")
     * @return configured X509ExtendedKeyManager
     * @throws GeneralSecurityException if key manager creation fails
     */
    public static X509ExtendedKeyManager createKeyManager(KeyStore keyStore, char[] password, 
                                                         String algorithm) 
        throws GeneralSecurityException;
    
    /**
     * Creates trust manager from truststore
     * @param trustStore truststore containing trusted certificates (null for JDK defaults)
     * @param algorithm trust manager algorithm (e.g., "PKIX", "SunX509")
     * @return configured X509ExtendedTrustManager
     * @throws NoSuchAlgorithmException if algorithm is not available
     * @throws KeyStoreException if truststore access fails
     */
    public static X509ExtendedTrustManager createTrustManager(@Nullable KeyStore trustStore, 
                                                             String algorithm) 
        throws NoSuchAlgorithmException, KeyStoreException;
    
    /**
     * Creates trust manager from collection of certificates
     * @param certificates trusted certificates
     * @return configured X509ExtendedTrustManager
     * @throws GeneralSecurityException if trust manager creation fails
     */
    public static X509ExtendedTrustManager createTrustManager(Collection<Certificate> certificates) 
        throws GeneralSecurityException;
    
    /**
     * Creates stream of keystore entries for processing
     * @param keyStore keystore to stream
     * @param exceptionHandler function to handle GeneralSecurityException during streaming
     * @return Stream of KeyStoreEntry objects
     */
    public static Stream<KeyStoreEntry> stream(KeyStore keyStore, 
                                              Function<GeneralSecurityException, ? extends RuntimeException> exceptionHandler);
}

Usage Examples:

import org.elasticsearch.common.ssl.KeyStoreUtil;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.List;

// Infer keystore type
String type = KeyStoreUtil.inferKeyStoreType("keystore.p12"); // returns "PKCS12"
String jksType = KeyStoreUtil.inferKeyStoreType("keystore.jks"); // returns "JKS"

// Read keystore from file
KeyStore keystore = KeyStoreUtil.readKeyStore(
    Paths.get("/etc/ssl/keystore.p12"),
    "PKCS12",
    "password".toCharArray()
);

// Build keystore from certificates and key
Collection<Certificate> certChain = List.of(endEntityCert, intermediateCert);
KeyStore builtKeystore = KeyStoreUtil.buildKeyStore(
    certChain,
    privateKey,
    "password".toCharArray()
);

// Filter keystore entries
KeyStore filteredKeystore = KeyStoreUtil.filter(keystore, entry -> 
    entry.getAlias().startsWith("server-"));

// Build truststore from CA certificates
KeyStore truststore = KeyStoreUtil.buildTrustStore(caCertificates);

// Create key manager
X509ExtendedKeyManager keyManager = KeyStoreUtil.createKeyManager(
    certChain.toArray(new Certificate[0]),
    privateKey,
    "password".toCharArray()
);

// Create trust manager from certificates
X509ExtendedTrustManager trustManager = KeyStoreUtil.createTrustManager(caCertificates);

// Stream keystore entries
KeyStoreUtil.stream(keystore, ex -> new RuntimeException(ex))
    .filter(entry -> entry.isKeyEntry())
    .forEach(entry -> {
        System.out.println("Key alias: " + entry.getAlias());
        X509Certificate cert = entry.getX509Certificate();
        System.out.println("Subject: " + cert.getSubjectX500Principal());
    });

KeyStore Entry Wrapper

Wrapper class for individual keystore entries providing convenient access methods.

/**
 * Wrapper for individual keystore entries
 */
public static class KeyStoreEntry {
    /**
     * Gets the alias of this keystore entry
     * @return entry alias
     */
    public String getAlias();
    
    /**
     * Gets the certificate as X509Certificate
     * @return X509Certificate or null if not a certificate entry
     */
    public X509Certificate getX509Certificate();
    
    /**
     * Checks if this entry contains a private key
     * @return true if this is a key entry
     */
    public boolean isKeyEntry();
    
    /**
     * Gets the private key from this entry
     * @param password password for private key access
     * @return PrivateKey or null if not a key entry or wrong password
     */
    public PrivateKey getKey(char[] password);
    
    /**
     * Gets the certificate chain for this entry
     * @return list of certificates in the chain
     */
    public List<? extends X509Certificate> getX509CertificateChain();
    
    /**
     * Deletes this entry from the keystore
     */
    public void delete();
}

PEM Utilities

Utilities for parsing PEM formatted certificates and private keys with support for encrypted keys.

/**
 * Utilities for parsing PEM formatted certificates and private keys
 */
public final class PemUtils {
    /**
     * Reads private key from PEM file with optional password
     * @param path path to PEM private key file
     * @param passwordSupplier supplier for key password (called only if key is encrypted)
     * @return parsed PrivateKey
     * @throws IOException if file reading fails
     * @throws GeneralSecurityException if key parsing fails
     */
    public static PrivateKey readPrivateKey(Path path, Supplier<char[]> passwordSupplier) 
        throws IOException, GeneralSecurityException;
    
    /**
     * Parses PKCS#8 PEM formatted private key string
     * @param pemString PEM formatted private key string
     * @return parsed PrivateKey
     * @throws IOException if PEM parsing fails
     * @throws GeneralSecurityException if key parsing fails
     */
    public static PrivateKey parsePKCS8PemString(String pemString) 
        throws IOException, GeneralSecurityException;
    
    /**
     * Reads certificates from multiple PEM files
     * @param certPaths collection of paths to PEM certificate files
     * @return list of parsed certificates
     * @throws CertificateException if certificate parsing fails
     * @throws IOException if file reading fails
     */
    public static List<Certificate> readCertificates(Collection<Path> certPaths) 
        throws CertificateException, IOException;
}

Usage Examples:

import org.elasticsearch.common.ssl.PemUtils;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Supplier;

// Read unencrypted private key
PrivateKey privateKey = PemUtils.readPrivateKey(
    Paths.get("/etc/ssl/private/server.key"),
    () -> null  // no password needed
);

// Read encrypted private key
PrivateKey encryptedKey = PemUtils.readPrivateKey(
    Paths.get("/etc/ssl/private/encrypted.key"),
    () -> "secret123".toCharArray()  // provide password when needed
);

// Read encrypted key with interactive password prompt
PrivateKey interactiveKey = PemUtils.readPrivateKey(
    Paths.get("/etc/ssl/private/secure.key"),
    () -> {
        System.out.print("Enter key password: ");
        return System.console().readPassword();
    }
);

// Parse PEM string directly
String pemKeyString = """
    -----BEGIN PRIVATE KEY-----
    MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
    -----END PRIVATE KEY-----
    """;
PrivateKey parsedKey = PemUtils.parsePKCS8PemString(pemKeyString);

// Read multiple certificate files
List<Certificate> certificates = PemUtils.readCertificates(List.of(
    Paths.get("/etc/ssl/certs/ca.pem"),
    Paths.get("/etc/ssl/certs/intermediate.pem"),
    Paths.get("/etc/ssl/certs/server.pem")
));

// Read certificate chain from single file
List<Certificate> certChain = PemUtils.readCertificates(List.of(
    Paths.get("/etc/ssl/certs/fullchain.pem")  // file with multiple certificates
));

SSL Utilities

General SSL-related utility methods for certificate operations.

/**
 * SSL-related utility methods
 */
public final class SslUtil {
    /**
     * Calculates certificate fingerprint using specified algorithm
     * @param certificate X509 certificate to fingerprint
     * @param algorithm hash algorithm (e.g., "SHA-256", "SHA-1", "MD5")
     * @return hex-encoded fingerprint string
     * @throws CertificateEncodingException if certificate encoding fails
     */
    public static String calculateFingerprint(X509Certificate certificate, String algorithm) 
        throws CertificateEncodingException;
}

Usage Examples:

import org.elasticsearch.common.ssl.SslUtil;
import java.security.cert.X509Certificate;

// Calculate SHA-256 fingerprint
String sha256Fingerprint = SslUtil.calculateFingerprint(certificate, "SHA-256");
System.out.println("SHA-256: " + sha256Fingerprint);

// Calculate SHA-1 fingerprint
String sha1Fingerprint = SslUtil.calculateFingerprint(certificate, "SHA-1");
System.out.println("SHA-1: " + sha1Fingerprint);

// Calculate MD5 fingerprint (less secure, for compatibility)
String md5Fingerprint = SslUtil.calculateFingerprint(certificate, "MD5");
System.out.println("MD5: " + md5Fingerprint);

DER Parser

Minimal ASN.1 DER decoder for PKCS#1 private keys, providing low-level parsing capabilities.

/**
 * Minimal ASN.1 DER decoder for PKCS#1 private keys
 */
public final class DerParser {
    /**
     * Creates DER parser for byte array
     * @param bytes DER encoded bytes to parse
     */
    public DerParser(byte[] bytes);
    
    /**
     * Reads ASN.1 object with required type check
     * @param requiredType expected ASN.1 type constant
     * @return parsed ASN.1 object
     * @throws IOException if parsing fails or type doesn't match
     */
    public Asn1Object readAsn1Object(int requiredType) throws IOException;
    
    /**
     * Reads next ASN.1 object without type checking
     * @return parsed ASN.1 object
     * @throws IOException if parsing fails
     */
    public Asn1Object readAsn1Object() throws IOException;
}

ASN.1 Object Wrapper

Wrapper for parsed ASN.1 objects with convenient access methods.

/**
 * Wrapper for parsed ASN.1 objects
 */
public static class Asn1Object {
    /**
     * Gets the ASN.1 type tag
     * @return type tag value
     */
    public int getType();
    
    /**
     * Gets the content length
     * @return content length in bytes
     */
    public int getLength();
    
    /**
     * Gets the raw content bytes
     * @return content byte array
     */
    public byte[] getValue();
    
    /**
     * Checks if this is a constructed (composite) object
     * @return true if constructed
     */
    public boolean isConstructed();
    
    /**
     * Gets parser for nested content (if constructed)
     * @return DerParser for nested content
     * @throws IOException if not constructed or parsing fails
     */
    public DerParser getParser() throws IOException;
    
    /**
     * Interprets content as integer value
     * @return BigInteger value
     * @throws IOException if content is not a valid integer
     */
    public BigInteger getInteger() throws IOException;
    
    /**
     * Interprets content as string value
     * @return string value
     * @throws IOException if content is not a valid string
     */
    public String getString() throws IOException;
    
    /**
     * Interprets content as object identifier (OID)
     * @return OID string (e.g., "1.2.840.113549.1.1.1")
     * @throws IOException if content is not a valid OID
     */
    public String getOid() throws IOException;
}

ASN.1 Type Constants

Constants for ASN.1 type identification.

/**
 * ASN.1 type constants
 */
public static class Type {
    public static final int INTEGER = 0x02;
    public static final int OCTET_STRING = 0x04;
    public static final int OBJECT_OID = 0x06;
    public static final int SEQUENCE = 0x30;
    // Additional type constants...
}

Usage Examples:

import org.elasticsearch.common.ssl.DerParser;
import org.elasticsearch.common.ssl.DerParser.Asn1Object;
import org.elasticsearch.common.ssl.DerParser.Type;
import java.math.BigInteger;

// Parse DER encoded private key
byte[] derBytes = // ... DER encoded PKCS#1 private key bytes
DerParser parser = new DerParser(derBytes);

// Read outer SEQUENCE
Asn1Object sequence = parser.readAsn1Object(Type.SEQUENCE);
DerParser seqParser = sequence.getParser();

// Read version (INTEGER)
Asn1Object version = seqParser.readAsn1Object(Type.INTEGER);
BigInteger versionNum = version.getInteger();

// Read modulus (large INTEGER)
Asn1Object modulus = seqParser.readAsn1Object(Type.INTEGER);
BigInteger modulusValue = modulus.getInteger();

// Continue parsing other RSA private key components...

Utility Patterns

Keystore Type Detection

The library automatically detects keystore types:

// File extensions mapped to keystore types:
// .jks -> JKS
// .p12, .pfx -> PKCS12
// .bks -> BKS
// others -> JKS (default)

String type = KeyStoreUtil.inferKeyStoreType("mystore.p12"); // "PKCS12"

Certificate Chain Validation

When building keystores, ensure proper certificate chain ordering:

// Correct order: end entity certificate first, then intermediates, then root
List<Certificate> chainInOrder = List.of(
    endEntityCert,      // certificate for private key
    intermediateCert,   // intermediate CA
    rootCert           // root CA (optional)
);

KeyStore keystore = KeyStoreUtil.buildKeyStore(chainInOrder, privateKey, password);

PEM File Handling

The PEM utilities handle various PEM formats:

// Supports multiple certificate formats:
// - Single certificate per file
// - Multiple certificates in one file (certificate chains)
// - Mixed certificate and key files (certificates only extracted)

// Supports multiple private key formats:
// - PKCS#8 (-----BEGIN PRIVATE KEY-----)
// - PKCS#8 encrypted (-----BEGIN ENCRYPTED PRIVATE KEY-----)
// - Legacy RSA format (-----BEGIN RSA PRIVATE KEY-----)

Install with Tessl CLI

npx tessl i tessl/maven-org-elasticsearch--elasticsearch-ssl-config

docs

configuration.md

diagnostics.md

enums-types.md

index.md

key-management.md

trust-management.md

utilities.md

tile.json