1 /*
2  * hunt-proton: AMQP Protocol library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.proton.engine.impl.ssl.SimpleSslTransportWrapper;
13 
14 
15 //import static hunt.proton.engine.impl.ByteBufferUtils.newWriteableBuffer;
16 //
17 //import hunt.io.ByteBuffer;
18 //import java.util.logging.Level;
19 //import java.util.logging.Logger;
20 //
21 //import javax.net.ssl.SSLEngineResult;
22 //import javax.net.ssl.SSLEngineResult.HandshakeStatus;
23 //import javax.net.ssl.SSLEngineResult.Status;
24 //import javax.net.ssl.SSLException;
25 //
26 //import hunt.proton.engine.Transport;
27 //import hunt.proton.engine.TransportException;
28 //import hunt.proton.engine.impl.TransportInput;
29 //import hunt.proton.engine.impl.TransportOutput;
30 //
31 ///**
32 // * TODO close the SSLEngine when told to, and modify {@link #wrapOutput()} and {@link #unwrapInput()}
33 // * to respond appropriately thereafter.
34 // */
35 //class SimpleSslTransportWrapper implements SslTransportWrapper
36 //{
37 //    private static Logger _logger = Logger.getLogger(SimpleSslTransportWrapper.class.getName());
38 //
39 //    private ProtonSslEngine _sslEngine;
40 //
41 //    private TransportInput _underlyingInput;
42 //    private TransportOutput _underlyingOutput;
43 //
44 //    private boolean _tail_closed = false;
45 //    private ByteBuffer _inputBuffer;
46 //
47 //    private boolean _head_closed = false;
48 //    private ByteBuffer _outputBuffer;
49 //    private ByteBuffer _head;
50 //
51 //    /**
52 //     * A buffer for the decoded bytes that will be passed to _underlyingInput.
53 //     * This extra layer of buffering is necessary in case the underlying input's buffer
54 //     * is too small for SSLEngine to ever unwrap into.
55 //     */
56 //    private ByteBuffer _decodedInputBuffer;
57 //
58 //    /** could change during the lifetime of the ssl connection owing to renegotiation. */
59 //    private String _cipherName;
60 //
61 //    /** could change during the lifetime of the ssl connection owing to renegotiation. */
62 //    private String _protocolName;
63 //
64 //
65 //    SimpleSslTransportWrapper(ProtonSslEngine sslEngine, TransportInput underlyingInput, TransportOutput underlyingOutput)
66 //    {
67 //        _underlyingInput = underlyingInput;
68 //        _underlyingOutput = underlyingOutput;
69 //        _sslEngine = sslEngine;
70 //
71 //        int effectiveAppBufferMax = _sslEngine.getEffectiveApplicationBufferSize();
72 //        int packetSize = _sslEngine.getPacketBufferSize();
73 //
74 //        // Input and output buffers need to be large enough to contain one SSL packet,
75 //        // as stated in SSLEngine JavaDoc.
76 //        _inputBuffer = newWriteableBuffer(packetSize);
77 //        _outputBuffer = newWriteableBuffer(packetSize);
78 //        _head = _outputBuffer.asReadOnlyBuffer();
79 //        _head.limit(0);
80 //
81 //        _decodedInputBuffer = newWriteableBuffer(effectiveAppBufferMax);
82 //
83 //        if(_logger.isLoggable(Level.FINE))
84 //        {
85 //            _logger.fine("Constructed " + this);
86 //        }
87 //    }
88 //
89 //
90 //    /**
91 //     * Unwraps the contents of {@link #_inputBuffer} and passes it to {@link #_underlyingInput}.
92 //     *
93 //     * Regarding the state of {@link #_inputBuffer}:
94 //     * - On entry, it is assumed to be readable.
95 //     * - On exit, it is still readable and its "remaining" bytes are those that we were unable
96 //     * to unwrap (e.g. if they don't form a whole packet).
97 //     */
98 //    private void unwrapInput() throws SSLException
99 //    {
100 //        int prevInRemaining = -1;
101 //        while (true) {
102 //            SSLEngineResult result = _sslEngine.unwrap(_inputBuffer, _decodedInputBuffer);
103 //            logEngineClientModeAndResult(result, "input");
104 //
105 //            int read = result.bytesProduced();
106 //            Status status = result.getStatus();
107 //            HandshakeStatus hstatus = result.getHandshakeStatus();
108 //
109 //            int capacity = _underlyingInput.capacity();
110 //            if (capacity == Transport.END_OF_STREAM || capacity <= 0) {
111 //                _tail_closed = true;
112 //                if (_decodedInputBuffer.position() > 0) {
113 //                    throw new TransportException("bytes left unconsumed");
114 //                }
115 //            } else {
116 //                _decodedInputBuffer.flip();
117 //
118 //                while (_decodedInputBuffer.hasRemaining() && capacity > 0) {
119 //                    ByteBuffer tail = _underlyingInput.tail();
120 //                    int limit = _decodedInputBuffer.limit();
121 //                    int overflow = _decodedInputBuffer.remaining() - capacity;
122 //                    if (overflow > 0) {
123 //                        _decodedInputBuffer.limit(limit - overflow);
124 //                    }
125 //                    tail.put(_decodedInputBuffer);
126 //                    _decodedInputBuffer.limit(limit);
127 //                    _underlyingInput.process();
128 //                    capacity = _underlyingInput.capacity();
129 //                }
130 //
131 //                if (capacity == Transport.END_OF_STREAM || capacity <= 0) {
132 //                    _tail_closed = true;
133 //                    if (_decodedInputBuffer.hasRemaining()) {
134 //                        throw new TransportException("bytes left unconsumed");
135 //                    }
136 //                }
137 //
138 //                _decodedInputBuffer.compact();
139 //            }
140 //
141 //            switch (status) {
142 //            case CLOSED:
143 //                _tail_closed = true;
144 //                break;
145 //            case BUFFER_OVERFLOW:
146 //                {
147 //                    ByteBuffer old = _decodedInputBuffer;
148 //                    _decodedInputBuffer = newWriteableBuffer(old.capacity()*2);
149 //                    old.flip();
150 //                    _decodedInputBuffer.put(old);
151 //                }
152 //                continue;
153 //            case BUFFER_UNDERFLOW:
154 //                if (_tail_closed) {
155 //                    _head_closed = true;
156 //                }
157 //                // wait for more data
158 //                break;
159 //            case OK:
160 //                break;
161 //            }
162 //
163 //            switch (hstatus)
164 //            {
165 //            case NEED_WRAP:
166 //                int inputRemaining = _inputBuffer.remaining();
167 //                if (inputRemaining > 0 && status == Status.OK && (inputRemaining < prevInRemaining || prevInRemaining < 0)) {
168 //                    // Track remaining input so we break if no progress is made.
169 //                    prevInRemaining = inputRemaining;
170 //                    // Process a wrap, try to progress on the remaining input.
171 //                    pending();
172 //                    continue;
173 //                }
174 //                // wait for write to kick in
175 //                break;
176 //            case NEED_TASK:
177 //                runDelegatedTasks(result);
178 //                continue;
179 //            case FINISHED:
180 //                updateCipherAndProtocolName(result);
181 //            case NOT_HANDSHAKING:
182 //            case NEED_UNWRAP:
183 //                if (_inputBuffer.position() > 0 && status == Status.OK) {
184 //                    continue;
185 //                } else {
186 //                    if (_inputBuffer.position() == 0 &&
187 //                        hstatus == HandshakeStatus.NEED_UNWRAP &&
188 //                        _tail_closed) {
189 //                        _head_closed = true;
190 //                    }
191 //                    break;
192 //                }
193 //            }
194 //
195 //            break;
196 //        }
197 //    }
198 //
199 //    /**
200 //     * Wrap the underlying transport's output, passing it to the output buffer.
201 //     *
202 //     * {@link #_outputBuffer} is assumed to be writeable on entry and is guaranteed to
203 //     * be still writeable on exit.
204 //     */
205 //    private void wrapOutput() throws SSLException
206 //    {
207 //        while (true) {
208 //            int pending = _underlyingOutput.pending();
209 //            if (pending < 0) {
210 //                _head_closed = true;
211 //            }
212 //
213 //            ByteBuffer clearOutputBuffer = _underlyingOutput.head();
214 //            SSLEngineResult result = _sslEngine.wrap(clearOutputBuffer, _outputBuffer);
215 //            logEngineClientModeAndResult(result, "output");
216 //
217 //            int written = result.bytesConsumed();
218 //            _underlyingOutput.pop(written);
219 //            pending = _underlyingOutput.pending();
220 //
221 //            Status status = result.getStatus();
222 //            switch (status) {
223 //            case CLOSED:
224 //                _head_closed = true;
225 //                break;
226 //            case OK:
227 //                break;
228 //            case BUFFER_OVERFLOW:
229 //                ByteBuffer old = _outputBuffer;
230 //                _outputBuffer = newWriteableBuffer(_outputBuffer.capacity()*2);
231 //                _head = _outputBuffer.asReadOnlyBuffer();
232 //                old.flip();
233 //                _outputBuffer.put(old);
234 //                continue;
235 //            case BUFFER_UNDERFLOW:
236 //                throw new IllegalStateException("app buffer underflow");
237 //            }
238 //
239 //            HandshakeStatus hstatus = result.getHandshakeStatus();
240 //            switch (hstatus) {
241 //            case NEED_UNWRAP:
242 //                // wait for input data
243 //                if (_inputBuffer.position() == 0 && _tail_closed) {
244 //                    _head_closed = true;
245 //                }
246 //                break;
247 //            case NEED_WRAP:
248 //                // keep looping
249 //                continue;
250 //            case NEED_TASK:
251 //                runDelegatedTasks(result);
252 //                continue;
253 //            case FINISHED:
254 //                updateCipherAndProtocolName(result);
255 //                // intentionally fall through
256 //            case NOT_HANDSHAKING:
257 //                if (pending > 0 && status == Status.OK) {
258 //                    continue;
259 //                } else {
260 //                    break;
261 //                }
262 //            }
263 //
264 //            break;
265 //        }
266 //    }
267 //
268 //    private boolean hasSpaceForSslPacket(ByteBuffer byteBuffer)
269 //    {
270 //        return byteBuffer.remaining() >= _sslEngine.getPacketBufferSize();
271 //    }
272 //
273 //    /** @return the cipher name, which is null until the SSL handshaking is completed */
274 //    @Override
275 //    public String getCipherName()
276 //    {
277 //        return _cipherName;
278 //    }
279 //
280 //    /** @return the protocol name, which is null until the SSL handshaking is completed */
281 //    @Override
282 //    public String getProtocolName()
283 //    {
284 //        return _protocolName;
285 //    }
286 //
287 //    private void updateCipherAndProtocolName(SSLEngineResult result)
288 //    {
289 //        if (result.getHandshakeStatus() == HandshakeStatus.FINISHED)
290 //        {
291 //            _cipherName = _sslEngine.getCipherSuite();
292 //            _protocolName = _sslEngine.getProtocol();
293 //        }
294 //    }
295 //
296 //    private void runDelegatedTasks(SSLEngineResult result)
297 //    {
298 //        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
299 //        {
300 //            Runnable runnable;
301 //            while ((runnable = _sslEngine.getDelegatedTask()) !is null)
302 //            {
303 //                runnable.run();
304 //            }
305 //
306 //            HandshakeStatus hsStatus = _sslEngine.getHandshakeStatus();
307 //            if (hsStatus == HandshakeStatus.NEED_TASK)
308 //            {
309 //                throw new RuntimeException("handshake shouldn't need additional tasks");
310 //            }
311 //        }
312 //    }
313 //
314 //    private void logEngineClientModeAndResult(SSLEngineResult result, String direction)
315 //    {
316 //        if(_logger.isLoggable(Level.FINEST))
317 //        {
318 //            _logger.log(Level.FINEST, "useClientMode = " + _sslEngine.getUseClientMode() + " direction = " + direction
319 //                        + " " + resultToString(result));
320 //        }
321 //    }
322 //
323 //    private String resultToString(SSLEngineResult result)
324 //    {
325 //        return new StringBuilder("[SSLEngineResult status = ").append(result.getStatus())
326 //                .append(" handshakeStatus = ").append(result.getHandshakeStatus())
327 //                .append(" bytesConsumed = ").append(result.bytesConsumed())
328 //                .append(" bytesProduced = ").append(result.bytesProduced())
329 //                .append("]").toString();
330 //    }
331 //
332 //    @Override
333 //    public int capacity()
334 //    {
335 //        if (_tail_closed) return Transport.END_OF_STREAM;
336 //        return _inputBuffer.remaining();
337 //    }
338 //
339 //    @Override
340 //    public int position()
341 //    {
342 //        if (_tail_closed) return Transport.END_OF_STREAM;
343 //        return _inputBuffer.position();
344 //    }
345 //
346 //    @Override
347 //    public ByteBuffer tail()
348 //    {
349 //        if (_tail_closed) throw new TransportException("tail closed");
350 //        return _inputBuffer;
351 //    }
352 //
353 //    @Override
354 //    public void process() throws TransportException
355 //    {
356 //        if (_tail_closed) throw new TransportException("tail closed");
357 //
358 //        _inputBuffer.flip();
359 //
360 //        try {
361 //            unwrapInput();
362 //        } catch (SSLException e) {
363 //            if(_logger.isLoggable(Level.FINEST)){
364 //                _logger.log(Level.FINEST, e.getMessage(), e);
365 //            } else {
366 //                _logger.log(Level.WARNING, e.getMessage());
367 //            }
368 //            _inputBuffer.position(_inputBuffer.limit());
369 //            _tail_closed = true;
370 //
371 //            throw new TransportException(e);
372 //        } finally {
373 //            _inputBuffer.compact();
374 //        }
375 //    }
376 //
377 //    @Override
378 //    public void close_tail()
379 //    {
380 //        try {
381 //            _underlyingInput.close_tail();
382 //        } finally {
383 //            _tail_closed = true;
384 //        }
385 //    }
386 //
387 //    @Override
388 //    public int pending()
389 //    {
390 //        try {
391 //            wrapOutput();
392 //        } catch (SSLException e) {
393 //            _logger.log(Level.WARNING, e.getMessage());
394 //            _head_closed = true;
395 //        }
396 //
397 //        _head.limit(_outputBuffer.position());
398 //
399 //        if (_head_closed && _outputBuffer.position() == 0) {
400 //            return Transport.END_OF_STREAM;
401 //        }
402 //
403 //        return _outputBuffer.position();
404 //    }
405 //
406 //    @Override
407 //    public ByteBuffer head()
408 //    {
409 //        pending();
410 //        return _head;
411 //    }
412 //
413 //    @Override
414 //    public void pop(int bytes)
415 //    {
416 //        _outputBuffer.flip();
417 //        _outputBuffer.position(bytes);
418 //        _outputBuffer.compact();
419 //        _head.position(0);
420 //        _head.limit(_outputBuffer.position());
421 //    }
422 //
423 //    @Override
424 //    public void close_head()
425 //    {
426 //        _underlyingOutput.close_head();
427 //        int p = pending();
428 //        if (p > 0) {
429 //            pop(p);
430 //        }
431 //    }
432 //
433 //
434 //    @Override
435 //    public String toString()
436 //    {
437 //        StringBuilder builder = new StringBuilder();
438 //        builder.append("SimpleSslTransportWrapper [sslEngine=").append(_sslEngine)
439 //            .append(", inputBuffer=").append(_inputBuffer)
440 //            .append(", outputBuffer=").append(_outputBuffer)
441 //            .append(", decodedInputBuffer=").append(_decodedInputBuffer)
442 //            .append(", cipherName=").append(_cipherName)
443 //            .append(", protocolName=").append(_protocolName)
444 //            .append("]");
445 //        return builder.toString();
446 //    }
447 //}