Subversion Repositories Programming Utils

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
86 rm5248 1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
package org.apache.sshd.client.kex;
20
 
21
import java.security.PublicKey;
22
 
23
import org.apache.sshd.client.session.ClientSessionImpl;
24
import org.apache.sshd.common.Digest;
25
import org.apache.sshd.common.KeyExchange;
26
import org.apache.sshd.common.NamedFactory;
27
import org.apache.sshd.common.Signature;
28
import org.apache.sshd.common.SshConstants;
29
import org.apache.sshd.common.SshException;
30
import org.apache.sshd.common.kex.AbstractDH;
31
import org.apache.sshd.common.kex.DH;
32
import org.apache.sshd.common.session.AbstractSession;
33
import org.apache.sshd.common.util.Buffer;
34
import org.apache.sshd.common.util.KeyUtils;
35
import org.slf4j.Logger;
36
import org.slf4j.LoggerFactory;
37
 
38
/**
39
 * Base class for DHG key exchange algorithms.
40
 * Implementations will only have to configure the required data on the
41
 * {@link DH} class in the {@link #getDH()} method.
42
 *
43
 * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
44
 */
45
public abstract class AbstractDHGClient implements KeyExchange {
46
 
47
    private final Logger log = LoggerFactory.getLogger(getClass());
48
 
49
    private ClientSessionImpl session;
50
    private byte[] V_S;
51
    private byte[] V_C;
52
    private byte[] I_S;
53
    private byte[] I_C;
54
    private Digest hash;
55
    private AbstractDH dh;
56
    private byte[] e;
57
    private byte[] f;
58
    private byte[] K;
59
    private byte[] H;
60
    private PublicKey serverKey;
61
 
62
    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
63
        if (!(s instanceof ClientSessionImpl)) {
64
            throw new IllegalStateException("Using a client side KeyExchange on a server");
65
        }
66
        session = (ClientSessionImpl) s;
67
        this.V_S = V_S;
68
        this.V_C = V_C;
69
        this.I_S = I_S;
70
        this.I_C = I_C;
71
        dh = getDH();
72
        hash =  dh.getHash();
73
        hash.init();
74
        e = dh.getE();
75
 
76
        log.debug("Send SSH_MSG_KEXDH_INIT");
77
        Buffer buffer = s.createBuffer(SshConstants.SSH_MSG_KEXDH_INIT);
78
        buffer.putMPInt(e);
79
        session.writePacket(buffer);
80
    }
81
 
82
    protected abstract AbstractDH getDH() throws Exception;
83
 
84
    public boolean next(Buffer buffer) throws Exception {
85
        byte cmd = buffer.getByte();
86
        if (cmd != SshConstants.SSH_MSG_KEXDH_REPLY) {
87
            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
88
                                   "Protocol error: expected packet SSH_MSG_KEXDH_REPLY, got " + cmd);
89
        }
90
 
91
        log.debug("Received SSH_MSG_KEXDH_REPLY");
92
 
93
        byte[] K_S = buffer.getBytes();
94
        f = buffer.getMPIntAsBytes();
95
        byte[] sig = buffer.getBytes();
96
        dh.setF(f);
97
        K = dh.getK();
98
 
99
        buffer = new Buffer(K_S);
100
        serverKey = buffer.getRawPublicKey();
101
        final String keyAlg = KeyUtils.getKeyType(serverKey);
102
        if (keyAlg == null) {
103
            throw new SshException("Unsupported server key type");
104
        }
105
 
106
        buffer = new Buffer();
107
        buffer.putString(V_C);
108
        buffer.putString(V_S);
109
        buffer.putString(I_C);
110
        buffer.putString(I_S);
111
        buffer.putString(K_S);
112
        buffer.putMPInt(e);
113
        buffer.putMPInt(f);
114
        buffer.putMPInt(K);
115
        hash.update(buffer.array(), 0, buffer.available());
116
        H = hash.digest();
117
 
118
        Signature verif = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), keyAlg);
119
        verif.init(serverKey, null);
120
        verif.update(H, 0, H.length);
121
        if (!verif.verify(sig)) {
122
            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
123
                                   "KeyExchange signature verification failed");
124
        }
125
        return true;
126
    }
127
 
128
    public Digest getHash() {
129
        return hash;
130
    }
131
 
132
    public byte[] getH() {
133
        return H;
134
    }
135
 
136
    public byte[] getK() {
137
        return K;
138
    }
139
 
140
    public PublicKey getServerKey() {
141
        return serverKey;
142
    }
143
 
144
}