Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions build.moxie
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ properties: {
bouncycastle.version : 1.81
selenium.version : 2.28.0
wikitext.version : 1.4
sshd.version: 1.7.0
mina.version: 2.0.27
sshd.version: 2.14.0
guice.version : 5.1.0
# Gitblit maintains a fork of guice-servlet
guice-servlet.version : 5.1.0-gb2
Expand Down Expand Up @@ -173,7 +172,6 @@ dependencies:
- compile 'org.bouncycastle:bcpkix-jdk18on:${bouncycastle.version}' :war
- compile 'net.i2p.crypto:eddsa:0.2.0' :war !org.easymock
- compile 'org.apache.sshd:sshd-core:${sshd.version}' :war !org.easymock
- compile 'org.apache.mina:mina-core:${mina.version}' :war !org.easymock
- compile 'rome:rome:0.9' :war :manager :api
- compile 'com.google.code.gson:gson:2.10' :war :fedclient :manager :api
- compile 'org.codehaus.groovy:groovy-all:${groovy.version}' :war
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,20 @@

import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Path;

import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.session.SessionContext;

public class DisabledFilesystemFactory implements FileSystemFactory {

/**
* Create user specific file system.
*
* @param session The session created for the user
* @return The current {@link FileSystem} for the provided session
* @throws java.io.IOException when the filesystem can not be created
*/
@Override
public FileSystem createFileSystem(Session session) throws IOException {
return null;
public Path getUserHomeDir(SessionContext session) throws IOException {
return null;
}

@Override
public FileSystem createFileSystem(SessionContext session) throws IOException {
return null;
}
}
144 changes: 54 additions & 90 deletions src/main/java/com/gitblit/transport/ssh/FileKeyPairProvider.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
/*
* 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
* Copyright 2014 gitblit.com.
*
* http://www.apache.org/licenses/LICENSE-2.0
* Licensed 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
*
* 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.
* 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;

Expand All @@ -29,8 +26,10 @@
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.apache.sshd.common.config.keys.FilePasswordProvider;
import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider;
import org.apache.sshd.common.session.SessionContext;
import org.apache.sshd.common.util.security.SecurityUtils;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
Expand All @@ -45,82 +44,62 @@
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

/**
* This host key provider loads private keys from the specified files.
* <p>
* 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 <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class FileKeyPairProvider extends AbstractKeyPairProvider
{
public class FileKeyPairProvider extends AbstractKeyPairProvider {

private String[] files;

public FileKeyPairProvider()
{
public FileKeyPairProvider() {
}

public FileKeyPairProvider(String[] files)
{
public FileKeyPairProvider(String[] files) {
this.files = files;
}

public String[] getFiles()
{
public String[] getFiles() {
return files;
}

public void setFiles(String[] files)
{
public void setFiles(String[] files) {
this.files = files;
}

public Iterable<KeyPair> loadKeys() {
return loadKeys(null);
}

@Override
public Iterable<KeyPair> loadKeys()
{
public Iterable<KeyPair> loadKeys(SessionContext session) {
if (!SecurityUtils.isBouncyCastleRegistered()) {
throw new IllegalStateException("BouncyCastle must be registered as a JCE provider");
}
return new Iterable<KeyPair>()
{
return new Iterable<KeyPair>() {
@Override
public Iterator<KeyPair> iterator()
{
return new Iterator<KeyPair>()
{
public Iterator<KeyPair> iterator() {
return new Iterator<KeyPair>() {
private final Iterator<String> iterator = Arrays.asList(files).iterator();
private KeyPair nextKeyPair;
private boolean nextKeyPairSet = false;
private boolean nextKeyPairSet;

@Override
public boolean hasNext()
{
public boolean hasNext() {
return nextKeyPairSet || setNextObject();
}

@Override
public KeyPair next()
{
if (!nextKeyPairSet) {
if (!setNextObject()) {
throw new NoSuchElementException();
}
public KeyPair next() {
if (!nextKeyPairSet && !setNextObject()) {
throw new NoSuchElementException();
}
nextKeyPairSet = false;
return nextKeyPair;
}

@Override
public void remove()
{
public void remove() {
throw new UnsupportedOperationException();
}

private boolean setNextObject()
{
private boolean setNextObject() {
while (iterator.hasNext()) {
String file = iterator.next();
File f = new File(file);
Expand All @@ -136,80 +115,65 @@ private boolean setNextObject()
}
return false;
}

};
}
};
}


private KeyPair doLoadKey(String file)
{
private KeyPair doLoadKey(String file) {
try {

try (PemReader r = new PemReader(new InputStreamReader(new FileInputStream(file)))) {
PemObject pemObject = r.readPemObject();
if ("OPENSSH PRIVATE KEY".equals(pemObject.getType())) {
// This reads a properly OpenSSH formatted ed25519 private key file.
// It is currently unused because the SSHD library in play doesn't work with proper keys.
// This is kept in the hope that in the future the library offers proper support.
if (pemObject != null && "OPENSSH PRIVATE KEY".equals(pemObject.getType())) {
try {
byte[] privateKeyContent = pemObject.getContent();
AsymmetricKeyParameter privateKeyParameters = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(privateKeyContent);
if (privateKeyParameters instanceof Ed25519PrivateKeyParameters) {
OpenSSHPrivateKeySpec privkeySpec = new OpenSSHPrivateKeySpec(privateKeyContent);

Ed25519PublicKeyParameters publicKeyParameters = ((Ed25519PrivateKeyParameters)privateKeyParameters).generatePublicKey();
OpenSSHPublicKeySpec pubKeySpec = new OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(publicKeyParameters));

Ed25519PublicKeyParameters publicKeyParameters =
((Ed25519PrivateKeyParameters) privateKeyParameters).generatePublicKey();
OpenSSHPublicKeySpec pubKeySpec =
new OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(publicKeyParameters));
KeyFactory kf = KeyFactory.getInstance("Ed25519", "BC");
PrivateKey privateKey = kf.generatePrivate(privkeySpec);
PublicKey publicKey = kf.generatePublic(pubKeySpec);
return new KeyPair(publicKey, privateKey);
}
else {
log.warn("OpenSSH format is only supported for Ed25519 key type. Unable to read key " + file);
}
}
catch (Exception e) {
log.warn("Unable to read key " + file, e);
log.warn("OpenSSH format is only supported for Ed25519 key type. Unable to read key {}", file);
} catch (Exception e) {
log.warn("Unable to read key {}", file, e);
}
return null;
}

if ("EDDSA PRIVATE KEY".equals(pemObject.getType())) {
// This reads the ed25519 key from a file format that we created in SshDaemon.
// The type EDDSA PRIVATE KEY was given by us and nothing official.
if (pemObject != null && "EDDSA PRIVATE KEY".equals(pemObject.getType())) {
byte[] privateKeyContent = pemObject.getContent();
PrivateKeyEntryDecoder<? extends PublicKey,? extends PrivateKey> decoder = SecurityUtils.getOpenSSHEDDSAPrivateKeyEntryDecoder();
PrivateKey privateKey = decoder.decodePrivateKey(null, privateKeyContent, 0, privateKeyContent.length);
PublicKey publicKey = SecurityUtils. recoverEDDSAPublicKey(privateKey);
PrivateKeyEntryDecoder<? extends PublicKey, ? extends PrivateKey> decoder =
SecurityUtils.getOpenSSHEDDSAPrivateKeyEntryDecoder();
PrivateKey privateKey = decoder.decodePrivateKey(
null, FilePasswordProvider.EMPTY, privateKeyContent, 0, privateKeyContent.length);
PublicKey publicKey = SecurityUtils.recoverEDDSAPublicKey(privateKey);
return new KeyPair(publicKey, privateKey);
}
}

try (PEMParser r = new PEMParser(new InputStreamReader(new FileInputStream(file)))) {
Object o = r.readObject();

JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
pemConverter.setProvider("BC");
if (o instanceof PEMKeyPair) {
o = pemConverter.getKeyPair((PEMKeyPair)o);
return (KeyPair)o;
return pemConverter.getKeyPair((PEMKeyPair) o);
}
else if (o instanceof KeyPair) {
return (KeyPair)o;
if (o instanceof KeyPair) {
return (KeyPair) o;
}
else {
log.warn("Cannot read unsupported PEM object of type: " + o.getClass().getCanonicalName());
if (o != null) {
log.warn("Cannot read unsupported PEM object of type: {}", o.getClass().getCanonicalName());
}
}

}
catch (Exception e) {
log.warn("Unable to read key " + file, e);
} catch (Exception e) {
log.warn("Unable to read key {}", file, e);
}
return null;
}

}
Loading