http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java deleted file mode 100644 index bceca59..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHECDSAPrivateKeyEntryDecoder.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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.loader.openssh; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchProviderException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.util.Objects; - -import org.apache.sshd.common.cipher.ECCurves; -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.KeyEntryResolver; -import org.apache.sshd.common.config.keys.KeyUtils; -import org.apache.sshd.common.config.keys.impl.AbstractPrivateKeyEntryDecoder; -import org.apache.sshd.common.util.security.SecurityUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class OpenSSHECDSAPrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDecoder<ECPublicKey, ECPrivateKey> { - public static final OpenSSHECDSAPrivateKeyEntryDecoder INSTANCE = new OpenSSHECDSAPrivateKeyEntryDecoder(); - - public OpenSSHECDSAPrivateKeyEntryDecoder() { - super(ECPublicKey.class, ECPrivateKey.class, ECCurves.KEY_TYPES); - } - - @Override - public ECPrivateKey decodePrivateKey(String keyType, FilePasswordProvider passwordProvider, InputStream keyData) - throws IOException, GeneralSecurityException { - ECCurves curve = ECCurves.fromKeyType(keyType); - if (curve == null) { - throw new InvalidKeySpecException("Not an EC curve name: " + keyType); - } - - if (!SecurityUtils.isECCSupported()) { - throw new NoSuchProviderException("ECC not supported"); - } - - String keyCurveName = curve.getName(); - // see rfc5656 section 3.1 - String encCurveName = KeyEntryResolver.decodeString(keyData); - if (!keyCurveName.equals(encCurveName)) { - throw new InvalidKeySpecException("Mismatched key curve name (" + keyCurveName + ") vs. encoded one (" + encCurveName + ")"); - } - - byte[] pubKey = KeyEntryResolver.readRLEBytes(keyData); - Objects.requireNonNull(pubKey, "No public point"); // TODO validate it is a valid ECPoint - BigInteger s = KeyEntryResolver.decodeBigInt(keyData); - ECParameterSpec params = curve.getParameters(); - return generatePrivateKey(new ECPrivateKeySpec(s, params)); - } - - @Override - public String encodePrivateKey(OutputStream s, ECPrivateKey key) throws IOException { - Objects.requireNonNull(key, "No private key provided"); - return null; - } - - @Override - public ECPublicKey recoverPublicKey(ECPrivateKey prvKey) throws GeneralSecurityException { - ECCurves curve = ECCurves.fromECKey(prvKey); - if (curve == null) { - throw new InvalidKeyException("Unknown curve"); - } - // TODO see how we can figure out the public value - return super.recoverPublicKey(prvKey); - } - - @Override - public ECPublicKey clonePublicKey(ECPublicKey key) throws GeneralSecurityException { - if (!SecurityUtils.isECCSupported()) { - throw new NoSuchProviderException("ECC not supported"); - } - - if (key == null) { - return null; - } - - ECParameterSpec params = key.getParams(); - if (params == null) { - throw new InvalidKeyException("Missing parameters in key"); - } - - return generatePublicKey(new ECPublicKeySpec(key.getW(), params)); - } - - @Override - public ECPrivateKey clonePrivateKey(ECPrivateKey key) throws GeneralSecurityException { - if (!SecurityUtils.isECCSupported()) { - throw new NoSuchProviderException("ECC not supported"); - } - - if (key == null) { - return null; - } - - ECParameterSpec params = key.getParams(); - if (params == null) { - throw new InvalidKeyException("Missing parameters in key"); - } - - return generatePrivateKey(new ECPrivateKeySpec(key.getS(), params)); - } - - @Override - public KeyFactory getKeyFactoryInstance() throws GeneralSecurityException { - if (SecurityUtils.isECCSupported()) { - return SecurityUtils.getKeyFactory(KeyUtils.EC_ALGORITHM); - } else { - throw new NoSuchProviderException("ECC not supported"); - } - } - - @Override - public KeyPair generateKeyPair(int keySize) throws GeneralSecurityException { - ECCurves curve = ECCurves.fromCurveSize(keySize); - if (curve == null) { - throw new InvalidKeySpecException("Unknown curve for key size=" + keySize); - } - - KeyPairGenerator gen = getKeyPairGenerator(); - gen.initialize(curve.getParameters()); - return gen.generateKeyPair(); - } - - @Override - public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException { - if (SecurityUtils.isECCSupported()) { - return SecurityUtils.getKeyPairGenerator(KeyUtils.EC_ALGORITHM); - } else { - throw new NoSuchProviderException("ECC not supported"); - } - } -}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java deleted file mode 100644 index 95db256..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParser.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * 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.loader.openssh; - -import java.io.ByteArrayInputStream; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.StreamCorruptedException; -import java.nio.charset.StandardCharsets; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.util.AbstractMap.SimpleImmutableEntry; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TreeMap; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.KeyEntryResolver; -import org.apache.sshd.common.config.keys.KeyUtils; -import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder; -import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder; -import org.apache.sshd.common.config.keys.loader.AbstractKeyPairResourceParser; -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.ValidateUtils; -import org.apache.sshd.common.util.buffer.BufferUtils; -import org.apache.sshd.common.util.io.IoUtils; -import org.apache.sshd.common.util.security.SecurityUtils; - -/** - * Basic support for <A HREF="http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?rev=1.1&content-type=text/x-cvsweb-markup">OpenSSH key file(s)</A> - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class OpenSSHKeyPairResourceParser extends AbstractKeyPairResourceParser { - public static final String BEGIN_MARKER = "BEGIN OPENSSH PRIVATE KEY"; - public static final List<String> BEGINNERS = - Collections.unmodifiableList(Collections.singletonList(BEGIN_MARKER)); - - public static final String END_MARKER = "END OPENSSH PRIVATE KEY"; - public static final List<String> ENDERS = - Collections.unmodifiableList(Collections.singletonList(END_MARKER)); - - public static final String AUTH_MAGIC = "openssh-key-v1"; - public static final OpenSSHKeyPairResourceParser INSTANCE = new OpenSSHKeyPairResourceParser(); - - private static final byte[] AUTH_MAGIC_BYTES = AUTH_MAGIC.getBytes(StandardCharsets.UTF_8); - private static final Map<String, PrivateKeyEntryDecoder<?, ?>> BY_KEY_TYPE_DECODERS_MAP = - new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - - private static final Map<Class<?>, PrivateKeyEntryDecoder<?, ?>> BY_KEY_CLASS_DECODERS_MAP = - new HashMap<>(); - - static { - registerPrivateKeyEntryDecoder(OpenSSHRSAPrivateKeyDecoder.INSTANCE); - registerPrivateKeyEntryDecoder(OpenSSHDSSPrivateKeyEntryDecoder.INSTANCE); - - if (SecurityUtils.isECCSupported()) { - registerPrivateKeyEntryDecoder(OpenSSHECDSAPrivateKeyEntryDecoder.INSTANCE); - } - if (SecurityUtils.isEDDSACurveSupported()) { - registerPrivateKeyEntryDecoder(SecurityUtils.getOpenSSHEDDSAPrivateKeyEntryDecoder()); - } - } - - public OpenSSHKeyPairResourceParser() { - super(BEGINNERS, ENDERS); - } - - @Override - public Collection<KeyPair> extractKeyPairs( - String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream) - throws IOException, GeneralSecurityException { - stream = validateStreamMagicMarker(resourceKey, stream); - - String cipher = KeyEntryResolver.decodeString(stream); - if (!OpenSSHParserContext.IS_NONE_CIPHER.test(cipher)) { - throw new NoSuchAlgorithmException("Unsupported cipher: " + cipher); - } - - boolean debugEnabled = log.isDebugEnabled(); - if (debugEnabled) { - log.debug("extractKeyPairs({}) cipher={}", resourceKey, cipher); - } - - String kdfName = KeyEntryResolver.decodeString(stream); - if (!OpenSSHParserContext.IS_NONE_KDF.test(kdfName)) { - throw new NoSuchAlgorithmException("Unsupported KDF: " + kdfName); - } - - byte[] kdfOptions = KeyEntryResolver.readRLEBytes(stream); - if (debugEnabled) { - log.debug("extractKeyPairs({}) KDF={}, options={}", - resourceKey, kdfName, BufferUtils.toHex(':', kdfOptions)); - } - - int numKeys = KeyEntryResolver.decodeInt(stream); - if (numKeys <= 0) { - if (debugEnabled) { - log.debug("extractKeyPairs({}) no encoded keys", resourceKey); - } - return Collections.emptyList(); - } - - List<PublicKey> publicKeys = new ArrayList<>(numKeys); - OpenSSHParserContext context = new OpenSSHParserContext(cipher, kdfName, kdfOptions); - boolean traceEnabled = log.isTraceEnabled(); - for (int index = 1; index <= numKeys; index++) { - PublicKey pubKey = readPublicKey(resourceKey, context, stream); - ValidateUtils.checkNotNull(pubKey, "Empty public key #%d in %s", index, resourceKey); - if (traceEnabled) { - log.trace("extractKeyPairs({}) read public key #{}: {} {}", - resourceKey, index, KeyUtils.getKeyType(pubKey), KeyUtils.getFingerPrint(pubKey)); - } - publicKeys.add(pubKey); - } - - byte[] privateData = KeyEntryResolver.readRLEBytes(stream); - try (InputStream bais = new ByteArrayInputStream(privateData)) { - return readPrivateKeys(resourceKey, context, publicKeys, passwordProvider, bais); - } - } - - protected PublicKey readPublicKey( - String resourceKey, OpenSSHParserContext context, InputStream stream) - throws IOException, GeneralSecurityException { - byte[] keyData = KeyEntryResolver.readRLEBytes(stream); - try (InputStream bais = new ByteArrayInputStream(keyData)) { - String keyType = KeyEntryResolver.decodeString(bais); - PublicKeyEntryDecoder<?, ?> decoder = KeyUtils.getPublicKeyEntryDecoder(keyType); - if (decoder == null) { - throw new NoSuchAlgorithmException("Unsupported key type (" + keyType + ") in " + resourceKey); - } - - return decoder.decodePublicKey(keyType, bais); - } - } - - protected List<KeyPair> readPrivateKeys( - String resourceKey, OpenSSHParserContext context, Collection<? extends PublicKey> publicKeys, - FilePasswordProvider passwordProvider, InputStream stream) - throws IOException, GeneralSecurityException { - if (GenericUtils.isEmpty(publicKeys)) { - return Collections.emptyList(); - } - - boolean traceEnabled = log.isTraceEnabled(); - int check1 = KeyEntryResolver.decodeInt(stream); - int check2 = KeyEntryResolver.decodeInt(stream); - if (traceEnabled) { - log.trace("readPrivateKeys({}) check1=0x{}, check2=0x{}", - resourceKey, Integer.toHexString(check1), Integer.toHexString(check2)); - } - - List<KeyPair> keyPairs = new ArrayList<>(publicKeys.size()); - for (PublicKey pubKey : publicKeys) { - String pubType = KeyUtils.getKeyType(pubKey); - int keyIndex = keyPairs.size() + 1; - if (traceEnabled) { - log.trace("extractKeyPairs({}) read private key #{}: {}", - resourceKey, keyIndex, pubType); - } - - Map.Entry<PrivateKey, String> prvData = readPrivateKey(resourceKey, context, pubType, passwordProvider, stream); - PrivateKey prvKey = (prvData == null) ? null : prvData.getKey(); - ValidateUtils.checkNotNull(prvKey, "Empty private key #%d in %s", keyIndex, resourceKey); - - String prvType = KeyUtils.getKeyType(prvKey); - ValidateUtils.checkTrue(Objects.equals(pubType, prvType), - "Mismatched public (%s) vs. private (%s) key type #%d in %s", - pubType, prvType, keyIndex, resourceKey); - - if (traceEnabled) { - log.trace("extractKeyPairs({}) add private key #{}: {} {}", - resourceKey, keyIndex, prvType, prvData.getValue()); - } - keyPairs.add(new KeyPair(pubKey, prvKey)); - } - - return keyPairs; - } - - protected SimpleImmutableEntry<PrivateKey, String> readPrivateKey( - String resourceKey, OpenSSHParserContext context, String keyType, FilePasswordProvider passwordProvider, InputStream stream) - throws IOException, GeneralSecurityException { - String prvType = KeyEntryResolver.decodeString(stream); - if (!Objects.equals(keyType, prvType)) { - throw new StreamCorruptedException("Mismatched private key type: " - + ", expected=" + keyType + ", actual=" + prvType - + " in " + resourceKey); - } - - PrivateKeyEntryDecoder<?, ?> decoder = getPrivateKeyEntryDecoder(prvType); - if (decoder == null) { - throw new NoSuchAlgorithmException("Unsupported key type (" + prvType + ") in " + resourceKey); - } - - PrivateKey prvKey = decoder.decodePrivateKey(prvType, passwordProvider, stream); - if (prvKey == null) { - throw new InvalidKeyException("Cannot parse key type (" + prvType + ") in " + resourceKey); - } - - String comment = KeyEntryResolver.decodeString(stream); - return new SimpleImmutableEntry<>(prvKey, comment); - } - - protected <S extends InputStream> S validateStreamMagicMarker(String resourceKey, S stream) throws IOException { - byte[] actual = new byte[AUTH_MAGIC_BYTES.length]; - IoUtils.readFully(stream, actual); - if (!Arrays.equals(AUTH_MAGIC_BYTES, actual)) { - throw new StreamCorruptedException(resourceKey + ": Mismatched magic marker value: " + BufferUtils.toHex(':', actual)); - } - - int eos = stream.read(); - if (eos == -1) { - throw new EOFException(resourceKey + ": Premature EOF after magic marker value"); - } - - if (eos != 0) { - throw new StreamCorruptedException(resourceKey + ": Missing EOS after magic marker value: 0x" + Integer.toHexString(eos)); - } - - return stream; - } - - /** - * @param decoder The decoder to register - * @throws IllegalArgumentException if no decoder or not key type or no - * supported names for the decoder - * @see PrivateKeyEntryDecoder#getPublicKeyType() - * @see PrivateKeyEntryDecoder#getSupportedTypeNames() - */ - public static void registerPrivateKeyEntryDecoder(PrivateKeyEntryDecoder<?, ?> decoder) { - Objects.requireNonNull(decoder, "No decoder specified"); - - Class<?> pubType = Objects.requireNonNull(decoder.getPublicKeyType(), "No public key type declared"); - Class<?> prvType = Objects.requireNonNull(decoder.getPrivateKeyType(), "No private key type declared"); - synchronized (BY_KEY_CLASS_DECODERS_MAP) { - BY_KEY_CLASS_DECODERS_MAP.put(pubType, decoder); - BY_KEY_CLASS_DECODERS_MAP.put(prvType, decoder); - } - - Collection<String> names = ValidateUtils.checkNotNullAndNotEmpty(decoder.getSupportedTypeNames(), "No supported key type"); - synchronized (BY_KEY_TYPE_DECODERS_MAP) { - for (String n : names) { - PrivateKeyEntryDecoder<?, ?> prev = BY_KEY_TYPE_DECODERS_MAP.put(n, decoder); - if (prev != null) { - //noinspection UnnecessaryContinue - continue; // debug breakpoint - } - } - } - } - - /** - * @param keyType The {@code OpenSSH} key type string - e.g., {@code ssh-rsa, ssh-dss} - * - ignored if {@code null}/empty - * @return The registered {@link PrivateKeyEntryDecoder} or {code null} if not found - */ - public static PrivateKeyEntryDecoder<?, ?> getPrivateKeyEntryDecoder(String keyType) { - if (GenericUtils.isEmpty(keyType)) { - return null; - } - - synchronized (BY_KEY_TYPE_DECODERS_MAP) { - return BY_KEY_TYPE_DECODERS_MAP.get(keyType); - } - } - - /** - * @param kp The {@link KeyPair} to examine - ignored if {@code null} - * @return The matching {@link PrivateKeyEntryDecoder} provided <U>both</U> - * the public and private keys have the same decoder - {@code null} if no - * match found - * @see #getPrivateKeyEntryDecoder(Key) - */ - public static PrivateKeyEntryDecoder<?, ?> getPrivateKeyEntryDecoder(KeyPair kp) { - if (kp == null) { - return null; - } - - PrivateKeyEntryDecoder<?, ?> d1 = getPrivateKeyEntryDecoder(kp.getPublic()); - PrivateKeyEntryDecoder<?, ?> d2 = getPrivateKeyEntryDecoder(kp.getPrivate()); - if (d1 == d2) { - return d1; - } else { - return null; // some kind of mixed keys... - } - } - - /** - * @param key The {@link Key} (public or private) - ignored if {@code null} - * @return The registered {@link PrivateKeyEntryDecoder} for this key or {code null} if no match found - * @see #getPrivateKeyEntryDecoder(Class) - */ - public static PrivateKeyEntryDecoder<?, ?> getPrivateKeyEntryDecoder(Key key) { - if (key == null) { - return null; - } else { - return getPrivateKeyEntryDecoder(key.getClass()); - } - } - - /** - * @param keyType The key {@link Class} - ignored if {@code null} or not a {@link Key} - * compatible type - * @return The registered {@link PrivateKeyEntryDecoder} or {code null} if no match found - */ - public static PrivateKeyEntryDecoder<?, ?> getPrivateKeyEntryDecoder(Class<?> keyType) { - if ((keyType == null) || (!Key.class.isAssignableFrom(keyType))) { - return null; - } - - synchronized (BY_KEY_TYPE_DECODERS_MAP) { - PrivateKeyEntryDecoder<?, ?> decoder = BY_KEY_CLASS_DECODERS_MAP.get(keyType); - if (decoder != null) { - return decoder; - } - - // in case it is a derived class - for (PrivateKeyEntryDecoder<?, ?> dec : BY_KEY_CLASS_DECODERS_MAP.values()) { - Class<?> pubType = dec.getPublicKeyType(); - Class<?> prvType = dec.getPrivateKeyType(); - if (pubType.isAssignableFrom(keyType) || prvType.isAssignableFrom(keyType)) { - return dec; - } - } - } - - return null; - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHParserContext.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHParserContext.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHParserContext.java deleted file mode 100644 index 07f2a9a..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHParserContext.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.loader.openssh; - -import java.util.function.Predicate; - -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.buffer.BufferUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class OpenSSHParserContext { - public static final String NONE_CIPHER = "none"; - public static final Predicate<String> IS_NONE_CIPHER = c -> GenericUtils.isEmpty(c) || NONE_CIPHER.equalsIgnoreCase(c); - - public static final String NONE_KDF = "none"; - public static final Predicate<String> IS_NONE_KDF = c -> GenericUtils.isEmpty(c) || NONE_KDF.equalsIgnoreCase(c); - - private String cipherName; - private String kdfName; - private byte[] kdfOptions; - - public OpenSSHParserContext() { - super(); - } - - public OpenSSHParserContext(String cipherName, String kdfName, byte... kdfOptions) { - this.cipherName = cipherName; - this.kdfName = kdfName; - this.kdfOptions = kdfOptions; - } - - public String getCipherName() { - return cipherName; - } - - public void setCipherName(String cipherName) { - this.cipherName = cipherName; - } - - public String getKdfName() { - return kdfName; - } - - public void setKdfName(String kdfName) { - this.kdfName = kdfName; - } - - public byte[] getKdfOptions() { - return kdfOptions; - } - - public void setKdfOptions(byte[] kdfOptions) { - this.kdfOptions = kdfOptions; - } - - @Override - public String toString() { - return getClass().getSimpleName() - + "[cipher=" + getCipherName() - + ", kdfName=" + getKdfName() - + ", kdfOptions=" + BufferUtils.toHex(':', getKdfOptions()) - + "]"; - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java deleted file mode 100644 index 72e003f..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHRSAPrivateKeyDecoder.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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.loader.openssh; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.KeyPairGenerator; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.security.spec.RSAPrivateKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.util.Collections; -import java.util.Objects; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.KeyEntryResolver; -import org.apache.sshd.common.config.keys.KeyUtils; -import org.apache.sshd.common.config.keys.impl.AbstractPrivateKeyEntryDecoder; -import org.apache.sshd.common.keyprovider.KeyPairProvider; -import org.apache.sshd.common.util.security.SecurityUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class OpenSSHRSAPrivateKeyDecoder extends AbstractPrivateKeyEntryDecoder<RSAPublicKey, RSAPrivateKey> { - public static final BigInteger DEFAULT_PUBLIC_EXPONENT = new BigInteger("65537"); - public static final OpenSSHRSAPrivateKeyDecoder INSTANCE = new OpenSSHRSAPrivateKeyDecoder(); - - public OpenSSHRSAPrivateKeyDecoder() { - super(RSAPublicKey.class, RSAPrivateKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_RSA))); - } - - @Override - public RSAPrivateKey decodePrivateKey(String keyType, FilePasswordProvider passwordProvider, InputStream keyData) - throws IOException, GeneralSecurityException { - if (!KeyPairProvider.SSH_RSA.equals(keyType)) { // just in case we were invoked directly - throw new InvalidKeySpecException("Unexpected key type: " + keyType); - } - - BigInteger n = KeyEntryResolver.decodeBigInt(keyData); - BigInteger e = KeyEntryResolver.decodeBigInt(keyData); - if (!Objects.equals(e, DEFAULT_PUBLIC_EXPONENT)) { - log.warn("decodePrivateKey({}) non-standard RSA exponent found: {}", keyType, e); - } - - BigInteger d = KeyEntryResolver.decodeBigInt(keyData); - BigInteger inverseQmodP = KeyEntryResolver.decodeBigInt(keyData); - Objects.requireNonNull(inverseQmodP, "Missing iqmodp"); // TODO run some validation on it - BigInteger p = KeyEntryResolver.decodeBigInt(keyData); - BigInteger q = KeyEntryResolver.decodeBigInt(keyData); - BigInteger modulus = p.multiply(q); - if (!Objects.equals(n, modulus)) { - log.warn("decodePrivateKey({}) mismatched modulus values: encoded={}, calculated={}", - keyType, n, modulus); - } - - return generatePrivateKey(new RSAPrivateKeySpec(n, d)); - } - - @Override - public boolean isPublicKeyRecoverySupported() { - return true; - } - - @Override - public RSAPublicKey recoverPublicKey(RSAPrivateKey privateKey) throws GeneralSecurityException { - return KeyUtils.recoverRSAPublicKey(privateKey); - } - - @Override - public RSAPublicKey clonePublicKey(RSAPublicKey key) throws GeneralSecurityException { - if (key == null) { - return null; - } else { - return generatePublicKey(new RSAPublicKeySpec(key.getModulus(), key.getPublicExponent())); - } - } - - @Override - public RSAPrivateKey clonePrivateKey(RSAPrivateKey key) throws GeneralSecurityException { - if (key == null) { - return null; - } - - if (!(key instanceof RSAPrivateCrtKey)) { - throw new InvalidKeyException("Cannot clone a non-RSAPrivateCrtKey: " + key.getClass().getSimpleName()); - } - - RSAPrivateCrtKey rsaPrv = (RSAPrivateCrtKey) key; - return generatePrivateKey( - new RSAPrivateCrtKeySpec( - rsaPrv.getModulus(), - rsaPrv.getPublicExponent(), - rsaPrv.getPrivateExponent(), - rsaPrv.getPrimeP(), - rsaPrv.getPrimeQ(), - rsaPrv.getPrimeExponentP(), - rsaPrv.getPrimeExponentQ(), - rsaPrv.getCrtCoefficient())); - } - - @Override - public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException { - return SecurityUtils.getKeyPairGenerator(KeyUtils.RSA_ALGORITHM); - } - - @Override - public KeyFactory getKeyFactoryInstance() throws GeneralSecurityException { - return SecurityUtils.getKeyFactory(KeyUtils.RSA_ALGORITHM); - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java deleted file mode 100644 index bee13d6..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/AbstractPEMResourceKeyPairParser.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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.loader.pem; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.StreamCorruptedException; -import java.security.GeneralSecurityException; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import javax.security.auth.login.CredentialException; -import javax.security.auth.login.FailedLoginException; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.loader.AbstractKeyPairResourceParser; -import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser; -import org.apache.sshd.common.config.keys.loader.PrivateKeyEncryptionContext; -import org.apache.sshd.common.config.keys.loader.PrivateKeyObfuscator; -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.ValidateUtils; -import org.apache.sshd.common.util.buffer.BufferUtils; - -/** - * Base class for PEM file key-pair loaders - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public abstract class AbstractPEMResourceKeyPairParser - extends AbstractKeyPairResourceParser - implements KeyPairPEMResourceParser { - private final String algo; - private final String algId; - - protected AbstractPEMResourceKeyPairParser(String algo, String algId, List<String> beginners, List<String> enders) { - super(beginners, enders); - this.algo = ValidateUtils.checkNotNullAndNotEmpty(algo, "No encryption algorithm provided"); - this.algId = ValidateUtils.checkNotNullAndNotEmpty(algId, "No algorithm identifier provided"); - } - - @Override - public String getAlgorithm() { - return algo; - } - - @Override - public String getAlgorithmIdentifier() { - return algId; - } - - @Override - public Collection<KeyPair> extractKeyPairs( - String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, List<String> lines) - throws IOException, GeneralSecurityException { - if (GenericUtils.isEmpty(lines)) { - return Collections.emptyList(); - } - - Boolean encrypted = null; - byte[] initVector = null; - String algInfo = null; - int dataStartIndex = -1; - for (int index = 0; index < lines.size(); index++) { - String line = GenericUtils.trimToEmpty(lines.get(index)); - if (GenericUtils.isEmpty(line)) { - continue; - } - - // check if header line - if not, assume data lines follow - int headerPos = line.indexOf(':'); - if (headerPos < 0) { - dataStartIndex = index; - break; - } - - if (line.startsWith("Proc-Type:")) { - if (encrypted != null) { - throw new StreamCorruptedException("Multiple encryption indicators in " + resourceKey); - } - - line = line.substring(headerPos + 1).trim(); - line = line.toUpperCase(); - encrypted = Boolean.valueOf(line.contains("ENCRYPTED")); - } else if (line.startsWith("DEK-Info:")) { - if ((initVector != null) || (algInfo != null)) { - throw new StreamCorruptedException("Multiple encryption settings in " + resourceKey); - } - - line = line.substring(headerPos + 1).trim(); - headerPos = line.indexOf(','); - if (headerPos < 0) { - throw new StreamCorruptedException(resourceKey + ": Missing encryption data values separator in line '" + line + "'"); - } - - algInfo = line.substring(0, headerPos).trim(); - - String algInitVector = line.substring(headerPos + 1).trim(); - initVector = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, algInitVector); - } - } - - if (dataStartIndex < 0) { - throw new StreamCorruptedException("No data lines (only headers or empty) found in " + resourceKey); - } - - List<String> dataLines = lines.subList(dataStartIndex, lines.size()); - if ((encrypted != null) || (algInfo != null) || (initVector != null)) { - if (passwordProvider == null) { - throw new CredentialException("Missing password provider for encrypted resource=" + resourceKey); - } - - String password = passwordProvider.getPassword(resourceKey); - if (GenericUtils.isEmpty(password)) { - throw new FailedLoginException("No password data for encrypted resource=" + resourceKey); - } - - PrivateKeyEncryptionContext encContext = new PrivateKeyEncryptionContext(algInfo); - encContext.setPassword(password); - encContext.setInitVector(initVector); - byte[] encryptedData = KeyPairResourceParser.extractDataBytes(dataLines); - byte[] decodedData = applyPrivateKeyCipher(encryptedData, encContext, false); - try (InputStream bais = new ByteArrayInputStream(decodedData)) { - return extractKeyPairs(resourceKey, beginMarker, endMarker, passwordProvider, bais); - } - } - - return super.extractKeyPairs(resourceKey, beginMarker, endMarker, passwordProvider, dataLines); - } - - protected byte[] applyPrivateKeyCipher(byte[] bytes, PrivateKeyEncryptionContext encContext, boolean encryptIt) throws GeneralSecurityException { - String cipherName = encContext.getCipherName(); - PrivateKeyObfuscator o = encContext.resolvePrivateKeyObfuscator(); - if (o == null) { - throw new NoSuchAlgorithmException("decryptPrivateKeyData(" + encContext + ")[encrypt=" + encryptIt + "] unknown cipher: " + cipherName); - } - - if (encryptIt) { - byte[] initVector = encContext.getInitVector(); - if (GenericUtils.isEmpty(initVector)) { - initVector = o.generateInitializationVector(encContext); - encContext.setInitVector(initVector); - } - } - - return o.applyPrivateKeyCipher(bytes, encContext, encryptIt); - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/DSSPEMResourceKeyPairParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/DSSPEMResourceKeyPairParser.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/DSSPEMResourceKeyPairParser.java deleted file mode 100644 index 0c357af..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/DSSPEMResourceKeyPairParser.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.loader.pem; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StreamCorruptedException; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.spec.DSAPrivateKeySpec; -import java.security.spec.DSAPublicKeySpec; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.KeyUtils; -import org.apache.sshd.common.util.io.NoCloseInputStream; -import org.apache.sshd.common.util.io.der.ASN1Object; -import org.apache.sshd.common.util.io.der.ASN1Type; -import org.apache.sshd.common.util.io.der.DERParser; -import org.apache.sshd.common.util.security.SecurityUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class DSSPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairParser { - // Not exactly according to standard but good enough - public static final String BEGIN_MARKER = "BEGIN DSA PRIVATE KEY"; - public static final List<String> BEGINNERS = - Collections.unmodifiableList(Collections.singletonList(BEGIN_MARKER)); - - public static final String END_MARKER = "END DSA PRIVATE KEY"; - public static final List<String> ENDERS = - Collections.unmodifiableList(Collections.singletonList(END_MARKER)); - - /** - * @see <A HREF="https://tools.ietf.org/html/rfc3279#section-2.3.2">RFC-3279 section 2.3.2</A> - */ - public static final String DSS_OID = "1.2.840.10040.4.1"; - - public static final DSSPEMResourceKeyPairParser INSTANCE = new DSSPEMResourceKeyPairParser(); - - public DSSPEMResourceKeyPairParser() { - super(KeyUtils.DSS_ALGORITHM, DSS_OID, BEGINNERS, ENDERS); - } - - @Override - public Collection<KeyPair> extractKeyPairs( - String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream) - throws IOException, GeneralSecurityException { - KeyPair kp = decodeDSSKeyPair(SecurityUtils.getKeyFactory(KeyUtils.DSS_ALGORITHM), stream, false); - return Collections.singletonList(kp); - } - - /** - * <p>The ASN.1 syntax for the private key:</P> - * <pre><code> - * DSAPrivateKey ::= SEQUENCE { - * version Version, - * p INTEGER, - * q INTEGER, - * g INTEGER, - * y INTEGER, - * x INTEGER - * } - * </code></pre> - * @param kf The {@link KeyFactory} To use to generate the keys - * @param s The {@link InputStream} containing the encoded bytes - * @param okToClose <code>true</code> if the method may close the input - * stream regardless of success or failure - * @return The recovered {@link KeyPair} - * @throws IOException If failed to read or decode the bytes - * @throws GeneralSecurityException If failed to generate the keys - */ - public static KeyPair decodeDSSKeyPair(KeyFactory kf, InputStream s, boolean okToClose) - throws IOException, GeneralSecurityException { - ASN1Object sequence; - try (DERParser parser = new DERParser(NoCloseInputStream.resolveInputStream(s, okToClose))) { - sequence = parser.readObject(); - } - - if (!ASN1Type.SEQUENCE.equals(sequence.getObjType())) { - throw new IOException("Invalid DER: not a sequence: " + sequence.getObjType()); - } - - // Parse inside the sequence - try (DERParser parser = sequence.createParser()) { - // Skip version - ASN1Object version = parser.readObject(); - if (version == null) { - throw new StreamCorruptedException("No version"); - } - - BigInteger p = parser.readObject().asInteger(); - BigInteger q = parser.readObject().asInteger(); - BigInteger g = parser.readObject().asInteger(); - BigInteger y = parser.readObject().asInteger(); - BigInteger x = parser.readObject().asInteger(); - PublicKey pubKey = kf.generatePublic(new DSAPublicKeySpec(y, p, q, g)); - PrivateKey prvKey = kf.generatePrivate(new DSAPrivateKeySpec(x, p, q, g)); - return new KeyPair(pubKey, prvKey); - } - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java deleted file mode 100644 index dd8d2ea..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/ECDSAPEMResourceKeyPairParser.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * 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.loader.pem; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StreamCorruptedException; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.NoSuchProviderException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECPoint; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.util.AbstractMap.SimpleImmutableEntry; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.apache.sshd.common.cipher.ECCurves; -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.KeyUtils; -import org.apache.sshd.common.util.io.NoCloseInputStream; -import org.apache.sshd.common.util.io.der.ASN1Object; -import org.apache.sshd.common.util.io.der.ASN1Type; -import org.apache.sshd.common.util.io.der.DERParser; -import org.apache.sshd.common.util.security.SecurityUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class ECDSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairParser { - public static final String BEGIN_MARKER = "BEGIN EC PRIVATE KEY"; - public static final List<String> BEGINNERS = - Collections.unmodifiableList(Collections.singletonList(BEGIN_MARKER)); - - public static final String END_MARKER = "END EC PRIVATE KEY"; - public static final List<String> ENDERS = - Collections.unmodifiableList(Collections.singletonList(END_MARKER)); - - /** - * @see <A HREF="https://tools.ietf.org/html/rfc3279#section-2.3.5">RFC-3279 section 2.3.5</A> - */ - public static final String ECDSA_OID = "1.2.840.10045.2.1"; - - public static final ECDSAPEMResourceKeyPairParser INSTANCE = new ECDSAPEMResourceKeyPairParser(); - - public ECDSAPEMResourceKeyPairParser() { - super(KeyUtils.EC_ALGORITHM, ECDSA_OID, BEGINNERS, ENDERS); - } - - @Override - public Collection<KeyPair> extractKeyPairs( - String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream) - throws IOException, GeneralSecurityException { - Map.Entry<ECPublicKeySpec, ECPrivateKeySpec> spec = decodeECPrivateKeySpec(stream, false); - if (!SecurityUtils.isECCSupported()) { - throw new NoSuchProviderException("ECC not supported"); - } - - KeyFactory kf = SecurityUtils.getKeyFactory(KeyUtils.EC_ALGORITHM); - ECPublicKey pubKey = (ECPublicKey) kf.generatePublic(spec.getKey()); - ECPrivateKey prvKey = (ECPrivateKey) kf.generatePrivate(spec.getValue()); - KeyPair kp = new KeyPair(pubKey, prvKey); - return Collections.singletonList(kp); - } - - /** - * <P>ASN.1 syntax according to rfc5915 is:</P></BR> - * <PRE><CODE> - * ECPrivateKey ::= SEQUENCE { - * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), - * privateKey OCTET STRING, - * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, - * publicKey [1] BIT STRING OPTIONAL - * } - * </CODE></PRE> - * <P><I>ECParameters</I> syntax according to RFC5480:</P></BR> - * <PRE><CODE> - * ECParameters ::= CHOICE { - * namedCurve OBJECT IDENTIFIER - * -- implicitCurve NULL - * -- specifiedCurve SpecifiedECDomain - * } - * </CODE></PRE> - * @param inputStream The {@link InputStream} containing the DER encoded data - * @param okToClose {@code true} if OK to close the DER stream once parsing complete - * @return The decoded {@link SimpleImmutableEntry} of {@link ECPublicKeySpec} and {@link ECPrivateKeySpec} - * @throws IOException If failed to to decode the DER stream - */ - public static SimpleImmutableEntry<ECPublicKeySpec, ECPrivateKeySpec> decodeECPrivateKeySpec(InputStream inputStream, boolean okToClose) throws IOException { - ASN1Object sequence; - try (DERParser parser = new DERParser(NoCloseInputStream.resolveInputStream(inputStream, okToClose))) { - sequence = parser.readObject(); - } - - if (!ASN1Type.SEQUENCE.equals(sequence.getObjType())) { - throw new IOException("Invalid DER: not a sequence: " + sequence.getObjType()); - } - - // Parse inside the sequence - try (DERParser parser = sequence.createParser()) { - ECPrivateKeySpec prvSpec = decodeECPrivateKeySpec(parser); - ECCurves curve = ECCurves.fromCurveParameters(prvSpec.getParams()); - if (curve == null) { - throw new StreamCorruptedException("Unknown curve"); - } - - ECPoint w = decodeECPublicKeyValue(curve, parser); - ECPublicKeySpec pubSpec = new ECPublicKeySpec(w, prvSpec.getParams()); - return new SimpleImmutableEntry<>(pubSpec, prvSpec); - } - } - - public static final ECPrivateKeySpec decodeECPrivateKeySpec(DERParser parser) throws IOException { - // see openssl asn1parse -inform PEM -in ...file... -dump - ASN1Object versionObject = parser.readObject(); // Skip version - if (versionObject == null) { - throw new StreamCorruptedException("No version"); - } - - // as per RFC-5915 section 3 - BigInteger version = versionObject.asInteger(); - if (!BigInteger.ONE.equals(version)) { - throw new StreamCorruptedException("Bad version value: " + version); - } - - ASN1Object keyObject = parser.readObject(); - if (keyObject == null) { - throw new StreamCorruptedException("No private key value"); - } - - ASN1Type objType = keyObject.getObjType(); - if (!ASN1Type.OCTET_STRING.equals(objType)) { - throw new StreamCorruptedException("Non-matching private key object type: " + objType); - } - - ASN1Object paramsObject = parser.readObject(); - if (paramsObject == null) { - throw new StreamCorruptedException("No parameters value"); - } - - // TODO make sure params object tag is 0xA0 - - final List<Integer> curveOID; - try (DERParser paramsParser = paramsObject.createParser()) { - ASN1Object namedCurve = paramsParser.readObject(); - if (namedCurve == null) { - throw new StreamCorruptedException("Missing named curve parameter"); - } - - curveOID = namedCurve.asOID(); - } - - ECCurves curve = ECCurves.fromOIDValue(curveOID); - if (curve == null) { - throw new StreamCorruptedException("Unknown curve OID: " + curveOID); - } - - BigInteger s = ECCurves.octetStringToInteger(keyObject.getPureValueBytes()); - return new ECPrivateKeySpec(s, curve.getParameters()); - } - - /** - * <P>ASN.1 syntax according to rfc5915 is:</P></BR> - * <PRE> - * publicKey [1] BIT STRING OPTIONAL - * </PRE> - * @param curve The {@link ECCurves} curve - * @param parser The {@link DERParser} assumed to be positioned at the - * start of the data - * @return The encoded {@link ECPoint} - * @throws IOException If failed to create the point - */ - public static final ECPoint decodeECPublicKeyValue(ECCurves curve, DERParser parser) throws IOException { - // see openssl asn1parse -inform PEM -in ...file... -dump - ASN1Object dataObject = parser.readObject(); - if (dataObject == null) { - throw new StreamCorruptedException("No public key data bytes"); - } - - try (DERParser dataParser = dataObject.createParser()) { - ASN1Object pointData = dataParser.readObject(); - if (pointData == null) { - throw new StreamCorruptedException("Missing public key data parameter"); - } - - ASN1Type objType = pointData.getObjType(); - if (!ASN1Type.BIT_STRING.equals(objType)) { - throw new StreamCorruptedException("Non-matching public key object type: " + objType); - } - - // see https://tools.ietf.org/html/rfc5480#section-2.2 - byte[] octets = pointData.getValue(); - return ECCurves.octetStringToEcPoint(octets); - } - } - -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/KeyPairPEMResourceParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/KeyPairPEMResourceParser.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/KeyPairPEMResourceParser.java deleted file mode 100644 index 07c7e44..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/KeyPairPEMResourceParser.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.loader.pem; - -import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public interface KeyPairPEMResourceParser extends KeyPairResourceParser { - /** - * @return The encryption algorithm name - e.g., "RSA", "DSA" - */ - String getAlgorithm(); - - /** - * @return The OID used to identify this algorithm in DER encodings - e.g., RSA=1.2.840.113549.1.1.1 - */ - String getAlgorithmIdentifier(); -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PEMResourceParserUtils.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PEMResourceParserUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PEMResourceParserUtils.java deleted file mode 100644 index b6749da..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PEMResourceParserUtils.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.loader.pem; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyPair; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TreeMap; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser; -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.ValidateUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public final class PEMResourceParserUtils { - public static final KeyPairResourceParser PROXY = new KeyPairResourceParser() { - @Override - public Collection<KeyPair> loadKeyPairs( - String resourceKey, FilePasswordProvider passwordProvider, List<String> lines) - throws IOException, GeneralSecurityException { - @SuppressWarnings("synthetic-access") - KeyPairResourceParser proxy = PROXY_HOLDER.get(); - return (proxy == null) ? Collections.<KeyPair>emptyList() : proxy.loadKeyPairs(resourceKey, passwordProvider, lines); - } - - @Override - public boolean canExtractKeyPairs(String resourceKey, List<String> lines) - throws IOException, GeneralSecurityException { - @SuppressWarnings("synthetic-access") - KeyPairResourceParser proxy = PROXY_HOLDER.get(); - return (proxy != null) && proxy.canExtractKeyPairs(resourceKey, lines); - } - }; - - private static final Map<String, KeyPairPEMResourceParser> BY_OID_MAP = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - private static final Map<String, KeyPairPEMResourceParser> BY_ALGORITHM_MAP = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - private static final AtomicReference<KeyPairResourceParser> PROXY_HOLDER = new AtomicReference<>(KeyPairResourceParser.EMPTY); - - static { - registerPEMResourceParser(RSAPEMResourceKeyPairParser.INSTANCE); - registerPEMResourceParser(DSSPEMResourceKeyPairParser.INSTANCE); - registerPEMResourceParser(ECDSAPEMResourceKeyPairParser.INSTANCE); - registerPEMResourceParser(PKCS8PEMResourceKeyPairParser.INSTANCE); - } - - private PEMResourceParserUtils() { - throw new UnsupportedOperationException("No instance"); - } - - public static void registerPEMResourceParser(KeyPairPEMResourceParser parser) { - Objects.requireNonNull(parser, "No parser to register"); - synchronized (BY_OID_MAP) { - BY_OID_MAP.put(ValidateUtils.checkNotNullAndNotEmpty(parser.getAlgorithmIdentifier(), "No OID value"), parser); - } - - synchronized (BY_ALGORITHM_MAP) { - BY_ALGORITHM_MAP.put(ValidateUtils.checkNotNullAndNotEmpty(parser.getAlgorithm(), "No algorithm value"), parser); - // Use a copy in order to avoid concurrent modifications - PROXY_HOLDER.set(KeyPairResourceParser.aggregate(new ArrayList<>(BY_ALGORITHM_MAP.values()))); - } - } - - public static KeyPairPEMResourceParser getPEMResourceParserByOid(String oid) { - if (GenericUtils.isEmpty(oid)) { - return null; - } - - synchronized (BY_OID_MAP) { - return BY_OID_MAP.get(oid); - } - } - - public static KeyPairPEMResourceParser getPEMResourceParserByAlgorithm(String algorithm) { - if (GenericUtils.isEmpty(algorithm)) { - return null; - } - - synchronized (BY_ALGORITHM_MAP) { - return BY_ALGORITHM_MAP.get(algorithm); - } - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java deleted file mode 100644 index b333f23..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParser.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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.loader.pem; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StreamCorruptedException; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.KeyUtils; -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.ValidateUtils; -import org.apache.sshd.common.util.io.IoUtils; -import org.apache.sshd.common.util.io.der.ASN1Object; -import org.apache.sshd.common.util.io.der.DERParser; -import org.apache.sshd.common.util.security.SecurityUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class PKCS8PEMResourceKeyPairParser extends AbstractPEMResourceKeyPairParser { - // Not exactly according to standard but good enough - public static final String BEGIN_MARKER = "BEGIN PRIVATE KEY"; - public static final List<String> BEGINNERS = - Collections.unmodifiableList(Collections.singletonList(BEGIN_MARKER)); - - public static final String END_MARKER = "END PRIVATE KEY"; - public static final List<String> ENDERS = - Collections.unmodifiableList(Collections.singletonList(END_MARKER)); - - public static final String PKCS8_FORMAT = "PKCS#8"; - - public static final PKCS8PEMResourceKeyPairParser INSTANCE = new PKCS8PEMResourceKeyPairParser(); - - public PKCS8PEMResourceKeyPairParser() { - super(PKCS8_FORMAT, PKCS8_FORMAT, BEGINNERS, ENDERS); - } - - @Override - public Collection<KeyPair> extractKeyPairs( - String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream) - throws IOException, GeneralSecurityException { - // Save the data before getting the algorithm OID since we will need it - byte[] encBytes = IoUtils.toByteArray(stream); - List<Integer> oidAlgorithm = getPKCS8AlgorithmIdentifier(encBytes); - PrivateKey prvKey = decodePEMPrivateKeyPKCS8(oidAlgorithm, encBytes, passwordProvider); - PublicKey pubKey = ValidateUtils.checkNotNull(KeyUtils.recoverPublicKey(prvKey), - "Failed to recover public key of OID=%s", oidAlgorithm); - KeyPair kp = new KeyPair(pubKey, prvKey); - return Collections.singletonList(kp); - } - - public static PrivateKey decodePEMPrivateKeyPKCS8( - List<Integer> oidAlgorithm, byte[] keyBytes, FilePasswordProvider passwordProvider) - throws GeneralSecurityException { - ValidateUtils.checkNotNullAndNotEmpty(oidAlgorithm, "No PKCS8 algorithm OID"); - return decodePEMPrivateKeyPKCS8(GenericUtils.join(oidAlgorithm, '.'), keyBytes, passwordProvider); - } - - public static PrivateKey decodePEMPrivateKeyPKCS8( - String oid, byte[] keyBytes, FilePasswordProvider passwordProvider) - throws GeneralSecurityException { - KeyPairPEMResourceParser parser = - PEMResourceParserUtils.getPEMResourceParserByOid( - ValidateUtils.checkNotNullAndNotEmpty(oid, "No PKCS8 algorithm OID")); - if (parser == null) { - throw new NoSuchAlgorithmException("decodePEMPrivateKeyPKCS8(" + oid + ") unknown algorithm identifier"); - } - - String algorithm = ValidateUtils.checkNotNullAndNotEmpty(parser.getAlgorithm(), "No parser algorithm"); - KeyFactory factory = SecurityUtils.getKeyFactory(algorithm); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); - return factory.generatePrivate(keySpec); - } - - public static List<Integer> getPKCS8AlgorithmIdentifier(byte[] input) throws IOException { - try (DERParser parser = new DERParser(input)) { - return getPKCS8AlgorithmIdentifier(parser); - } - } - - /** - * According to the standard: - * <PRE><CODE> - * PrivateKeyInfo ::= SEQUENCE { - * version Version, - * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - * privateKey PrivateKey, - * attributes [0] IMPLICIT Attributes OPTIONAL - * } - * - * Version ::= INTEGER - * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier - * PrivateKey ::= OCTET STRING - * Attributes ::= SET OF Attribute - * AlgorithmIdentifier ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL - * } - * </CODE></PRE> - * @param parser The {@link DERParser} to use - * @return The PKCS8 algorithm OID - * @throws IOException If malformed data - * @see #getPKCS8AlgorithmIdentifier(ASN1Object) - */ - public static List<Integer> getPKCS8AlgorithmIdentifier(DERParser parser) throws IOException { - return getPKCS8AlgorithmIdentifier(parser.readObject()); - } - - public static List<Integer> getPKCS8AlgorithmIdentifier(ASN1Object privateKeyInfo) throws IOException { - try (DERParser parser = privateKeyInfo.createParser()) { - // Skip version - ASN1Object versionObject = parser.readObject(); - if (versionObject == null) { - throw new StreamCorruptedException("No version"); - } - - ASN1Object privateKeyAlgorithm = parser.readObject(); - if (privateKeyAlgorithm == null) { - throw new StreamCorruptedException("No private key algorithm"); - } - - try (DERParser oidParser = privateKeyAlgorithm.createParser()) { - ASN1Object oid = oidParser.readObject(); - return oid.asOID(); - } - } - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/RSAPEMResourceKeyPairParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/RSAPEMResourceKeyPairParser.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/RSAPEMResourceKeyPairParser.java deleted file mode 100644 index d760aaf..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/loader/pem/RSAPEMResourceKeyPairParser.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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.loader.pem; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StreamCorruptedException; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.security.spec.RSAPrivateKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.config.keys.KeyUtils; -import org.apache.sshd.common.util.io.NoCloseInputStream; -import org.apache.sshd.common.util.io.der.ASN1Object; -import org.apache.sshd.common.util.io.der.ASN1Type; -import org.apache.sshd.common.util.io.der.DERParser; -import org.apache.sshd.common.util.security.SecurityUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class RSAPEMResourceKeyPairParser extends AbstractPEMResourceKeyPairParser { - // Not exactly according to standard but good enough - public static final String BEGIN_MARKER = "BEGIN RSA PRIVATE KEY"; - public static final List<String> BEGINNERS = - Collections.unmodifiableList(Collections.singletonList(BEGIN_MARKER)); - - public static final String END_MARKER = "END RSA PRIVATE KEY"; - public static final List<String> ENDERS = - Collections.unmodifiableList(Collections.singletonList(END_MARKER)); - - /** - * @see <A HREF="https://tools.ietf.org/html/rfc3279#section-2.3.1">RFC-3279 section 2.3.1</A> - */ - public static final String RSA_OID = "1.2.840.113549.1.1.1"; - - public static final RSAPEMResourceKeyPairParser INSTANCE = new RSAPEMResourceKeyPairParser(); - - public RSAPEMResourceKeyPairParser() { - super(KeyUtils.RSA_ALGORITHM, RSA_OID, BEGINNERS, ENDERS); - } - - @Override - public Collection<KeyPair> extractKeyPairs( - String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream) - throws IOException, GeneralSecurityException { - KeyPair kp = decodeRSAKeyPair(SecurityUtils.getKeyFactory(KeyUtils.RSA_ALGORITHM), stream, false); - return Collections.singletonList(kp); - } - - /** - * <p>The ASN.1 syntax for the private key as per RFC-3447 section A.1.2:</P> - * <pre><code> - * RSAPrivateKey ::= SEQUENCE { - * version Version, - * modulus INTEGER, -- n - * publicExponent INTEGER, -- e - * privateExponent INTEGER, -- d - * prime1 INTEGER, -- p - * prime2 INTEGER, -- q - * exponent1 INTEGER, -- d mod (p-1) - * exponent2 INTEGER, -- d mod (q-1) - * coefficient INTEGER, -- (inverse of q) mod p - * otherPrimeInfos OtherPrimeInfos OPTIONAL - * } - * </code></pre> - * @param kf The {@link KeyFactory} To use to generate the keys - * @param s The {@link InputStream} containing the encoded bytes - * @param okToClose <code>true</code> if the method may close the input - * stream regardless of success or failure - * @return The recovered {@link KeyPair} - * @throws IOException If failed to read or decode the bytes - * @throws GeneralSecurityException If failed to generate the keys - */ - public static KeyPair decodeRSAKeyPair(KeyFactory kf, InputStream s, boolean okToClose) - throws IOException, GeneralSecurityException { - ASN1Object sequence; - try (DERParser parser = new DERParser(NoCloseInputStream.resolveInputStream(s, okToClose))) { - sequence = parser.readObject(); - } - - if (!ASN1Type.SEQUENCE.equals(sequence.getObjType())) { - throw new IOException("Invalid DER: not a sequence: " + sequence.getObjType()); - } - - try (DERParser parser = sequence.createParser()) { - // Skip version - ASN1Object versionObject = parser.readObject(); - if (versionObject == null) { - throw new StreamCorruptedException("No version"); - } - - // as per RFC-3447 section A.1.2 - BigInteger version = versionObject.asInteger(); - if (!BigInteger.ZERO.equals(version)) { - throw new StreamCorruptedException("Multi-primes N/A"); - } - - BigInteger modulus = parser.readObject().asInteger(); - BigInteger publicExp = parser.readObject().asInteger(); - PublicKey pubKey = kf.generatePublic(new RSAPublicKeySpec(modulus, publicExp)); - - BigInteger privateExp = parser.readObject().asInteger(); - BigInteger primeP = parser.readObject().asInteger(); - BigInteger primeQ = parser.readObject().asInteger(); - BigInteger primeExponentP = parser.readObject().asInteger(); - BigInteger primeExponentQ = parser.readObject().asInteger(); - BigInteger crtCoef = parser.readObject().asInteger(); - RSAPrivateKeySpec prvSpec = new RSAPrivateCrtKeySpec( - modulus, publicExp, privateExp, primeP, primeQ, primeExponentP, primeExponentQ, crtCoef); - PrivateKey prvKey = kf.generatePrivate(prvSpec); - return new KeyPair(pubKey, prvKey); - } - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/digest/BaseDigest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/digest/BaseDigest.java b/sshd-core/src/main/java/org/apache/sshd/common/digest/BaseDigest.java deleted file mode 100644 index a5ef6f9..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/digest/BaseDigest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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.digest; - -import java.security.MessageDigest; -import java.util.Objects; - -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.NumberUtils; -import org.apache.sshd.common.util.ValidateUtils; -import org.apache.sshd.common.util.security.SecurityUtils; - -/** - * Base class for Digest algorithms based on the JCE provider. - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class BaseDigest implements Digest { - - private final String algorithm; - private final int bsize; - private int h; - private String s; - private MessageDigest md; - - /** - * Create a new digest using the given algorithm and block size. - * The initialization and creation of the underlying {@link MessageDigest} - * object will be done in the {@link #init()} method. - * - * @param algorithm the JCE algorithm to use for this digest - * @param bsize the block size of this digest - */ - public BaseDigest(String algorithm, int bsize) { - this.algorithm = ValidateUtils.checkNotNullAndNotEmpty(algorithm, "No algorithm"); - ValidateUtils.checkTrue(bsize > 0, "Invalid block size: %d", bsize); - this.bsize = bsize; - } - - @Override - public final String getAlgorithm() { - return algorithm; - } - - @Override - public int getBlockSize() { - return bsize; - } - - @Override - public void init() throws Exception { - this.md = SecurityUtils.getMessageDigest(getAlgorithm()); - } - - @Override - public void update(byte[] data) throws Exception { - update(data, 0, NumberUtils.length(data)); - } - - @Override - public void update(byte[] data, int start, int len) throws Exception { - Objects.requireNonNull(md, "Digest not initialized").update(data, start, len); - } - - /** - * @return The current {@link MessageDigest} - may be {@code null} if {@link #init()} not called - */ - protected MessageDigest getMessageDigest() { - return md; - } - - @Override - public byte[] digest() throws Exception { - return Objects.requireNonNull(md, "Digest not initialized").digest(); - } - - @Override - public int hashCode() { - synchronized (this) { - if (h == 0) { - h = Objects.hashCode(getAlgorithm()) + getBlockSize(); - if (h == 0) { - h = 1; - } - } - } - - return h; - } - - @Override - public int compareTo(Digest that) { - if (that == null) { - return -1; // push null(s) to end - } else if (this == that) { - return 0; - } - - String thisAlg = getAlgorithm(); - String thatAlg = that.getAlgorithm(); - int nRes = GenericUtils.safeCompare(thisAlg, thatAlg, false); - if (nRes != 0) { - return nRes; // debug breakpoint - } - - nRes = Integer.compare(this.getBlockSize(), that.getBlockSize()); - if (nRes != 0) { - return nRes; // debug breakpoint - } - - return 0; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (getClass() != obj.getClass()) { - return false; - } - - int nRes = compareTo((Digest) obj); - return nRes == 0; - } - - @Override - public String toString() { - synchronized (this) { - if (s == null) { - s = getClass().getSimpleName() + "[" + getAlgorithm() + ":" + getBlockSize() + "]"; - } - } - - return s; - } -}
