I think your forgot to commit the changes to a few files: KeyUtils,
KeyPairProvider

Le dim. 19 avr. 2020 à 18:00, <lgoldst...@apache.org> a écrit :

> This is an automated email from the ASF dual-hosted git repository.
>
> lgoldstein pushed a commit to branch master
> in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
>
> commit 47f779f06cb345c7cb706cb81f1214c37dab1fda
> Author: FliegenKLATSCH <ch...@koras.de>
> AuthorDate: Wed Apr 8 21:18:40 2020 +0200
>
>     [SSHD-660] Add support for serer side openssh host certkeys
> ---
>  .../org/apache/sshd/cli/server/SshServerMain.java  |  15 ++
>  .../apache/sshd/common/config/keys/KeyUtils.java   |   8 +
>  .../common/config/keys/OpenSshCertificate.java     |  63 +++++++
>  .../common/config/keys/OpenSshCertificateImpl.java | 210
> +++++++++++++++++++++
>  .../keys/impl/OpenSSHCertificateDecoder.java       | 118 ++++++++++++
>  .../FileHostKeyCertificateProvider.java            | 102 ++++++++++
>  .../keyprovider/HostKeyCertificateProvider.java    |  32 ++++
>  .../sshd/common/keyprovider/KeyPairProvider.java   |  14 +-
>  .../sshd/common/signature/BuiltinSignatures.java   |  88 +++++++++
>  .../sshd/common/signature/SignatureFactory.java    |   2 +-
>  .../apache/sshd/common/signature/SignatureRSA.java |   4 +-
>  .../org/apache/sshd/common/util/buffer/Buffer.java |  34 +++-
>  .../sshd/common/util/buffer/ByteArrayBuffer.java   |   7 +
>  .../util/buffer/keys/BufferPublicKeyParser.java    |   1 +
>  .../buffer/keys/OpenSSHCertPublicKeyParser.java    |  89 +++++++++
>  .../security/eddsa/EdDSASecurityProviderUtils.java |   2 -
>  .../util/security/eddsa/EDDSAProviderTest.java     |   4 +-
>  .../java/org/apache/sshd/client/ClientBuilder.java |   6 +
>  .../apache/sshd/client/ClientFactoryManager.java   |   6 +
>  .../java/org/apache/sshd/client/kex/DHGClient.java | 105 ++++++++++-
>  .../sshd/client/session/AbstractClientSession.java |  27 ++-
>  .../java/org/apache/sshd/server/ServerBuilder.java |   8 +
>  .../apache/sshd/server/ServerFactoryManager.java   |   6 +
>  .../java/org/apache/sshd/server/SshServer.java     |  11 ++
>  .../sshd/server/config/keys/ServerIdentity.java    |  23 ++-
>  .../java/org/apache/sshd/server/kex/DHGServer.java |   1 +
>  .../sshd/server/session/AbstractServerSession.java |  43 ++++-
>  .../common/signature/OpenSSHCertificateTest.java   | 161 ++++++++++++++++
>  .../org/apache/sshd/common/signature/example-ca    |  49 +++++
>  .../apache/sshd/common/signature/example-ca.pub    |   1 +
>  .../apache/sshd/common/signature/ssh_host_rsa_key  |  38 ++++
>  .../common/signature/ssh_host_rsa_key-cert.pub     |   1 +
>  .../sshd/common/signature/ssh_host_rsa_key.pub     |   1 +
>  .../signature/ssh_host_rsa_key_sha1-cert.pub       |   1 +
>  34 files changed, 1259 insertions(+), 22 deletions(-)
>
> diff --git
> a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
> b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
> index 321ae1e..c0f42ac 100644
> --- a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
> +++ b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
> @@ -19,6 +19,7 @@
>
>  package org.apache.sshd.cli.server;
>
> +import java.nio.file.Paths;
>  import java.util.Collection;
>  import java.util.LinkedList;
>  import java.util.List;
> @@ -26,12 +27,15 @@ import java.util.Map;
>  import java.util.Objects;
>  import java.util.TreeMap;
>  import java.util.logging.Level;
> +import java.util.stream.Collectors;
>
>  import org.apache.sshd.common.NamedResource;
>  import org.apache.sshd.common.PropertyResolver;
>  import org.apache.sshd.common.PropertyResolverUtils;
>  import org.apache.sshd.common.config.ConfigFileReaderSupport;
>  import org.apache.sshd.common.config.SshConfigFileReader;
> +import org.apache.sshd.common.keyprovider.FileHostKeyCertificateProvider;
> +import org.apache.sshd.common.keyprovider.HostKeyCertificateProvider;
>  import org.apache.sshd.common.keyprovider.KeyPairProvider;
>  import org.apache.sshd.common.util.GenericUtils;
>  import org.apache.sshd.server.SshServer;
> @@ -62,6 +66,7 @@ public class SshServerMain extends SshServerCliSupport {
>          String hostKeyType =
> AbstractGeneratorHostKeyProvider.DEFAULT_ALGORITHM;
>          int hostKeySize = 0;
>          Collection<String> keyFiles = null;
> +        Collection<String> certFiles = null;
>          Map<String, Object> options = new
> TreeMap<>(String.CASE_INSENSITIVE_ORDER);
>
>          int numArgs = GenericUtils.length(args);
> @@ -140,6 +145,11 @@ public class SshServerMain extends
> SshServerCliSupport {
>                          keyFiles = new LinkedList<>();
>                      }
>                      keyFiles.add(optValue);
> +                } else if
> (ServerIdentity.HOST_CERT_CONFIG_PROP.equals(optName)) {
> +                    if (certFiles == null) {
> +                        certFiles = new LinkedList<>();
> +                    }
> +                    certFiles.add(optValue);
>                  } else if
> (ConfigFileReaderSupport.PORT_CONFIG_PROP.equals(optName)) {
>                      port = Integer.parseInt(optValue);
>                  } else {
> @@ -171,6 +181,11 @@ public class SshServerMain extends
> SshServerCliSupport {
>          KeyPairProvider hostKeyProvider =
>              resolveServerKeys(System.err, hostKeyType, hostKeySize,
> keyFiles);
>          sshd.setKeyPairProvider(hostKeyProvider);
> +        if (certFiles != null) {
> +            HostKeyCertificateProvider certProvider = new
> FileHostKeyCertificateProvider(
> +
> certFiles.stream().map(Paths::get).collect(Collectors.toList()));
> +            sshd.setHostKeyCertificateProvider(certProvider);
> +        }
>          // Should come AFTER key pair provider setup so auto-welcome can
> be generated if needed
>          setupServerBanner(sshd, resolver);
>          sshd.setPort(port);
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
> b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
> index 37f4051..fd89f9e 100644
> ---
> a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyUtils.java
> @@ -68,6 +68,7 @@ import org.apache.sshd.common.Factory;
>  import org.apache.sshd.common.cipher.ECCurves;
>  import org.apache.sshd.common.config.keys.impl.DSSPublicKeyEntryDecoder;
>  import org.apache.sshd.common.config.keys.impl.ECDSAPublicKeyEntryDecoder;
> +import org.apache.sshd.common.config.keys.impl.OpenSSHCertificateDecoder;
>  import org.apache.sshd.common.config.keys.impl.RSAPublicKeyDecoder;
>  import
> org.apache.sshd.common.config.keys.impl.SkECDSAPublicKeyEntryDecoder;
>  import
> org.apache.sshd.common.config.keys.impl.SkED25519PublicKeyEntryDecoder;
> @@ -140,6 +141,8 @@ public final class KeyUtils {
>      /** @see <A HREF="">https://tools.ietf.org/html/rfc8332#section-3</A>
> */
>      public static final String RSA_SHA256_KEY_TYPE_ALIAS = "rsa-sha2-256";
>      public static final String RSA_SHA512_KEY_TYPE_ALIAS = "rsa-sha2-512";
> +    public static final String RSA_SHA256_CERT_TYPE_ALIAS = "
> rsa-sha2-256-cert-...@openssh.com";
> +    public static final String RSA_SHA512_CERT_TYPE_ALIAS = "
> rsa-sha2-512-cert-...@openssh.com";
>
>      private static final AtomicReference<DigestFactory>
> DEFAULT_DIGEST_HOLDER = new AtomicReference<>();
>
> @@ -153,9 +156,12 @@ public final class KeyUtils {
>          NavigableMapBuilder.<String,
> String>builder(String.CASE_INSENSITIVE_ORDER)
>              .put(RSA_SHA256_KEY_TYPE_ALIAS, KeyPairProvider.SSH_RSA)
>              .put(RSA_SHA512_KEY_TYPE_ALIAS, KeyPairProvider.SSH_RSA)
> +            .put(RSA_SHA256_CERT_TYPE_ALIAS, KeyPairProvider.SSH_RSA_CERT)
> +            .put(RSA_SHA512_CERT_TYPE_ALIAS, KeyPairProvider.SSH_RSA_CERT)
>              .build();
>
>      static {
> +        registerPublicKeyEntryDecoder(OpenSSHCertificateDecoder.INSTANCE);
>          registerPublicKeyEntryDecoder(RSAPublicKeyDecoder.INSTANCE);
>          registerPublicKeyEntryDecoder(DSSPublicKeyEntryDecoder.INSTANCE);
>
> @@ -800,6 +806,8 @@ public final class KeyUtils {
>              }
>          } else if
> (SecurityUtils.EDDSA.equalsIgnoreCase(key.getAlgorithm())) {
>              return KeyPairProvider.SSH_ED25519;
> +        } else if (key instanceof OpenSshCertificate) {
> +            return ((OpenSshCertificate) key).getKeyType();
>          }
>
>          return null;
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificate.java
> b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificate.java
> new file mode 100644
> index 0000000..9fa7d5a
> --- /dev/null
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificate.java
> @@ -0,0 +1,63 @@
> +/*
> + * 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.sshd.common.config.keys;
> +
> +import java.security.PrivateKey;
> +import java.security.PublicKey;
> +import java.util.Collection;
> +import java.util.List;
> +
> +public interface OpenSshCertificate extends PublicKey, PrivateKey {
> +    int SSH_CERT_TYPE_USER = 1;
> +    int SSH_CERT_TYPE_HOST = 2;
> +
> +    String getRawKeyType();
> +
> +    byte[] getNonce();
> +
> +    String getKeyType();
> +
> +    PublicKey getServerHostKey();
> +
> +    long getSerial();
> +
> +    int getType();
> +
> +    String getId();
> +
> +    Collection<String> getPrincipals();
> +
> +    long getValidAfter();
> +
> +    long getValidBefore();
> +
> +    List<String> getCriticalOptions();
> +
> +    List<String> getExtensions();
> +
> +    String getReserved();
> +
> +    PublicKey getCaPubKey();
> +
> +    byte[] getMessage();
> +
> +    byte[] getSignature();
> +
> +    String getSignatureAlg();
> +}
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificateImpl.java
> b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificateImpl.java
> new file mode 100644
> index 0000000..3af92ea
> --- /dev/null
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificateImpl.java
> @@ -0,0 +1,210 @@
> +/*
> + * 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.sshd.common.config.keys;
> +
> +import java.security.PublicKey;
> +import java.util.Collection;
> +import java.util.List;
> +
> +import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
> +
> +public class OpenSshCertificateImpl implements OpenSshCertificate {
> +
> +    private static final long serialVersionUID = -3592634724148744943L;
> +
> +    private String keyType;
> +    private byte[] nonce;
> +    private PublicKey serverHostKey;
> +    private long serial;
> +    private int type;
> +    private String id;
> +    private Collection<String> principals;
> +    private long validAfter;
> +    private long validBefore;
> +    private List<String> criticalOptions;
> +    private List<String> extensions;
> +    private String reserved;
> +    private PublicKey caPubKey;
> +    private byte[] message;
> +    private byte[] signature;
> +
> +    public OpenSshCertificateImpl() {
> +        super();
> +    }
> +
> +    @Override
> +    public String getRawKeyType() {
> +        return keyType.split("@")[0].substring(0,
> keyType.indexOf("-cert"));
> +    }
> +
> +    @Override
> +    public byte[] getNonce() {
> +        return nonce;
> +    }
> +
> +    @Override
> +    public String getKeyType() {
> +        return keyType;
> +    }
> +
> +    @Override
> +    public PublicKey getServerHostKey() {
> +        return serverHostKey;
> +    }
> +
> +    @Override
> +    public long getSerial() {
> +        return serial;
> +    }
> +
> +    @Override
> +    public int getType() {
> +        return type;
> +    }
> +
> +    @Override
> +    public String getId() {
> +        return id;
> +    }
> +
> +    @Override
> +    public Collection<String> getPrincipals() {
> +        return principals;
> +    }
> +
> +    @Override
> +    public long getValidAfter() {
> +        return validAfter;
> +    }
> +
> +    @Override
> +    public long getValidBefore() {
> +        return validBefore;
> +    }
> +
> +    @Override
> +    public List<String> getCriticalOptions() {
> +        return criticalOptions;
> +    }
> +
> +    @Override
> +    public List<String> getExtensions() {
> +        return extensions;
> +    }
> +
> +    @Override
> +    public String getReserved() {
> +        return reserved;
> +    }
> +
> +    @Override
> +    public PublicKey getCaPubKey() {
> +        return caPubKey;
> +    }
> +
> +    @Override
> +    public byte[] getMessage() {
> +        return message;
> +    }
> +
> +    @Override
> +    public byte[] getSignature() {
> +        return signature;
> +    }
> +
> +    @Override
> +    public String getSignatureAlg() {
> +        return new ByteArrayBuffer(signature).getString();
> +    }
> +
> +    @Override
> +    public String getAlgorithm() {
> +        return null;
> +    }
> +
> +    @Override
> +    public String getFormat() {
> +        return null;
> +    }
> +
> +    @Override
> +    public byte[] getEncoded() {
> +        return new byte[0];
> +    }
> +
> +    public void setKeyType(String keyType) {
> +        this.keyType = keyType;
> +    }
> +
> +    public void setNonce(byte[] nonce) {
> +        this.nonce = nonce;
> +    }
> +
> +    public void setServerHostKey(PublicKey serverHostKey) {
> +        this.serverHostKey = serverHostKey;
> +    }
> +
> +    public void setSerial(long serial) {
> +        this.serial = serial;
> +    }
> +
> +    public void setType(int type) {
> +        this.type = type;
> +    }
> +
> +    public void setId(String id) {
> +        this.id = id;
> +    }
> +
> +    public void setPrincipals(Collection<String> principals) {
> +        this.principals = principals;
> +    }
> +
> +    public void setValidAfter(long validAfter) {
> +        this.validAfter = validAfter;
> +    }
> +
> +    public void setValidBefore(long validBefore) {
> +        this.validBefore = validBefore;
> +    }
> +
> +    public void setCriticalOptions(List<String> criticalOptions) {
> +        this.criticalOptions = criticalOptions;
> +    }
> +
> +    public void setExtensions(List<String> extensions) {
> +        this.extensions = extensions;
> +    }
> +
> +    public void setReserved(String reserved) {
> +        this.reserved = reserved;
> +    }
> +
> +    public void setCaPubKey(PublicKey caPubKey) {
> +        this.caPubKey = caPubKey;
> +    }
> +
> +    public void setMessage(byte[] message) {
> +        this.message = message;
> +    }
> +
> +    public void setSignature(byte[] signature) {
> +        this.signature = signature;
> +    }
> +}
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/OpenSSHCertificateDecoder.java
> b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/OpenSSHCertificateDecoder.java
> new file mode 100644
> index 0000000..1e26aa8
> --- /dev/null
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/impl/OpenSSHCertificateDecoder.java
> @@ -0,0 +1,118 @@
> +/*
> + * 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.sshd.common.config.keys.impl;
> +
> +import java.io.ByteArrayInputStream;
> +import java.io.ByteArrayOutputStream;
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.io.OutputStream;
> +import java.security.GeneralSecurityException;
> +import java.security.KeyFactory;
> +import java.security.KeyPairGenerator;
> +import java.util.Arrays;
> +import java.util.Collections;
> +import java.util.Map;
> +import java.util.Objects;
> +
> +import org.apache.sshd.common.config.keys.KeyUtils;
> +import org.apache.sshd.common.config.keys.OpenSshCertificate;
> +import org.apache.sshd.common.keyprovider.KeyPairProvider;
> +import org.apache.sshd.common.session.SessionContext;
> +import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
> +import org.apache.sshd.common.util.buffer.keys.OpenSSHCertPublicKeyParser;
> +import org.apache.sshd.common.util.io.IoUtils;
> +
> +/**
> + * @author <a href="mailto:dev@mina.apache.org";>Apache MINA SSHD
> Project</a>
> + */
> +public class OpenSSHCertificateDecoder extends
> AbstractPublicKeyEntryDecoder<OpenSshCertificate, OpenSshCertificate> {
> +    public static final OpenSSHCertificateDecoder INSTANCE = new
> OpenSSHCertificateDecoder();
> +
> +    public OpenSSHCertificateDecoder() {
> +        super(OpenSshCertificate.class, OpenSshCertificate.class,
> +                Collections.unmodifiableList(Arrays.asList(
> +                        KeyUtils.RSA_SHA256_CERT_TYPE_ALIAS,
> +                        KeyUtils.RSA_SHA512_CERT_TYPE_ALIAS,
> +                        KeyPairProvider.SSH_RSA_CERT,
> +                        KeyPairProvider.SSH_DSS_CERT,
> +                        KeyPairProvider.SSH_ED25519_CERT,
> +                        KeyPairProvider.SSH_ECDSA_SHA2_NISTP256_CERT,
> +                        KeyPairProvider.SSH_ECDSA_SHA2_NISTP384_CERT,
> +                        KeyPairProvider.SSH_ECDSA_SHA2_NISTP521_CERT
> +                )));
> +    }
> +
> +    @Override
> +    public OpenSshCertificate decodePublicKey(
> +            SessionContext session, String keyType, InputStream keyData,
> Map<String, String> headers)
> +            throws IOException, GeneralSecurityException {
> +
> +        byte[] bytes = IoUtils.toByteArray(keyData);
> +
> +        ByteArrayBuffer buffer = new ByteArrayBuffer(bytes);
> +
> +        OpenSshCertificate cert = (OpenSshCertificate)
> OpenSSHCertPublicKeyParser.INSTANCE.getRawPublicKey(keyType, buffer);
> +
> +        if (cert.getType() != OpenSshCertificate.SSH_CERT_TYPE_HOST) {
> +            throw new GeneralSecurityException("The provided certificate
> is not a Host certificate.");
> +        }
> +
> +        return cert;
> +    }
> +
> +    @Override
> +    public String encodePublicKey(OutputStream s, OpenSshCertificate key)
> throws IOException {
> +        Objects.requireNonNull(key, "No public key provided");
> +
> +        ByteArrayBuffer buffer = new ByteArrayBuffer();
> +        buffer.putRawPublicKeyBytes(key);
> +        s.write(buffer.getCompactData());
> +
> +        return key.getKeyType();
> +    }
> +
> +    @Override
> +    public OpenSshCertificate clonePublicKey(OpenSshCertificate key)
> throws GeneralSecurityException {
> +        try (ByteArrayOutputStream outStream = new
> ByteArrayOutputStream()) {
> +            String keyType = encodePublicKey(outStream, key);
> +            try (InputStream inStream = new
> ByteArrayInputStream(outStream.toByteArray())) {
> +                return decodePublicKey(null, keyType, inStream, null);
> +            }
> +        } catch (IOException e) {
> +            throw new GeneralSecurityException("Unable to clone key.", e);
> +        }
> +    }
> +
> +    @Override
> +    public OpenSshCertificate clonePrivateKey(OpenSshCertificate key)
> throws GeneralSecurityException {
> +        return clonePublicKey(key);
> +    }
> +
> +    @Override
> +    public KeyPairGenerator getKeyPairGenerator() throws
> GeneralSecurityException {
> +        return null;
> +    }
> +
> +    @Override
> +    public KeyFactory getKeyFactoryInstance() throws
> GeneralSecurityException {
> +        return null;
> +    }
> +}
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileHostKeyCertificateProvider.java
> b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileHostKeyCertificateProvider.java
> new file mode 100644
> index 0000000..0c9b8b1
> --- /dev/null
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileHostKeyCertificateProvider.java
> @@ -0,0 +1,102 @@
> +/*
> + * 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.sshd.common.keyprovider;
> +
> +import java.io.IOException;
> +import java.nio.charset.StandardCharsets;
> +import java.nio.file.Files;
> +import java.nio.file.Path;
> +import java.security.GeneralSecurityException;
> +import java.security.InvalidKeyException;
> +import java.security.PublicKey;
> +import java.util.ArrayList;
> +import java.util.Arrays;
> +import java.util.Collection;
> +import java.util.Collections;
> +import java.util.List;
> +import java.util.Objects;
> +import java.util.stream.StreamSupport;
> +
> +import org.apache.sshd.common.config.keys.OpenSshCertificate;
> +import org.apache.sshd.common.config.keys.PublicKeyEntry;
> +import org.apache.sshd.common.session.SessionContext;
> +import org.apache.sshd.common.util.GenericUtils;
> +import org.apache.sshd.common.util.ValidateUtils;
> +import org.apache.sshd.common.util.logging.AbstractLoggingBean;
> +
> +public class FileHostKeyCertificateProvider extends AbstractLoggingBean
> implements HostKeyCertificateProvider {
> +    private Collection<? extends Path> files;
> +
> +    public FileHostKeyCertificateProvider() {
> +        super();
> +    }
> +
> +    public FileHostKeyCertificateProvider(Path path) {
> +        this(Collections.singletonList(Objects.requireNonNull(path, "No
> path provided")));
> +    }
> +
> +    public FileHostKeyCertificateProvider(Path... files) {
> +        this(Arrays.asList(ValidateUtils.checkNotNullAndNotEmpty(files,
> "No path provided")));
> +    }
> +
> +    public FileHostKeyCertificateProvider(Collection<? extends Path>
> files) {
> +        this.files = files;
> +    }
> +
> +    public Collection<? extends Path> getPaths() {
> +        return files;
> +    }
> +
> +    @Override
> +    public Iterable<OpenSshCertificate> loadCertificates(SessionContext
> session) throws IOException, GeneralSecurityException {
> +
> +        List<OpenSshCertificate> certificates = new ArrayList<>();
> +        for (Path file : files) {
> +            List<String> lines = Files.readAllLines(file,
> StandardCharsets.UTF_8);
> +            for (String line : lines) {
> +                line = GenericUtils.replaceWhitespaceAndTrim(line);
> +                if (line.isEmpty() || line.startsWith("#")) {
> +                    continue;
> +                }
> +
> +                PublicKeyEntry publicKeyEntry =
> PublicKeyEntry.parsePublicKeyEntry(line);
> +                if (publicKeyEntry == null) {
> +                    continue;
> +                }
> +                PublicKey publicKey =
> publicKeyEntry.resolvePublicKey(session, null, null);
> +                if (publicKey == null) {
> +                    continue;
> +                }
> +                if (!(publicKey instanceof OpenSshCertificate)) {
> +                    throw new InvalidKeyException("Got unexpected key
> type in " + file + ". Expected OpenSSHCertificate.");
> +                }
> +                certificates.add((OpenSshCertificate) publicKey);
> +            }
> +        }
> +
> +        return certificates;
> +    }
> +
> +    @Override
> +    public OpenSshCertificate loadCertificate(SessionContext session,
> String keyType) throws IOException, GeneralSecurityException {
> +        return
> StreamSupport.stream(loadCertificates(session).spliterator(), false)
> +            .filter(pubKey -> Objects.equals(pubKey.getKeyType(),
> keyType))
> +            .findFirst().orElse(null);
> +    }
> +}
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/HostKeyCertificateProvider.java
> b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/HostKeyCertificateProvider.java
> new file mode 100644
> index 0000000..ab8eba0
> --- /dev/null
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/HostKeyCertificateProvider.java
> @@ -0,0 +1,32 @@
> +/*
> + * 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.sshd.common.keyprovider;
> +
> +import java.io.IOException;
> +import java.security.GeneralSecurityException;
> +
> +import org.apache.sshd.common.config.keys.OpenSshCertificate;
> +import org.apache.sshd.common.session.SessionContext;
> +
> +public interface HostKeyCertificateProvider {
> +
> +    Iterable<OpenSshCertificate> loadCertificates(SessionContext session)
> throws IOException, GeneralSecurityException;
> +
> +    OpenSshCertificate loadCertificate(SessionContext session, String
> keyType) throws IOException, GeneralSecurityException;
> +}
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/KeyPairProvider.java
> b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/KeyPairProvider.java
> index 237b61f..2bc6114 100644
> ---
> a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/KeyPairProvider.java
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/KeyPairProvider.java
> @@ -73,6 +73,16 @@ public interface KeyPairProvider extends
> KeyIdentityProvider {
>      String ECDSA_SHA2_NISTP521 = ECCurves.nistp521.getKeyType();
>
>      /**
> +     * SSH identifier for openssh cert keys
> +     */
> +    String SSH_RSA_CERT = "ssh-rsa-cert-...@openssh.com";
> +    String SSH_DSS_CERT = "ssh-dss-cert-...@openssh.com";
> +    String SSH_ED25519_CERT = "ssh-ed25519-cert-...@openssh.com";
> +    String SSH_ECDSA_SHA2_NISTP256_CERT = "
> ecdsa-sha2-nistp256-cert-...@openssh.com";
> +    String SSH_ECDSA_SHA2_NISTP384_CERT = "
> ecdsa-sha2-nistp384-cert-...@openssh.com";
> +    String SSH_ECDSA_SHA2_NISTP521_CERT = "
> ecdsa-sha2-nistp521-cert-...@openssh.com";
> +
> +    /**
>       * A {@link KeyPairProvider} that has no keys
>       */
>      KeyPairProvider EMPTY_KEYPAIR_PROVIDER =
> @@ -84,7 +94,7 @@ public interface KeyPairProvider extends
> KeyIdentityProvider {
>
>              @Override
>              public Iterable<String> getKeyTypes(SessionContext session) {
> -                return Collections.emptyList();
> +                return Collections.emptySet();
>              }
>
>              @Override
> @@ -122,7 +132,7 @@ public interface KeyPairProvider extends
> KeyIdentityProvider {
>      /**
>       * @param session The {@link SessionContext} for invoking this load
> command - may
>       * be {@code null} if not invoked within a session context (e.g.,
> offline tool).
> -     * @return The available {@link Iterable} key types in preferred
> order - never {@code null}
> +     * @return The available {@link Iterable} key types - never {@code
> null}
>       * @throws IOException If failed to read/parse the keys data
>       * @throws GeneralSecurityException If failed to generate the keys
>       */
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
> b/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
> index bedf5de..695e26a 100644
> ---
> a/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
> @@ -57,18 +57,36 @@ public enum BuiltinSignatures implements
> SignatureFactory {
>              return new SignatureDSA();
>          }
>      },
> +    dsa_cert(KeyPairProvider.SSH_DSS_CERT) {
> +        @Override
> +        public Signature create() {
> +            return new SignatureDSA();
> +        }
> +    },
>      rsa(KeyPairProvider.SSH_RSA) {
>          @Override
>          public Signature create() {
>              return new SignatureRSASHA1();
>          }
>      },
> +    rsa_cert(KeyPairProvider.SSH_RSA_CERT) {
> +        @Override
> +        public Signature create() {
> +            return new SignatureRSASHA1();
> +        }
> +    },
>      rsaSHA256(KeyUtils.RSA_SHA256_KEY_TYPE_ALIAS) {
>          @Override
>          public Signature create() {
>              return new SignatureRSASHA256();
>          }
>      },
> +    rsaSHA256_cert(KeyUtils.RSA_SHA256_CERT_TYPE_ALIAS) {
> +        @Override
> +        public Signature create() {
> +            return new SignatureRSASHA256();
> +        }
> +    },
>      rsaSHA512(KeyUtils.RSA_SHA512_KEY_TYPE_ALIAS) {
>          private final AtomicReference<Boolean> supportHolder = new
> AtomicReference<>();
>
> @@ -95,6 +113,32 @@ public enum BuiltinSignatures implements
> SignatureFactory {
>              return supported;
>          }
>      },
> +    rsaSHA512_cert(KeyUtils.RSA_SHA512_CERT_TYPE_ALIAS) {
> +        private final AtomicReference<Boolean> supportHolder = new
> AtomicReference<>();
> +
> +        @Override
> +        public Signature create() {
> +            return new SignatureRSASHA512();
> +        }
> +
> +        @Override
> +        public boolean isSupported() {
> +            Boolean supported = supportHolder.get();
> +            if (supported == null) {
> +                try {
> +                    java.security.Signature sig =
> +
> SecurityUtils.getSignature(SignatureRSASHA512.ALGORITHM);
> +                    supported = sig != null;
> +                } catch (Exception e) {
> +                    supported = Boolean.FALSE;
> +                }
> +
> +                supportHolder.set(supported);
> +            }
> +
> +            return supported;
> +        }
> +    },
>      nistp256(KeyPairProvider.ECDSA_SHA2_NISTP256) {
>          @Override
>          public Signature create() {
> @@ -106,6 +150,17 @@ public enum BuiltinSignatures implements
> SignatureFactory {
>              return SecurityUtils.isECCSupported();
>          }
>      },
> +    nistp256_cert(KeyPairProvider.SSH_ECDSA_SHA2_NISTP256_CERT) {
> +        @Override
> +        public Signature create() {
> +            return new SignatureECDSA.SignatureECDSA256();
> +        }
> +
> +        @Override
> +        public boolean isSupported() {
> +            return SecurityUtils.isECCSupported();
> +        }
> +    },
>      nistp384(KeyPairProvider.ECDSA_SHA2_NISTP384) {
>          @Override
>          public Signature create() {
> @@ -117,6 +172,17 @@ public enum BuiltinSignatures implements
> SignatureFactory {
>              return SecurityUtils.isECCSupported();
>          }
>      },
> +    nistp384_cert(KeyPairProvider.SSH_ECDSA_SHA2_NISTP384_CERT) {
> +        @Override
> +        public Signature create() {
> +            return new SignatureECDSA.SignatureECDSA384();
> +        }
> +
> +        @Override
> +        public boolean isSupported() {
> +            return SecurityUtils.isECCSupported();
> +        }
> +    },
>      nistp521(KeyPairProvider.ECDSA_SHA2_NISTP521) {
>          @Override
>          public Signature create() {
> @@ -128,6 +194,17 @@ public enum BuiltinSignatures implements
> SignatureFactory {
>              return SecurityUtils.isECCSupported();
>          }
>      },
> +    nistp521_cert(KeyPairProvider.SSH_ECDSA_SHA2_NISTP521_CERT) {
> +        @Override
> +        public Signature create() {
> +            return new SignatureECDSA.SignatureECDSA521();
> +        }
> +
> +        @Override
> +        public boolean isSupported() {
> +            return SecurityUtils.isECCSupported();
> +        }
> +    },
>      sk_ecdsa_sha2_nistp256(SkECDSAPublicKeyEntryDecoder.KEY_TYPE) {
>          @Override
>          public Signature create() {
> @@ -150,6 +227,17 @@ public enum BuiltinSignatures implements
> SignatureFactory {
>              return SecurityUtils.isEDDSACurveSupported();
>          }
>      },
> +    ed25519_cert(KeyPairProvider.SSH_ED25519_CERT) {
> +        @Override
> +        public Signature create() {
> +            return SecurityUtils.getEDDSASigner();
> +        }
> +
> +        @Override
> +        public boolean isSupported() {
> +            return SecurityUtils.isEDDSACurveSupported();
> +        }
> +    },
>      sk_ssh_ed25519(SkED25519PublicKeyEntryDecoder.KEY_TYPE) {
>          @Override
>          public Signature create() {
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
> b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
> index 25296d0..363859c 100644
> ---
> a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
> @@ -90,7 +90,6 @@ public interface SignatureFactory extends
> BuiltinFactory<Signature> {
>              return Collections.emptyList();
>          }
>
> -        // We want to preserve the original available order as it
> indicates the preference
>          Set<String> providedKeys = new HashSet<>();
>          for (String providedType : provided) {
>              Collection<String> equivTypes =
> @@ -102,6 +101,7 @@ public interface SignatureFactory extends
> BuiltinFactory<Signature> {
>              return Collections.emptyList();
>          }
>
> +        // We want to preserve the original available order as it
> indicates the preference
>          List<String> supported = new ArrayList<>(available);
>          for (int index = 0; index < supported.size(); index++) {
>              String kt = supported.get(index);
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java
> b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java
> index b0fb2fe..ff84404 100644
> ---
> a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java
> @@ -78,7 +78,9 @@ public abstract class SignatureRSA extends
> AbstractSignature {
>               *      corresponds to a good-faith implementation and is
> considered safe to accept.
>               */
>              String canonicalName = KeyUtils.getCanonicalKeyType(keyType);
> -
> ValidateUtils.checkTrue(KeyPairProvider.SSH_RSA.equals(canonicalName),
> "Mismatched key type: %s", keyType);
> +            if (!KeyPairProvider.SSH_RSA.equals(canonicalName) &&
> !KeyPairProvider.SSH_RSA_CERT.equals(canonicalName)) {
> +                throw new IllegalArgumentException("Mismatched key type:
> " + keyType);
> +            }
>              data = encoding.getValue();
>          }
>
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
> b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
> index 2482fb0..db65ac9 100644
> ---
> a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
> @@ -60,6 +60,7 @@ import org.apache.sshd.common.SshConstants;
>  import org.apache.sshd.common.SshException;
>  import org.apache.sshd.common.cipher.ECCurves;
>  import org.apache.sshd.common.config.keys.KeyUtils;
> +import org.apache.sshd.common.config.keys.OpenSshCertificate;
>  import org.apache.sshd.common.keyprovider.KeyPairProvider;
>  import org.apache.sshd.common.util.GenericUtils;
>  import org.apache.sshd.common.util.NumberUtils;
> @@ -114,6 +115,11 @@ public abstract class Buffer implements Readable {
>      public abstract byte[] array();
>
>      /**
> +     * @return The bytes consumed so far
> +     */
> +    public abstract byte[] getBytesConsumed();
> +
> +    /**
>       * @param pos A position in the <U>raw</U> underlying data bytes
>       * @return The byte at the specified position without changing the
>       * current {@link #rpos() read position}. <B>Note:</B> no validation
> @@ -893,18 +899,21 @@ public abstract class Buffer implements Readable {
>      }
>
>      public void putRawPublicKey(PublicKey key) {
> +        putString(KeyUtils.getKeyType(key));
> +        putRawPublicKeyBytes(key);
> +    }
> +
> +    public void putRawPublicKeyBytes(PublicKey key) {
>          Objects.requireNonNull(key, "No key");
>          if (key instanceof RSAPublicKey) {
>              RSAPublicKey rsaPub = (RSAPublicKey) key;
>
> -            putString(KeyPairProvider.SSH_RSA);
>              putMPInt(rsaPub.getPublicExponent());
>              putMPInt(rsaPub.getModulus());
>          } else if (key instanceof DSAPublicKey) {
>              DSAPublicKey dsaPub = (DSAPublicKey) key;
>              DSAParams dsaParams = dsaPub.getParams();
>
> -            putString(KeyPairProvider.SSH_DSS);
>              putMPInt(dsaParams.getP());
>              putMPInt(dsaParams.getQ());
>              putMPInt(dsaParams.getG());
> @@ -918,11 +927,30 @@ public abstract class Buffer implements Readable {
>              }
>
>              byte[] ecPoint = ECCurves.encodeECPoint(ecKey.getW(),
> ecParams);
> -            putString(curve.getKeyType());
>              putString(curve.getName());
>              putBytes(ecPoint);
>          } else if (SecurityUtils.EDDSA.equals(key.getAlgorithm())) {
>              SecurityUtils.putRawEDDSAPublicKey(this, key);
> +        } else if (key instanceof OpenSshCertificate) {
> +            OpenSshCertificate cert = (OpenSshCertificate) key;
> +
> +            putBytes(cert.getNonce());
> +            putRawPublicKeyBytes(cert.getServerHostKey());
> +            putLong(cert.getSerial());
> +            putInt(cert.getType());
> +            putString(cert.getId());
> +            ByteArrayBuffer tmpBuffer = new ByteArrayBuffer();
> +            tmpBuffer.putStringList(cert.getPrincipals(), false);
> +            putBytes(tmpBuffer.getCompactData());
> +            putLong(cert.getValidAfter());
> +            putLong(cert.getValidBefore());
> +            putNameList(cert.getCriticalOptions());
> +            putNameList(cert.getExtensions());
> +            putString(cert.getReserved());
> +            tmpBuffer = new ByteArrayBuffer();
> +            tmpBuffer.putRawPublicKey(cert.getCaPubKey());
> +            putBytes(tmpBuffer.getCompactData());
> +            putBytes(cert.getSignature());
>          } else {
>              throw new BufferException("Unsupported raw public key
> algorithm: " + key.getAlgorithm());
>          }
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
> b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
> index 65fcb0b..2a98434 100644
> ---
> a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
> @@ -158,6 +158,13 @@ public class ByteArrayBuffer extends Buffer {
>      }
>
>      @Override
> +    public byte[] getBytesConsumed() {
> +        byte[] consumed = new byte[rpos];
> +        System.arraycopy(data, 0, consumed, 0, rpos);
> +        return consumed;
> +    }
> +
> +    @Override
>      public byte rawByte(int pos) {
>          return data[pos];
>      }
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/BufferPublicKeyParser.java
> b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/BufferPublicKeyParser.java
> index 6b9bae2..2b788e5 100644
> ---
> a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/BufferPublicKeyParser.java
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/BufferPublicKeyParser.java
> @@ -60,6 +60,7 @@ public interface BufferPublicKeyParser<PUB extends
> PublicKey> {
>                      ECBufferPublicKeyParser.INSTANCE,
>                      SkECBufferPublicKeyParser.INSTANCE,
>                      ED25519BufferPublicKeyParser.INSTANCE,
> +                    OpenSSHCertPublicKeyParser.INSTANCE,
>                      SkED25519BufferPublicKeyParser.INSTANCE));
>
>      /**
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/OpenSSHCertPublicKeyParser.java
> b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/OpenSSHCertPublicKeyParser.java
> new file mode 100644
> index 0000000..1c9823a
> --- /dev/null
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/keys/OpenSSHCertPublicKeyParser.java
> @@ -0,0 +1,89 @@
> +/*
> + * 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.sshd.common.util.buffer.keys;
> +
> +import java.security.GeneralSecurityException;
> +import java.security.PublicKey;
> +import java.util.Arrays;
> +import java.util.Collection;
> +
> +import org.apache.sshd.common.SshException;
> +import org.apache.sshd.common.config.keys.OpenSshCertificateImpl;
> +import org.apache.sshd.common.keyprovider.KeyPairProvider;
> +import org.apache.sshd.common.util.buffer.Buffer;
> +import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
> +
> +public class OpenSSHCertPublicKeyParser extends
> AbstractBufferPublicKeyParser<PublicKey> {
> +
> +    public static final OpenSSHCertPublicKeyParser INSTANCE = new
> OpenSSHCertPublicKeyParser(PublicKey.class,
> +        Arrays.asList(
> +            KeyPairProvider.SSH_RSA_CERT,
> +            KeyPairProvider.SSH_DSS_CERT,
> +            KeyPairProvider.SSH_ECDSA_SHA2_NISTP256_CERT,
> +            KeyPairProvider.SSH_ECDSA_SHA2_NISTP384_CERT,
> +            KeyPairProvider.SSH_ECDSA_SHA2_NISTP521_CERT,
> +            KeyPairProvider.SSH_ED25519_CERT
> +        ));
> +
> +    public OpenSSHCertPublicKeyParser(Class<PublicKey> keyClass,
> Collection<String> supported) {
> +        super(keyClass, supported);
> +    }
> +
> +    @Override
> +    public PublicKey getRawPublicKey(String keyType, Buffer buffer)
> throws GeneralSecurityException {
> +
> +        OpenSshCertificateImpl certificate = new OpenSshCertificateImpl();
> +        certificate.setKeyType(keyType);
> +
> +        certificate.setNonce(buffer.getBytes());
> +
> +        String rawKeyType = certificate.getRawKeyType();
> +        certificate.setServerHostKey(DEFAULT.getRawPublicKey(rawKeyType,
> buffer));
> +
> +        certificate.setSerial(buffer.getLong());
> +        certificate.setType(buffer.getInt());
> +
> +        certificate.setId(buffer.getString());
> +
> +        certificate.setPrincipals(new
> ByteArrayBuffer(buffer.getBytes()).getStringList(false));
> +        certificate.setValidAfter(buffer.getLong());
> +        certificate.setValidBefore(buffer.getLong());
> +
> +        certificate.setCriticalOptions(buffer.getNameList());
> +        certificate.setExtensions(buffer.getNameList());
> +
> +        certificate.setReserved(buffer.getString());
> +
> +        try {
> +            certificate.setCaPubKey(buffer.getPublicKey());
> +        } catch (SshException ex) {
> +            throw new GeneralSecurityException("Could not parse public CA
> key with ID: " + certificate.getId(), ex);
> +        }
> +
> +        certificate.setMessage(buffer.getBytesConsumed());
> +        certificate.setSignature(buffer.getBytes());
> +
> +        if (buffer.rpos() != buffer.wpos()) {
> +            throw new GeneralSecurityException("KeyExchange signature
> verification failed, got more data than expected: "
> +                + buffer.rpos() + ", actual: " + buffer.wpos() + ". ID of
> the ca certificate: " + certificate.getId());
> +        }
> +
> +        return certificate;
> +    }
> +}
> diff --git
> a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
> b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
> index 242f550..e002d4b 100644
> ---
> a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
> +++
> b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
> @@ -30,7 +30,6 @@ import java.util.Objects;
>
>  import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
>  import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder;
> -import org.apache.sshd.common.keyprovider.KeyPairProvider;
>  import org.apache.sshd.common.util.ValidateUtils;
>  import org.apache.sshd.common.util.buffer.Buffer;
>  import org.apache.sshd.common.util.security.SecurityUtils;
> @@ -187,7 +186,6 @@ public final class EdDSASecurityProviderUtils {
>          EdDSAPublicKey edKey = ValidateUtils.checkInstanceOf(key,
> EdDSAPublicKey.class, "Not an EDDSA public key: %s", key);
>          byte[] seed = Ed25519PublicKeyDecoder.getSeedValue(edKey);
>          ValidateUtils.checkNotNull(seed, "No seed extracted from key:
> %s", edKey.getA());
> -        buffer.putString(KeyPairProvider.SSH_ED25519);
>          buffer.putBytes(seed);
>          return buffer;
>      }
> diff --git
> a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java
> b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java
> index 3ad00be..51ffd0b 100644
> ---
> a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java
> +++
> b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java
> @@ -30,7 +30,6 @@ import java.security.Signature;
>  import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
>  import org.apache.sshd.common.config.keys.KeyUtils;
>  import org.apache.sshd.common.keyprovider.KeyPairProvider;
> -import org.apache.sshd.common.util.buffer.Buffer;
>  import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
>  import org.apache.sshd.common.util.security.SecurityUtils;
>  import org.apache.sshd.util.test.JUnitTestSupport;
> @@ -118,7 +117,8 @@ public class EDDSAProviderTest extends
> JUnitTestSupport {
>          assertNotNull("No public key generated", pubKey);
>          assertEquals("Mismatched public key algorithm",
> SecurityUtils.EDDSA, pubKey.getAlgorithm());
>
> -        Buffer buf = SecurityUtils.putRawEDDSAPublicKey(new
> ByteArrayBuffer(), pubKey);
> +        ByteArrayBuffer buf = new ByteArrayBuffer();
> +        buf.putRawPublicKey(pubKey);
>          PublicKey actual = buf.getRawPublicKey();
>          assertEquals("Mismatched key algorithm", pubKey.getAlgorithm(),
> actual.getAlgorithm());
>          assertEquals("Mismatched recovered key", pubKey, actual);
> diff --git
> a/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
> b/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
> index 46d7ba9..36d1e4c 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
> @@ -76,6 +76,12 @@ public class ClientBuilder extends
> BaseBuilder<SshClient, ClientBuilder> {
>           */
>          Collections.unmodifiableList(
>              Arrays.asList(
> +                BuiltinSignatures.nistp256_cert,
> +                BuiltinSignatures.nistp384_cert,
> +                BuiltinSignatures.nistp521_cert,
> +                BuiltinSignatures.ed25519_cert,
> +                BuiltinSignatures.rsa_cert,
> +                BuiltinSignatures.dsa_cert,
>                  BuiltinSignatures.nistp256,
>                  BuiltinSignatures.nistp384,
>                  BuiltinSignatures.nistp521,
> diff --git
> a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
> b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
> index 5c8694b..017cf7a 100644
> ---
> a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
> +++
> b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
> @@ -114,6 +114,12 @@ public interface ClientFactoryManager
>      boolean DEFAULT_IGNORE_INVALID_IDENTITIES = true;
>
>      /**
> +     * Defines if we should abort in case we encounter an invalid (e.g.
> expired) openssh certificate.
> +     * The default is to ignore the certificate and proceed with the
> plain host key.
> +     */
> +    String ABORT_ON_INVALID_CERTIFICATE = "abort-on-invalid-certificate";
> +
> +    /**
>       * @return The {@link HostConfigEntryResolver} to use in order to
> resolve the
>       * effective session parameters - never {@code null}
>       */
> diff --git
> a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
> b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
> index e2694ee..4f1a4f0 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
> @@ -18,22 +18,31 @@
>   */
>  package org.apache.sshd.client.kex;
>
> +import java.net.InetSocketAddress;
> +import java.net.SocketAddress;
> +import java.security.PublicKey;
> +import java.util.Collection;
>  import java.util.Objects;
>
> +import org.apache.sshd.client.ClientFactoryManager;
>  import org.apache.sshd.common.NamedFactory;
>  import org.apache.sshd.common.SshConstants;
>  import org.apache.sshd.common.SshException;
>  import org.apache.sshd.common.config.keys.KeyUtils;
> +import org.apache.sshd.common.config.keys.OpenSshCertificate;
>  import org.apache.sshd.common.kex.AbstractDH;
>  import org.apache.sshd.common.kex.DHFactory;
> +import org.apache.sshd.common.kex.KexProposalOption;
>  import org.apache.sshd.common.kex.KeyExchange;
>  import org.apache.sshd.common.kex.KeyExchangeFactory;
> +import org.apache.sshd.common.keyprovider.KeyPairProvider;
>  import org.apache.sshd.common.session.Session;
>  import org.apache.sshd.common.signature.Signature;
>  import org.apache.sshd.common.util.GenericUtils;
>  import org.apache.sshd.common.util.ValidateUtils;
>  import org.apache.sshd.common.util.buffer.Buffer;
>  import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
> +import org.apache.sshd.common.util.net.SshdSocketAddress;
>
>  /**
>   * Base class for DHG key exchange algorithms.
> @@ -124,10 +133,29 @@ public class DHGClient extends
> AbstractDHClientKeyExchange {
>
>          buffer = new ByteArrayBuffer(k_s);
>          serverKey = buffer.getRawPublicKey();
> -        String keyAlg = KeyUtils.getKeyType(serverKey);
> +        PublicKey serverPublicHostKey = serverKey;
> +
> +        if (serverKey instanceof OpenSshCertificate) {
> +            OpenSshCertificate openSshKey = (OpenSshCertificate)
> serverKey;
> +            serverPublicHostKey = openSshKey.getServerHostKey();
> +
> +            try {
> +                verifyCertificate(session, openSshKey);
> +            } catch (SshException e) {
> +                if
> (session.getBooleanProperty(ClientFactoryManager.ABORT_ON_INVALID_CERTIFICATE,
> false)) {
> +                    throw e;
> +                } else {
> +                    // ignore certificate
> +                    serverKey = openSshKey.getServerHostKey();
> +                    log.info("Ignoring invalid certificate {}",
> openSshKey.getId(), e);
> +                }
> +            }
> +        }
> +
> +        String keyAlg =
> session.getNegotiatedKexParameter(KexProposalOption.SERVERKEYS);
>          if (GenericUtils.isEmpty(keyAlg)) {
> -            throw new SshException("Unsupported server key type: " +
> serverKey.getAlgorithm()
> -                + "[" + serverKey.getFormat() + "]");
> +            throw new SshException("Unsupported server key type: " +
> serverPublicHostKey.getAlgorithm()
> +                + "[" + serverPublicHostKey.getFormat() + "]");
>          }
>
>          buffer = new ByteArrayBuffer();
> @@ -145,7 +173,7 @@ public class DHGClient extends
> AbstractDHClientKeyExchange {
>          Signature verif = ValidateUtils.checkNotNull(
>              NamedFactory.create(session.getSignatureFactories(), keyAlg),
>              "No verifier located for algorithm=%s", keyAlg);
> -        verif.initVerifier(session, serverKey);
> +        verif.initVerifier(session, serverPublicHostKey);
>          verif.update(session, h);
>          if (!verif.verify(session, sig)) {
>              throw new
> SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
> @@ -154,4 +182,73 @@ public class DHGClient extends
> AbstractDHClientKeyExchange {
>
>          return true;
>      }
> +
> +    protected void verifyCertificate(Session session, OpenSshCertificate
> openSshKey) throws Exception {
> +        PublicKey signatureKey = openSshKey.getCaPubKey();
> +        String keyAlg = KeyUtils.getKeyType(signatureKey);
> +
> +        if (KeyPairProvider.SSH_RSA_CERT.equals(openSshKey.getKeyType()))
> {
> +            // allow sha2 signatures for legacy reasons
> +            String variant = openSshKey.getSignatureAlg();
> +            if (!GenericUtils.isEmpty(variant) &&
> KeyPairProvider.SSH_RSA.equals(KeyUtils.getCanonicalKeyType(variant))) {
> +                log.debug("Allowing to use variant {} instead of {}",
> variant, keyAlg);
> +                keyAlg = variant;
> +            } else {
> +                throw new
> SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
> +                    "Found invalid signature alg " + variant);
> +            }
> +        }
> +
> +        Signature verif = ValidateUtils.checkNotNull(
> +                NamedFactory.create(session.getSignatureFactories(),
> keyAlg),
> +                "No verifier located for algorithm=%s", keyAlg);
> +        verif.initVerifier(session, signatureKey);
> +        verif.update(session, openSshKey.getMessage());
> +        if (!verif.verify(session, openSshKey.getSignature())) {
> +            throw new
> SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
> +                    "KeyExchange CA signature verification failed for key
> type=" + keyAlg);
> +        }
> +
> +        if (openSshKey.getType() !=
> OpenSshCertificate.SSH_CERT_TYPE_HOST) {
> +            throw new
> SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
> +                    "KeyExchange signature verification failed, not a
> host key (2): "
> +                            + openSshKey.getType());
> +        }
> +
> +        long now = System.currentTimeMillis() / 1000;
> +        // valid after <= current time < valid before
> +        if (!(openSshKey.getValidAfter() <= now && now <
> openSshKey.getValidBefore())) {
> +            throw new
> SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
> +                    "KeyExchange signature verification failed, CA
> expired: "
> +                            + openSshKey.getValidAfter() + "-" +
> openSshKey.getValidBefore());
> +        }
> +
> +        /*
> +         * We compare only the connect address against the principals and
> do not do any reverse DNS lookups.
> +         * If one wants to connect with the IP it has to be included in
> the principals list of the certificate.
> +         */
> +        SocketAddress connectSocketAddress =
> getClientSession().getConnectAddress();
> +        if (connectSocketAddress instanceof SshdSocketAddress) {
> +            connectSocketAddress = ((SshdSocketAddress)
> connectSocketAddress).toInetSocketAddress();
> +        }
> +        if (connectSocketAddress instanceof InetSocketAddress) {
> +            String hostName = ((InetSocketAddress)
> connectSocketAddress).getHostString();
> +            Collection<String> principals = openSshKey.getPrincipals();
> +            if (GenericUtils.isEmpty(principals) ||
> !principals.contains(hostName)) {
> +                throw new
> SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
> +                        "KeyExchange signature verification failed,
> invalid principal: "
> +                                + principals);
> +            }
> +        } else {
> +            throw new
> SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
> +                    "KeyExchange signature verification failed, could not
> determine connect host.");
> +        }
> +
> +        if (!GenericUtils.isEmpty(openSshKey.getCriticalOptions())) {
> +            // no critical option defined for host keys yet
> +            throw new
> SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
> +                    "KeyExchange signature verification failed,
> unrecognized critical option: "
> +                            + openSshKey.getCriticalOptions());
> +        }
> +    }
>  }
> diff --git
> a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
> b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
> index 558266c..b36dfb6 100644
> ---
> a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
> +++
> b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
> @@ -51,6 +51,7 @@ import
> org.apache.sshd.common.channel.PtyChannelConfigurationHolder;
>  import org.apache.sshd.common.cipher.BuiltinCiphers;
>  import org.apache.sshd.common.cipher.CipherNone;
>  import org.apache.sshd.common.config.keys.KeyUtils;
> +import org.apache.sshd.common.config.keys.OpenSshCertificate;
>  import org.apache.sshd.common.forward.ForwardingFilter;
>  import org.apache.sshd.common.future.DefaultKeyExchangeFuture;
>  import org.apache.sshd.common.future.KeyExchangeFuture;
> @@ -546,10 +547,28 @@ public abstract class AbstractClientSession extends
> AbstractSession implements C
>          IoSession networkSession = getIoSession();
>          SocketAddress remoteAddress = networkSession.getRemoteAddress();
>          PublicKey serverKey = kex.getServerKey();
> -        boolean verified = serverKeyVerifier.verifyServerKey(this,
> remoteAddress, serverKey);
> -        if (log.isDebugEnabled()) {
> -            log.debug("checkKeys({}) key={}-{}, verified={}",
> -                this, KeyUtils.getKeyType(serverKey),
> KeyUtils.getFingerPrint(serverKey), verified);
> +
> +        boolean verified = false;
> +        if (serverKey instanceof OpenSshCertificate) {
> +            // check if we trust the CA
> +            verified = serverKeyVerifier.verifyServerKey(this,
> remoteAddress, ((OpenSshCertificate) serverKey).getCaPubKey());
> +            if (log.isDebugEnabled()) {
> +                log.debug("checkCA({}) key={}-{}, verified={}",
> +                    this, KeyUtils.getKeyType(serverKey),
> KeyUtils.getFingerPrint(serverKey), verified);
> +            }
> +
> +            if (!verified) {
> +                // fallback to actual public host key
> +                serverKey = ((OpenSshCertificate)
> serverKey).getServerHostKey();
> +            }
> +        }
> +
> +        if (!verified) {
> +            verified = serverKeyVerifier.verifyServerKey(this,
> remoteAddress, serverKey);
> +            if (log.isDebugEnabled()) {
> +                log.debug("checkKeys({}) key={}-{}, verified={}",
> +                    this, KeyUtils.getKeyType(serverKey),
> KeyUtils.getFingerPrint(serverKey), verified);
> +            }
>          }
>
>          if (!verified) {
> diff --git
> a/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
> b/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
> index 0f34f80..cbcebc3 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerBuilder.java
> @@ -98,6 +98,14 @@ public class ServerBuilder extends
> BaseBuilder<SshServer, ServerBuilder> {
>      public static final List<BuiltinSignatures>
> DEFAULT_SIGNATURE_PREFERENCE =
>          Collections.unmodifiableList(
>              Arrays.asList(
> +                BuiltinSignatures.nistp256_cert,
> +                BuiltinSignatures.nistp384_cert,
> +                BuiltinSignatures.nistp521_cert,
> +                BuiltinSignatures.ed25519_cert,
> +                BuiltinSignatures.rsaSHA512_cert,
> +                BuiltinSignatures.rsaSHA256_cert,
> +                BuiltinSignatures.rsa_cert,
> +                BuiltinSignatures.dsa_cert,
>                  BuiltinSignatures.nistp256,
>                  BuiltinSignatures.nistp384,
>                  BuiltinSignatures.nistp521,
> diff --git
> a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
> b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
> index 10e23b0..83f7770 100644
> ---
> a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
> +++
> b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
> @@ -22,6 +22,7 @@ import java.util.List;
>  import java.util.concurrent.TimeUnit;
>
>  import org.apache.sshd.common.FactoryManager;
> +import org.apache.sshd.common.keyprovider.HostKeyCertificateProvider;
>  import org.apache.sshd.server.command.CommandFactory;
>  import org.apache.sshd.server.session.ServerProxyAcceptorHolder;
>  import org.apache.sshd.server.shell.ShellFactory;
> @@ -110,4 +111,9 @@ public interface ServerFactoryManager
>       * or {@code null}/empty if subsystems are not supported on this
> server
>       */
>      List<SubsystemFactory> getSubsystemFactories();
> +
> +    /**
> +     * @return a {@link HostKeyCertificateProvider} if available, null as
> default
> +     */
> +    HostKeyCertificateProvider getHostKeyCertificateProvider();
>  }
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
> b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
> index fcc676f..be5d946 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
> @@ -39,6 +39,7 @@ import
> org.apache.sshd.common.helpers.AbstractFactoryManager;
>  import org.apache.sshd.common.io.IoAcceptor;
>  import org.apache.sshd.common.io.IoServiceFactory;
>  import org.apache.sshd.common.io.IoSession;
> +import org.apache.sshd.common.keyprovider.HostKeyCertificateProvider;
>  import org.apache.sshd.common.keyprovider.KeyPairProvider;
>  import org.apache.sshd.common.session.helpers.AbstractSession;
>  import org.apache.sshd.common.util.GenericUtils;
> @@ -105,6 +106,7 @@ public class SshServer extends AbstractFactoryManager
> implements ServerFactoryMa
>      private List<SubsystemFactory> subsystemFactories;
>      private List<UserAuthFactory> userAuthFactories;
>      private KeyPairProvider keyPairProvider;
> +    private HostKeyCertificateProvider hostKeyCertificateProvider;
>      private PasswordAuthenticator passwordAuthenticator;
>      private PublickeyAuthenticator publickeyAuthenticator;
>      private KeyboardInteractiveAuthenticator interactiveAuthenticator;
> @@ -261,6 +263,15 @@ public class SshServer extends AbstractFactoryManager
> implements ServerFactoryMa
>      }
>
>      @Override
> +    public HostKeyCertificateProvider getHostKeyCertificateProvider() {
> +        return hostKeyCertificateProvider;
> +    }
> +
> +    public void setHostKeyCertificateProvider(HostKeyCertificateProvider
> hostKeyCertificateProvider) {
> +        this.hostKeyCertificateProvider = hostKeyCertificateProvider;
> +    }
> +
> +    @Override
>      protected void checkConfig() {
>          super.checkConfig();
>
> diff --git
> a/sshd-core/src/main/java/org/apache/sshd/server/config/keys/ServerIdentity.java
> b/sshd-core/src/main/java/org/apache/sshd/server/config/keys/ServerIdentity.java
> index 7cc5010..5e3ffc5 100644
> ---
> a/sshd-core/src/main/java/org/apache/sshd/server/config/keys/ServerIdentity.java
> +++
> b/sshd-core/src/main/java/org/apache/sshd/server/config/keys/ServerIdentity.java
> @@ -55,6 +55,7 @@ public final class ServerIdentity {
>       * The server's keys configuration multi-value
>       */
>      public static final String HOST_KEY_CONFIG_PROP = "HostKey";
> +    public static final String HOST_CERT_CONFIG_PROP = "HostCertificate";
>
>      public static final Function<String, String> ID_GENERATOR =
>              ServerIdentity::getIdentityFileName;
> @@ -137,11 +138,31 @@ public final class ServerIdentity {
>       * @see
> org.apache.sshd.common.config.ConfigFileReaderSupport#readConfigFile(Path,
> java.nio.file.OpenOption...)
>       */
>      public static Map<String, Path> findIdentities(Properties props,
> LinkOption... options) throws IOException {
> +        return getLocations(HOST_KEY_CONFIG_PROP, props, options);
> +    }
> +
> +    /**
> +     * @param props   The {@link Properties} holding the server's
> configuration - ignored
> +     *                if {@code null}/empty
> +     * @param options The {@link LinkOption}s to use when checking files
> existence
> +     * @return A {@link Map} of the found certificates where key=the
> identity type
> +     * (case <U>insensitive</U>) and value=the {@link Path} of the file
> holding
> +     * the specific type key
> +     * @throws IOException If failed to access the file system
> +     * @see #getIdentityType(String)
> +     * @see #HOST_CERT_CONFIG_PROP
> +     * @see
> org.apache.sshd.common.config.ConfigFileReaderSupport#readConfigFile(Path,
> java.nio.file.OpenOption...)
> +     */
> +    public static Map<String, Path> findCertificates(Properties props,
> LinkOption... options) throws IOException {
> +        return getLocations(HOST_CERT_CONFIG_PROP, props, options);
> +    }
> +
> +    private static Map<String, Path> getLocations(String configPropKey,
> Properties props, LinkOption... options) throws IOException {
>          if (GenericUtils.isEmpty(props)) {
>              return Collections.emptyMap();
>          }
>
> -        String keyList = props.getProperty(HOST_KEY_CONFIG_PROP);
> +        String keyList = props.getProperty(configPropKey);
>          String[] paths = GenericUtils.split(keyList, ',');
>          if (GenericUtils.isEmpty(paths)) {
>              return Collections.emptyMap();
> diff --git
> a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
> b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
> index c8ee45e..7e96045 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
> @@ -104,6 +104,7 @@ public class DHGServer extends
> AbstractDHServerKeyExchange {
>
>          KeyPair kp = Objects.requireNonNull(session.getHostKey(), "No
> server key pair available");
>          String algo =
> session.getNegotiatedKexParameter(KexProposalOption.SERVERKEYS);
> +
>          Signature sig = ValidateUtils.checkNotNull(
>              NamedFactory.create(session.getSignatureFactories(), algo),
>              "Unknown negotiated server keys: %s", algo);
> diff --git
> a/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
> b/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
> index 7232935..5f4ddcf 100644
> ---
> a/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
> +++
> b/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
> @@ -28,6 +28,8 @@ import java.util.Collection;
>  import java.util.List;
>  import java.util.Map;
>  import java.util.Objects;
> +import java.util.Set;
> +import java.util.stream.Collectors;
>
>  import org.apache.sshd.common.FactoryManager;
>  import org.apache.sshd.common.NamedResource;
> @@ -37,6 +39,7 @@ import org.apache.sshd.common.SshConstants;
>  import org.apache.sshd.common.SshException;
>  import org.apache.sshd.common.auth.AbstractUserAuthServiceFactory;
>  import org.apache.sshd.common.config.keys.KeyUtils;
> +import org.apache.sshd.common.config.keys.OpenSshCertificate;
>  import org.apache.sshd.common.io.IoService;
>  import org.apache.sshd.common.io.IoSession;
>  import org.apache.sshd.common.io.IoWriteFuture;
> @@ -46,6 +49,7 @@ import org.apache.sshd.common.kex.KexState;
>  import org.apache.sshd.common.kex.extension.KexExtensionHandler;
>  import
> org.apache.sshd.common.kex.extension.KexExtensionHandler.AvailabilityPhase;
>  import org.apache.sshd.common.kex.extension.KexExtensionHandler.KexPhase;
> +import org.apache.sshd.common.keyprovider.HostKeyCertificateProvider;
>  import org.apache.sshd.common.keyprovider.KeyPairProvider;
>  import org.apache.sshd.common.session.ConnectionService;
>  import org.apache.sshd.common.session.SessionContext;
> @@ -81,6 +85,7 @@ public abstract class AbstractServerSession extends
> AbstractSession implements S
>      private HostBasedAuthenticator hostBasedAuthenticator;
>      private List<UserAuthFactory> userAuthFactories;
>      private KeyPairProvider keyPairProvider;
> +    private HostKeyCertificateProvider hostKeyCertificateProvider;
>
>      protected AbstractServerSession(ServerFactoryManager factoryManager,
> IoSession ioSession) {
>          super(true, factoryManager, ioSession);
> @@ -189,6 +194,15 @@ public abstract class AbstractServerSession extends
> AbstractSession implements S
>              (parent == null) ? null : ((ServerAuthenticationManager)
> parent).getKeyPairProvider());
>      }
>
> +    public HostKeyCertificateProvider getHostKeyCertificateProvider() {
> +        ServerFactoryManager manager = getFactoryManager();
> +        return resolveEffectiveProvider(HostKeyCertificateProvider.class,
> hostKeyCertificateProvider, manager.getHostKeyCertificateProvider());
> +    }
> +
> +    public void setHostKeyCertificateProvider(HostKeyCertificateProvider
> hostKeyCertificateProvider) {
> +        this.hostKeyCertificateProvider = hostKeyCertificateProvider;
> +    }
> +
>      @Override
>      public void setKeyPairProvider(KeyPairProvider keyPairProvider) {
>          this.keyPairProvider = keyPairProvider;
> @@ -367,9 +381,25 @@ public abstract class AbstractServerSession extends
> AbstractSession implements S
>
>          KeyPairProvider kpp = getKeyPairProvider();
>          boolean debugEnabled = log.isDebugEnabled();
> -        Iterable<String> provided;
> +        Set<String> provided = null;
>          try {
> -            provided = (kpp == null) ? null : kpp.getKeyTypes(this);
> +            if (kpp != null) {
> +                provided =
> GenericUtils.stream(kpp.getKeyTypes(this)).collect(Collectors.toSet());
> +
> +                HostKeyCertificateProvider hostKeyCertificateProvider =
> getHostKeyCertificateProvider();
> +                if (hostKeyCertificateProvider != null) {
> +                    Iterable<OpenSshCertificate> certificates =
> hostKeyCertificateProvider.loadCertificates(this);
> +                    for (OpenSshCertificate certificate : certificates) {
> +                        // Add the certificate alg only if the
> corresponding keyPair type is available
> +                        if
> (provided.contains(certificate.getRawKeyType())) {
> +                            provided.add(certificate.getKeyType());
> +                        } else {
> +                            log.info("No private key for provided
> certificate available. Missing private key type: {}",
> +                                certificate.getRawKeyType());
> +                        }
> +                    }
> +                }
> +            }
>          } catch (Error e) {
>              log.warn("resolveAvailableSignaturesProposal({}) failed ({})
> to get key types: {}",
>                   this, e.getClass().getSimpleName(), e.getMessage());
> @@ -498,7 +528,16 @@ public abstract class AbstractServerSession extends
> AbstractSession implements S
>          KeyPairProvider provider =
>              Objects.requireNonNull(getKeyPairProvider(), "No host keys
> provider");
>          try {
> +            HostKeyCertificateProvider hostKeyCertificateProvider =
> getHostKeyCertificateProvider();
> +            if (hostKeyCertificateProvider != null) {
> +                OpenSshCertificate publicKey =
> hostKeyCertificateProvider.loadCertificate(this, keyType);
> +                if (publicKey != null) {
> +                    KeyPair keyPair = provider.loadKey(this,
> publicKey.getRawKeyType());
> +                    return new KeyPair(publicKey, keyPair.getPrivate());
> +                }
> +            }
>              return provider.loadKey(this, keyType);
> +
>          } catch (IOException | GeneralSecurityException | Error e) {
>              log.warn("getHostKey({}) failed ({}) to load key of
> type={}[{}]: {}",
>                   this, e.getClass().getSimpleName(), proposedKey,
> keyType, e.getMessage());
> diff --git
> a/sshd-core/src/test/java/org/apache/sshd/common/signature/OpenSSHCertificateTest.java
> b/sshd-core/src/test/java/org/apache/sshd/common/signature/OpenSSHCertificateTest.java
> new file mode 100644
> index 0000000..50bd39d
> --- /dev/null
> +++
> b/sshd-core/src/test/java/org/apache/sshd/common/signature/OpenSSHCertificateTest.java
> @@ -0,0 +1,161 @@
> +/*
> + * 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.sshd.common.signature;
> +
> +import java.util.ArrayList;
> +import java.util.Arrays;
> +import java.util.Collections;
> +import java.util.List;
> +
> +import org.apache.sshd.client.ClientFactoryManager;
> +import org.apache.sshd.client.SshClient;
> +import org.apache.sshd.client.session.ClientSession;
> +import org.apache.sshd.common.NamedFactory;
> +import org.apache.sshd.common.PropertyResolverUtils;
> +import org.apache.sshd.common.SshConstants;
> +import org.apache.sshd.common.SshException;
> +import org.apache.sshd.common.keyprovider.FileHostKeyCertificateProvider;
> +import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
> +import org.apache.sshd.server.SshServer;
> +import org.apache.sshd.util.test.BaseTestSupport;
> +import org.apache.sshd.util.test.CoreTestSupportUtils;
> +import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
> +import org.junit.AfterClass;
> +import org.junit.Assert;
> +import org.junit.BeforeClass;
> +import org.junit.FixMethodOrder;
> +import org.junit.Test;
> +import org.junit.runner.RunWith;
> +import org.junit.runners.MethodSorters;
> +import org.junit.runners.Parameterized;
> +
> +@FixMethodOrder(MethodSorters.NAME_ASCENDING)
> +@RunWith(Parameterized.class)   // see
> https://github.com/junit-team/junit/wiki/Parameterized-tests
>
> +@Parameterized.UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
> +public class OpenSSHCertificateTest extends BaseTestSupport {
> +    private static SshServer sshd;
> +    private static SshClient client;
> +    private static int port;
> +
> +    private final FileHostKeyCertificateProvider certificateProvider;
> +    private final FileKeyPairProvider keyPairProvider;
> +    private final List<NamedFactory<Signature>> signatureFactory;
> +
> +    public OpenSSHCertificateTest(String keyPath, String certPath,
> List<NamedFactory<Signature>> signatureFactory) {
> +        this.keyPairProvider = new
> FileKeyPairProvider(getTestResourcesFolder().resolve(keyPath));
> +        this.certificateProvider = new
> FileHostKeyCertificateProvider(getTestResourcesFolder().resolve(certPath));
> +        this.signatureFactory = signatureFactory;
> +    }
> +
> +    @BeforeClass
> +    public static void setupClientAndServer() throws Exception {
> +        sshd =
> CoreTestSupportUtils.setupTestServer(OpenSSHCertificateTest.class);
> +        sshd.start();
> +        port = sshd.getPort();
> +
> +        client =
> CoreTestSupportUtils.setupTestClient(OpenSSHCertificateTest.class);
> +        client.start();
> +    }
> +
> +    @AfterClass
> +    public static void tearDownClientAndServer() throws Exception {
> +        if (sshd != null) {
> +            try {
> +                sshd.stop(true);
> +            } finally {
> +                sshd = null;
> +            }
> +        }
> +
> +        if (client != null) {
> +            try {
> +                client.stop();
> +            } finally {
> +                client = null;
> +            }
> +        }
> +    }
> +
> +    @Parameterized.Parameters(name = "type={2}")
> +    public static List<Object[]> parameters() {
> +        List<Object[]> list = new ArrayList<>();
> +
> +        String key = "ssh_host_rsa_key";
> +        String certificate = "ssh_host_rsa_key_sha1-cert.pub";
> +        String certificateSha512 = "ssh_host_rsa_key-cert.pub";
> +
> +        // default client
> +        list.add(new Object[]{key, certificate, null});
> +        list.add(new Object[]{key, certificate,
> Arrays.asList(BuiltinSignatures.rsa_cert, BuiltinSignatures.rsa)});
> +        // client does not support cert
> +        list.add(new Object[]{key, certificate,
> Collections.singletonList(BuiltinSignatures.rsa)});
> +        // rsa variant
> +        list.add(new Object[]{key, certificateSha512,
> Arrays.asList(BuiltinSignatures.rsaSHA512_cert,
> BuiltinSignatures.rsaSHA512)});
> +        list.add(new Object[]{key, certificateSha512,
> Arrays.asList(BuiltinSignatures.rsa_cert, BuiltinSignatures.rsaSHA512)});
> +
> +        return Collections.unmodifiableList(list);
> +    }
> +
> +    @Test
> +    public void testOpenSshCertificates() throws Exception {
> +        sshd.setKeyPairProvider(keyPairProvider);
> +        sshd.setHostKeyCertificateProvider(certificateProvider);
> +        if (signatureFactory != null) {
> +            client.setSignatureFactories(signatureFactory);
> +        }
> +
> +        // default client
> +        try (ClientSession s = client.connect(getCurrentTestName(),
> TEST_LOCALHOST, port)
> +            .verify(CONNECT_TIMEOUT).getSession()) {
> +            s.addPasswordIdentity(getCurrentTestName());
> +            s.auth().verify(AUTH_TIMEOUT);
> +        }
> +    }
> +
> +    @Test
> +    public void testPrincipal() throws Exception {
> +        sshd.setKeyPairProvider(keyPairProvider);
> +        sshd.setHostKeyCertificateProvider(certificateProvider);
> +        if (signatureFactory != null) {
> +            client.setSignatureFactories(signatureFactory);
> +        }
> +
> +        // invalid principal, but continue
> +        PropertyResolverUtils.updateProperty(client,
> ClientFactoryManager.ABORT_ON_INVALID_CERTIFICATE, false);
> +        try (ClientSession s = client.connect(getCurrentTestName(),
> "localhost", port)
> +            .verify(CONNECT_TIMEOUT).getSession()) {
> +            s.addPasswordIdentity(getCurrentTestName());
> +            s.auth().verify(AUTH_TIMEOUT);
> +        }
> +
> +        // invalid principal, abort
> +        PropertyResolverUtils.updateProperty(client,
> ClientFactoryManager.ABORT_ON_INVALID_CERTIFICATE, true);
> +        try (ClientSession s = client.connect(getCurrentTestName(),
> "localhost", port)
> +            .verify(CONNECT_TIMEOUT).getSession()) {
> +            s.addPasswordIdentity(getCurrentTestName());
> +            s.auth().verify(AUTH_TIMEOUT);
> +
> +            // in case client does not support cert, no exception should
> be thrown
> +
> Assert.assertFalse(client.getSignatureFactories().contains(BuiltinSignatures.rsa_cert));
> +        } catch (SshException e) {
> +
> Assert.assertEquals(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
> e.getDisconnectCode());
> +        }
> +    }
> +}
> diff --git
> a/sshd-core/src/test/resources/org/apache/sshd/common/signature/example-ca
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/example-ca
> new file mode 100644
> index 0000000..5c1f3cd
> --- /dev/null
> +++
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/example-ca
> @@ -0,0 +1,49 @@
> +-----BEGIN OPENSSH PRIVATE KEY-----
> +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
> +-----END OPENSSH PRIVATE KEY-----
> diff --git
> a/sshd-core/src/test/resources/org/apache/sshd/common/signature/example-ca.pub
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/example-ca.pub
> new file mode 100644
> index 0000000..c5776fc
> --- /dev/null
> +++
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/example-ca.pub
> @@ -0,0 +1 @@
> +ssh-rsa
> AAAAB3NzaC1yc2EAAAADAQABAAACAQDC9ueamUQ2HJDZvS9L6fpb4umROUrPrRjb6TaIuH3K8h9uT8+8oJIM4Pqn7mlSMvX0Vi8VUCpMQ2fZnqukFrB5W8jNdGG7a/IEDF/Yg3dON1D7I43GRo/I7Qk9EGSeDayvIeh0g6dqalx7dyIg83GvsuqC+dZlQpLdFML1PciaHur1NHF9zDyLKjb+Qfxi738Y3tmfSFOd37r0r2dWLqRQ0uDk1uY2fF0YYnQonvpW3Sc6pS8lxJXAOPRYs0a3IG0AQKvzXxjg3U4NYKU0rJ8LLpoeEYbgSYwCPg6RWYg618Yu6NU7OjdQ0i3ZfoCh4O/xuW+oz/RoEEkM8bzDr7GuLeluX7u5jUXUYoeBCbgdp21xTIlCezmzYhZYb6X5Vuk481xXCaEvHAJz++Qz8M3K7YWGilgynFFm6UUHCefgGirei10X4x24FpnTxKmLpxgGWlW1
> [...]
> diff --git
> a/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key
> new file mode 100644
> index 0000000..1db1976
> --- /dev/null
> +++
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key
> @@ -0,0 +1,38 @@
> +-----BEGIN OPENSSH PRIVATE KEY-----
> +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
> +-----END OPENSSH PRIVATE KEY-----
> diff --git
> a/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key-cert.pub
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key-cert.pub
> new file mode 100644
> index 0000000..c570d82
> --- /dev/null
> +++
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key-cert.pub
> @@ -0,0 +1 @@
> +ssh-rsa-cert-...@openssh.com
> AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgaLndJbPMJA6TJ5Gd1R+vScUdZaKELX/nEdWsfMmmOZ8AAAADAQABAAABgQDq0+az6bCKulks7E/RQBGUNlo8Pxe8Ylwc7KF2PxTrlGtD2qEjNyLMkBGAJMOME5PKiAoUNpmgxA/2oDbNQUEQpHOISnqz58SrkYwtlbRPntiu1bfZKQBxgs8oP0nVZU30ck9CmUVWdOY3R+sy85lL/g1vEwgGQPJHmnARg76TlX1xaDaR2RsHR+dz5MfPgZUn3C1SSIWSEoiuTNoh9uthHulybAhnHccTCt+90HN7nUXGSuoiu6P+Wg0p3oqClMk548MOBtSNyPFsSKFEOoivPHOfIuP1j5Of+j9iYhTp6bIrqKkUeX/y6s9iuw/d/ZlKYp2/h913iCHQ+VlJVJa/C96FXzudZ67pmuJ
> [...]
> diff --git
> a/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key.pub
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key.pub
> new file mode 100644
> index 0000000..65bea39
> --- /dev/null
> +++
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key.pub
> @@ -0,0 +1 @@
> +ssh-rsa
> AAAAB3NzaC1yc2EAAAADAQABAAABgQDq0+az6bCKulks7E/RQBGUNlo8Pxe8Ylwc7KF2PxTrlGtD2qEjNyLMkBGAJMOME5PKiAoUNpmgxA/2oDbNQUEQpHOISnqz58SrkYwtlbRPntiu1bfZKQBxgs8oP0nVZU30ck9CmUVWdOY3R+sy85lL/g1vEwgGQPJHmnARg76TlX1xaDaR2RsHR+dz5MfPgZUn3C1SSIWSEoiuTNoh9uthHulybAhnHccTCt+90HN7nUXGSuoiu6P+Wg0p3oqClMk548MOBtSNyPFsSKFEOoivPHOfIuP1j5Of+j9iYhTp6bIrqKkUeX/y6s9iuw/d/ZlKYp2/h913iCHQ+VlJVJa/C96FXzudZ67pmuJKIesGlYfQLz96Q/Tq5F+QuJm0wG0qUuq3Aa+LZcobOSw+Th/WEmQ9j9O6stZ4Pfh/BPUwPa12u19pLgKH8m25DYLjBLYZO+Zu
> [...]
> diff --git
> a/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key_sha1-cert.pub
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key_sha1-cert.pub
> new file mode 100644
> index 0000000..67116fa
> --- /dev/null
> +++
> b/sshd-core/src/test/resources/org/apache/sshd/common/signature/ssh_host_rsa_key_sha1-cert.pub
> @@ -0,0 +1 @@
> +ssh-rsa-cert-...@openssh.com
> AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgH+fKXukuzsdEZJ/q+yMiHyxAjVOMR3ZNBfiwxjfKVc0AAAADAQABAAABgQDq0+az6bCKulks7E/RQBGUNlo8Pxe8Ylwc7KF2PxTrlGtD2qEjNyLMkBGAJMOME5PKiAoUNpmgxA/2oDbNQUEQpHOISnqz58SrkYwtlbRPntiu1bfZKQBxgs8oP0nVZU30ck9CmUVWdOY3R+sy85lL/g1vEwgGQPJHmnARg76TlX1xaDaR2RsHR+dz5MfPgZUn3C1SSIWSEoiuTNoh9uthHulybAhnHccTCt+90HN7nUXGSuoiu6P+Wg0p3oqClMk548MOBtSNyPFsSKFEOoivPHOfIuP1j5Of+j9iYhTp6bIrqKkUeX/y6s9iuw/d/ZlKYp2/h913iCHQ+VlJVJa/C96FXzudZ67pmuJ
> [...]
>
>

-- 
------------------------
Guillaume Nodet

Reply via email to