/* * 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 com.gitblit.transport.ssh; import java.io.FileInputStream; import java.io.InputStreamReader; import java.security.KeyPair; import java.util.Arrays; import java.util.Iterator; import java.util.NoSuchElementException; import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider; import org.apache.sshd.common.util.SecurityUtils; import org.bouncycastle.openssl.PEMDecryptorProvider; import org.bouncycastle.openssl.PEMEncryptedKeyPair; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.PasswordFinder; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; /** * This host key provider loads private keys from the specified files. * * Note that this class has a direct dependency on BouncyCastle and won't work * unless it has been correctly registered as a security provider. * * @author Apache MINA SSHD Project */ public class FileKeyPairProvider extends AbstractKeyPairProvider { private String[] files; private PasswordFinder passwordFinder; public FileKeyPairProvider() { } public FileKeyPairProvider(String[] files) { this.files = files; } public FileKeyPairProvider(String[] files, PasswordFinder passwordFinder) { this.files = files; this.passwordFinder = passwordFinder; } public String[] getFiles() { return files; } public void setFiles(String[] files) { this.files = files; } public PasswordFinder getPasswordFinder() { return passwordFinder; } public void setPasswordFinder(PasswordFinder passwordFinder) { this.passwordFinder = passwordFinder; } public Iterable loadKeys() { if (!SecurityUtils.isBouncyCastleRegistered()) { throw new IllegalStateException("BouncyCastle must be registered as a JCE provider"); } return new Iterable() { @Override public Iterator iterator() { return new Iterator() { private final Iterator iterator = Arrays.asList(files).iterator(); private KeyPair nextKeyPair; private boolean nextKeyPairSet = false; @Override public boolean hasNext() { return nextKeyPairSet || setNextObject(); } @Override public KeyPair next() { if (!nextKeyPairSet) { if (!setNextObject()) { throw new NoSuchElementException(); } } nextKeyPairSet = false; return nextKeyPair; } @Override public void remove() { throw new UnsupportedOperationException(); } private boolean setNextObject() { while (iterator.hasNext()) { String file = iterator.next(); nextKeyPair = doLoadKey(file); if (nextKeyPair != null) { nextKeyPairSet = true; return true; } } return false; } }; } }; } protected KeyPair doLoadKey(String file) { try { PEMParser r = new PEMParser(new InputStreamReader(new FileInputStream(file))); try { Object o = r.readObject(); JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter(); pemConverter.setProvider("BC"); if (passwordFinder != null && o instanceof PEMEncryptedKeyPair) { JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder(); PEMDecryptorProvider pemDecryptor = decryptorBuilder.build(passwordFinder.getPassword()); o = pemConverter.getKeyPair(((PEMEncryptedKeyPair) o).decryptKeyPair(pemDecryptor)); } if (o instanceof PEMKeyPair) { o = pemConverter.getKeyPair((PEMKeyPair)o); return (KeyPair) o; } else if (o instanceof KeyPair) { return (KeyPair) o; } } finally { r.close(); } } catch (Exception e) { log.warn("Unable to read key " + file, e); } return null; } }