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 //}