All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sshd.common.signature.SignatureFactory Maven / Gradle / Ivy

There is a newer version: 2.4.1.Final
Show newest version
/*
 * 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.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.apache.sshd.common.BuiltinFactory;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.util.GenericUtils;

/**
 * @author Apache MINA SSHD Project
 */
public interface SignatureFactory extends BuiltinFactory {
    /**
     * ECC signature types in ascending order of preference (i.e., most preferred 1st)
     */
    List ECC_SIGNATURE_TYPE_PREFERENCES =
        Collections.unmodifiableList(
            Arrays.asList(
                    KeyPairProvider.ECDSA_SHA2_NISTP521,
                    KeyPairProvider.ECDSA_SHA2_NISTP384,
                    KeyPairProvider.ECDSA_SHA2_NISTP256));

    /**
     * RSA signature types in ascending order of preference (i.e., most preferred 1st)
     */
    List RSA_SIGNATURE_TYPE_PREFERENCES =
        Collections.unmodifiableList(
            Arrays.asList(
                KeyUtils.RSA_SHA512_KEY_TYPE_ALIAS,
                KeyUtils.RSA_SHA256_KEY_TYPE_ALIAS,
                KeyPairProvider.SSH_RSA));

    /**
     * @param provided The provided signature key types
     * @param factories The available signature factories
     * @return A {@link List} of the matching available factories names
     * that are also listed as provided ones - in the same order
     * of preference as they appear in the available listing. May be
     * empty if no provided signature key types, or no available ones
     * or no match found.
     * @see #resolveSignatureFactoryNamesProposal(Iterable, Collection)
     */
    static List resolveSignatureFactoriesProposal(
            Iterable provided, Collection> factories) {
        return resolveSignatureFactoryNamesProposal(provided, NamedResource.getNameList(factories));
    }

    /**
     * @param provided The provided signature key types
     * @param available The available signature factories names
     * @return A {@link List} of the matching available factories names
     * that are also listed as provided ones - in the same order
     * of preference as they appear in the available listing. May be
     * empty if no provided signature key types, or no available ones
     * or no match found.
     */
    static List resolveSignatureFactoryNamesProposal(
            Iterable provided, Collection available) {
        if ((provided == null) || GenericUtils.isEmpty(available)) {
            return Collections.emptyList();
        }

        // We want to preserve the original available order as it indicates the preference
        Set providedKeys = new HashSet<>();
        for (String providedType : provided) {
            Collection equivTypes =
                KeyUtils.getAllEquivalentKeyTypes(providedType);
            providedKeys.addAll(equivTypes);
        }

        if (GenericUtils.isEmpty(providedKeys)) {
            return Collections.emptyList();
        }

        List supported = new ArrayList<>(available);
        for (int index = 0; index < supported.size(); index++) {
            String kt = supported.get(index);
            if (!providedKeys.contains(kt)) {
                supported.remove(index);
                index--;    // compensate for auto-increment
            }
        }

        return supported;
    }

    // returns -1 or > size() if append to end
    static int resolvePreferredSignaturePosition(
            List> factories, NamedFactory factory) {
        if (GenericUtils.isEmpty(factories)) {
            return -1;  // just add it to the end
        }

        String name = factory.getName();
        if (KeyPairProvider.SSH_RSA.equalsIgnoreCase(name)) {
            return -1;
        }

        int pos = RSA_SIGNATURE_TYPE_PREFERENCES.indexOf(name);
        if (pos >= 0) {
            Map posMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
            for (int index = 0, count = factories.size(); index < count; index++) {
                NamedFactory f = factories.get(index);
                String keyType = f.getName();
                String canonicalName = KeyUtils.getCanonicalKeyType(keyType);
                if (!KeyPairProvider.SSH_RSA.equalsIgnoreCase(canonicalName)) {
                    continue;   // debug breakpoint
                }

                posMap.put(keyType, index);
            }

            return resolvePreferredSignaturePosition(RSA_SIGNATURE_TYPE_PREFERENCES, pos, posMap);
        }

        pos = ECC_SIGNATURE_TYPE_PREFERENCES.indexOf(name);
        if (pos >= 0) {
            Map posMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
            for (int index = 0, count = factories.size(); index < count; index++) {
                NamedFactory f = factories.get(index);
                String keyType = f.getName();
                if (!ECC_SIGNATURE_TYPE_PREFERENCES.contains(keyType)) {
                    continue;   // debug breakpoint
                }

                posMap.put(keyType, index);
            }

            return resolvePreferredSignaturePosition(ECC_SIGNATURE_TYPE_PREFERENCES, pos, posMap);
        }

        return -1;  // no special preference - stick it as last
    }

    static int resolvePreferredSignaturePosition(
            List preferredOrder, int prefValue, Map posMap) {
        if (GenericUtils.isEmpty(preferredOrder) || (prefValue < 0) || GenericUtils.isEmpty(posMap)) {
            return -1;
        }

        int posValue = -1;
        for (Map.Entry pe : posMap.entrySet()) {
            String name = pe.getKey();
            int order = preferredOrder.indexOf(name);
            if (order < 0) {
                continue;   // should not happen, but tolerate
            }

            Integer curIndex = pe.getValue();
            int resIndex;
            if (order < prefValue) {
                resIndex = curIndex.intValue() + 1;
            } else if (order > prefValue) {
                resIndex = curIndex.intValue(); // by using same index we insert in front of it in effect
            } else {
                continue;   // should not happen, but tolerate
            }

            // Preferred factories should be as close as possible to the beginning of the list
            if ((posValue < 0) || (resIndex < posValue)) {
                posValue = resIndex;
            }
        }

        return posValue;
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy