Skip to content

martinpaljak/java-ssh-provider

Repository files navigation

SSHProvider.java

MIT licensed  Latest release  Maven version  Build status  Made in Estonia

The missing key management bridge between (Open)SSH and Java worlds. SSHProvider (a Java Security Provider) makes SSH keys, certificates and signatures first-class citizens in the Java ecosystem:

Reproducible 175K .jar with pure Java and zero 3rd party dependencies.

Tip

Sign easily with local hardware keys on remote machines with SSH agent forwarding ❤️

How to use

There is also a longer Tutorial (WIP).

Access keys in agent

Generate standard signatures with a key in hardware via $SSH_AUTH_SOCK

Note

Keys are reported by their public key fingerprint (same as shown by ssh-add -l) but can also be addressed by full public key/certificate string (as shown by ssh-add -L or available in a .pub file).

import com.hardssh.provider.SSHProvider;

Security.addProvider(new SSHProvider()); // Add the provider

KeyStore ks = KeyStore.getInstance("SSH"); // access $SSH_AUTH_SOCK

ks.load(null, null); // a password would send an "unlock" command to the agent (ssh-add -X)

// same output as "ssh-add -l"
for (String alias : Collections.list(ks.aliases())) {
    System.out.println(alias); // SHA256:5DmYCoIkCgEoOnbx3K+UXLhHVh8pX8GXgf7IS8i9QPo
}

String alias = "SHA256:5DmYCoIkCgEoOnbx3K+UXLhHVh8pX8GXgf7IS8i9QPo";

PrivateKey key = (PrivateKey) ks.getKey(alias);
Signature sig = Signature.getInstance("SHA256withECDSA");
sig.initSign(key);

// Continue as usual

Important

If a key has associated SSH certificate(s), a KeyStore.PrivateKeyEntry with key + certificate will be available with the hash of the certificate (unlike OpenSSH/ssh-add, which reports certificates with the fingerprint of the key). SSHProvider supports multiple certificates per key. Certificates without an available private key will not be available via KeyStore.

Verify a SSHSIG signature created with OpenSSH

After signing a file ($ echo 'Hello, World!' > /tmp/helloworld.txt) with OpenSSH:

$ ssh-keygen -t ed25519 -f /tmp/id_ed25519 -N '' -C 'Test key'
$ ssh-keygen -Y sign -n file -f /tmp/id_ed25519 /tmp/helloworld.txt

Verify it with Java (or vice-versa):

PublicKey pub = SSHIdentity.fromPath(Paths.get("/tmp/id_ed25519.pub"));
byte[] signature = SSHSIG.fromArmored(Paths.get("/tmp/helloworld.txt.sig"));
Signature sig = Signature.getInstance("SSHSIG");
sig.setParameter(new SSHSIGVerificationSpec("file"));
sig.initVerify(pub);
sig.update(Files.readAllBytes(Paths.get("/tmp/helloworld.txt")))
Assert.assertTrue(sig.verify(signature));

Supported algorithms

Note

Supported key types are Ed25519, ECDSA, RSA and FIDO with Ed25519 and ECDSA. DSA keys are actively rejected.

  • KeyStore SSH
  • Signature Ed25519 (sign, agent only)
  • Signature SHA256withECDSA (sign, agent only)
  • Signature SHA384withECDSA (sign, agent only)
  • Signature SHA512withECDSA (sign, agent only)
  • Signature SHA256withRSA (sign, agent only)
  • Signature SHA512withRSA (sign, agent only)
  • Signature ssh-ed25519 (sign, verify)
  • Signature ssh-ecdsa-nistp256 (sign, verify)
  • Signature ssh-ecdsa-nistp384 (sign, verify)
  • Signature ssh-ecdsa-nistp521 (sign, verify)
  • Signature rsa-sha2-256 (sign, verify)
  • Signature rsa-sha2-512 (sign, verify)
  • Signature [email protected] (sign (agent only), verify)
  • Signature [email protected] (sign (agent only), verify)
  • Signature [email protected] (verify)
  • Signature SSHSIG (sign, verify)
  • CertificateFactory SSH
  • KeyFactory SSH
  • OpenSSHPublicKeySpec (to/from OpenSSH string format (~/.ssh/*.pub))

Installation

Important

Requires Java 21+ and currently targeting unices only. Source publish pending on final package re-structuring and cleanups. com.hardssh.provider.SSHProvider is here to stay.

With Maven:

<repositories>
    <repository>
        <id>javacard-pro</id>
        <url>https://mvn.javacard.pro/maven/</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>com.github.martinpaljak</groupId>
        <artifactId>sshprovider</artifactId>
        <version>25.02.21</version>
    </dependency>
</dependencies>

Agents

Tip

SSHProvider does not implement or handle plaintext private keys in any form by design.

If you really have to work with your plaintext keys from ~/.ssh, add them to the standard OpenSSH ssh-agent.

SSHProvider is regularly tested with and works seamlessly with:

Other Java/SSH projects

SSHProvider was not created in vacuum, there is other software available.

Nothing from the existing open source universe fitted the approach and requirements for building HardSSH, thus SSHProvider was born as a minimal and fresh cleanroom implementation for modern Java. The Security Provider builds upon the SSH agent code in YAUSA, but is published and packaged separately, due to its generic and re-usable nature.

It reflects on quarter century of pain experience agony with smart cards, secure elements and hardware cryptography. Please don't ask about PKCS#11 (which you can use via OpenSSH ssh-agent).