1 /* Copyright 2018 Google LLC 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * https://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 package com.google.security.cryptauth.lib.securegcm; 16 17 /** 18 * Describes a cryptographic handshake with arbitrary number of round trips. Some handshake 19 * messages may also send a payload. 20 * 21 * <p>Generic usage for handshake Initiator: 22 * {@code 23 * // Handshake Initiator 24 * D2DHandshakeContext handshake = <specific handshake>.forInitiator(); 25 * while (!handshake.isHandshakeComplete()) { 26 * try { 27 * // Get the next handshake message to send 28 * byte[] initiatorMessage = handshake.getNextHandshakeMessage(); 29 * 30 * // Send the message out and get the response 31 * socket.send(initiatorMessage); 32 * byte[] responderMessage = socket.read(); 33 * 34 * // Handle the response and obtain the optional payload 35 * byte[] payload = handshake.parseHandshakeMessage(responderMessage); 36 * 37 * // Handle the payload if one was sent 38 * if (payload.length > 0) { 39 * handlePayload(payload); 40 * } 41 * } catch (HandshakeException e) { 42 * // Handshake has failed, bail 43 * Log("Handshake failed!", e); 44 * return; 45 * } 46 * } 47 * 48 * ConnectionContext connectionContext; 49 * try { 50 * // Upgrade handshake context to a full connection context 51 * connectionContext = handshake.toConnectionContext(); 52 * } catch (HandshakeException e) { 53 * Log("Cannot convert handshake to connection context", e); 54 * } 55 * } 56 * 57 * <p>Generic usage for handshake Responder: 58 * {@code 59 * // Handshake Responder 60 * D2DHandshakeContext handshake = <specific handshake>.forResponder(); 61 * 62 * while (!handshake.isHandshakeComplete()) { 63 * try { 64 * // Get the message from the initiator 65 * byte[] initiatorMessage = socket.read(); 66 * 67 * // Handle the message and get the payload if it exists 68 * byte[] payload = handshake.parseHandshakeMessage(initiatorMessage); 69 * 70 * // Handle the payload if one was sent 71 * if (payload.length > 0) { 72 * handlePayload(payload); 73 * } 74 * 75 * // Make sure that wasn't the last message 76 * if (handshake.isHandshakeComplete()) { 77 * break; 78 * } 79 * 80 * // Get next message to send and send it 81 * byte[] responderMessage = handshake.getNextHandshakeMessage(); 82 * socket.send(responderMessage); 83 * } catch (HandshakeException e) { 84 * // Handshake has failed, bail 85 * Log("Handshake failed!", e); 86 * return; 87 * } 88 * } 89 * 90 * ConnectionContext connectionContext; 91 * try { 92 * // Upgrade handshake context to a full connection context 93 * connectionContext = handshake.toConnectionContext(); 94 * } catch (HandshakeException e) { 95 * Log("Cannot convert handshake to connection context", e); 96 * } 97 * } 98 */ 99 public interface D2DHandshakeContext { 100 101 /** 102 * Tells the caller whether the handshake has completed or not. If the handshake is complete, the 103 * caller may call {@link #toConnectionContext()} to obtain a connection context. 104 * 105 * @return true if the handshake is complete, false otherwise 106 */ 107 boolean isHandshakeComplete(); 108 109 /** 110 * Constructs the next message that should be sent in the handshake. 111 * 112 * @return the next message 113 * @throws HandshakeException if the handshake is over or if the next handshake message can't be 114 * obtained (e.g., there is an internal error) 115 */ 116 byte[] getNextHandshakeMessage() throws HandshakeException; 117 118 /** 119 * Tells the caller whether the next handshake message may carry a payload. If true, caller may 120 * call {@link #getNextHandshakeMessage(byte[])} instead of the regular 121 * {@link #getNextHandshakeMessage()}. If false, calling {@link #getNextHandshakeMessage(byte[])} 122 * will result in a {@link HandshakeException}. 123 * 124 * @return true if the next handshake message can carry a payload, false otherwise 125 */ 126 boolean canSendPayloadInHandshakeMessage(); 127 128 /** 129 * Constructs the next message that should be sent in the handshake along with a payload. Caller 130 * should verify that this method can be called by calling 131 * {@link #canSendPayloadInHandshakeMessage()}. 132 * 133 * @param payload the payload to include in the handshake message 134 * @return the next message 135 * @throws HandshakeException if the handshake is over or if the next handshake message can't be 136 * obtained (e.g., there is an internal error) or if the payload may not be included in this 137 * message 138 */ 139 byte[] getNextHandshakeMessage(byte[] payload) throws HandshakeException; 140 141 /** 142 * Parses a handshake message and returns the included payload (if any). 143 * 144 * @param handshakeMessage message received in the handshake 145 * @return payload or empty byte[] if no payload was in the handshake message 146 * @throws HandshakeException if an error occurs in parsing the handshake message 147 */ 148 byte[] parseHandshakeMessage(byte[] handshakeMessage) throws HandshakeException; 149 150 /** 151 * Creates a full {@link D2DConnectionContext}. May only be called if 152 * {@link #isHandshakeComplete()} returns true. 153 * 154 * @return a full {@link D2DConnectionContext} 155 * @throws HandshakeException if a connection context cannot be created 156 */ 157 D2DConnectionContext toConnectionContext() throws HandshakeException; 158 } 159