Skip to content

Commit

Permalink
fixes apache#6909 ssh: extend test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
JiriOndrusek committed Jan 16, 2025
1 parent ded8081 commit 90b72ed
Show file tree
Hide file tree
Showing 12 changed files with 706 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,18 @@

import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.IndexDependencyBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageProxyDefinitionBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import net.i2p.crypto.eddsa.EdDSAEngine;
import org.apache.sshd.common.channel.ChannelListener;
import org.apache.sshd.common.forward.PortForwardingEventListener;
import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
import org.apache.sshd.common.session.SessionListener;
import org.jboss.jandex.IndexView;

class SshProcessor {

Expand All @@ -51,9 +55,10 @@ void registerForReflection(BuildProducer<ReflectiveClassBuildItem> reflectiveCla
KeyAgreement.class,
KeyFactory.class,
Signature.class,
Mac.class).methods().build());
reflectiveClasses.produce(
ReflectiveClassBuildItem.builder(Nio2ServiceFactoryFactory.class).build());
Mac.class,
Nio2ServiceFactoryFactory.class,
EdDSAEngine.class,
net.i2p.crypto.eddsa.KeyFactory.class).methods().build());
}

@BuildStep
Expand All @@ -71,4 +76,22 @@ void sessionProxy(BuildProducer<NativeImageProxyDefinitionBuildItem> proxiesProd
}
}

@BuildStep
ReflectiveClassBuildItem registerForReflection(CombinedIndexBuildItem combinedIndex) {
IndexView index = combinedIndex.getIndex();

String[] dtos = index.getKnownClasses().stream()
.map(ci -> ci.name().toString())
.filter(n -> n.startsWith("org.bouncycastle.crypto.signers.Ed25519"))
.sorted()
.toArray(String[]::new);

return ReflectiveClassBuildItem.builder(dtos).methods().fields().build();
}

@BuildStep
IndexDependencyBuildItem registerDependencyForIndex2() {
return new IndexDependencyBuildItem("org.bouncycastle", "bcprov-jdk18on");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.quarkus.component.ssh.runtime;

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAKey;
import net.i2p.crypto.eddsa.EdDSAPublicKey;

/**
* We're substituting those offending methods that would require the presence of
* net.i2p.crypto:eddsa library which is not supported by Camel SSH component
*/
@TargetClass(EdDSAEngine.class)
final class SubstituteEdDSAEngine {

@Alias
private MessageDigest digest;

@Alias
private EdDSAKey key;

@Alias
private void reset() {
}

@Substitute
protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
reset();
if (publicKey instanceof EdDSAPublicKey) {
key = (EdDSAPublicKey) publicKey;

if (digest == null) {
// Instantiate the digest from the key parameters
try {
digest = MessageDigest.getInstance(key.getParams().getHashAlgorithm());
} catch (NoSuchAlgorithmException e) {
throw new InvalidKeyException(
"cannot get required digest " + key.getParams().getHashAlgorithm() + " for private key.");
}
} else if (!key.getParams().getHashAlgorithm().equals(digest.getAlgorithm()))
throw new InvalidKeyException("Key hash algorithm does not match chosen digest");
} //following line differs from the original method
else if (publicKey.getFormat().equals("X.509")) {
// X509Certificate will sometimes contain an X509Key rather than the EdDSAPublicKey itself; the contained
// key is valid but needs to be instanced as an EdDSAPublicKey before it can be used.
EdDSAPublicKey parsedPublicKey;
try {
parsedPublicKey = new EdDSAPublicKey(new X509EncodedKeySpec(publicKey.getEncoded()));
} catch (InvalidKeySpecException ex) {
throw new InvalidKeyException("cannot handle X.509 EdDSA public key: " + publicKey.getAlgorithm());
}
engineInitVerify(parsedPublicKey);
} else {
throw new InvalidKeyException("cannot identify EdDSA public key: " + publicKey.getClass());
}
}
}

This file was deleted.

67 changes: 67 additions & 0 deletions integration-tests/ssh/generate-certs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


set -e
set -x

keyType="ed25519"

keySize=2048
days=10000
password="password"
encryptionAlgo="aes-256-cbc"


workDir="target/openssl-work"
destinationDir="target/classes/edDSA"

# see https://stackoverflow.com/a/54924640
export MSYS_NO_PATHCONV=1

if [[ -n "${JAVA_HOME}" ]] ; then
keytool="$JAVA_HOME/bin/keytool"
elif ! [[ -x "$(command -v keytool)" ]] ; then
echo 'Error: Either add keytool to PATH or set JAVA_HOME' >&2
exit 1
else
keytool="keytool"
fi

if ! [[ -x "$(command -v openssl)" ]] ; then
echo 'Error: openssl is not installed.' >&2
exit 1
fi

mkdir -p "$workDir"
mkdir -p "$destinationDir"

# Ed25519 private key
#openssl genpkey -algorithm ed25519 -out "$destinationDir/key_ed25519.pem"
ssh-keygen -t ed25519 -o -a 100 -N "" -f "$destinationDir/key_ed25519.pem" -C "test@localhost"


# Ed25519 public key
#openssl pkey -in "$destinationDir/key_ed25519.pem" -pubout -out "$destinationDir/key_ed25519.pem.pub"
ssh-keygen -y -f "$destinationDir/key_ed25519.pem" > "$destinationDir/key_ed25519.pem.pub"

#generate known-hosts
echo -n "127.0.0.1 $(sed 's/\(.*\) \([^ ]*\)$/\1/' "$destinationDir/key_ed25519.pem.pub")" >> "$destinationDir/known_hosts_eddsa"
#echo -n "127.0.0.1 ssh-ed25519 $(sed -e '1d' -e '$d' "$destinationDir/key_ed25519.pem.pub")" >> "$destinationDir/known_hosts_eddsa"


Loading

0 comments on commit 90b72ed

Please sign in to comment.