Spec rev30: Add NXfallback and IXfallback patterns

This commit is contained in:
Rhys Weatherley 2016-07-03 13:24:25 +10:00
parent ac6ec2b537
commit f1a2a468c3
2 changed files with 108 additions and 20 deletions

View File

@ -124,6 +124,11 @@ public class HandshakeState implements Destroyable {
*/
private static final int REMOTE_PREMSG = 0x20;
/**
* Fallback is possible from this pattern (two-way, ends in "K").
*/
private static final int FALLBACK_POSSIBLE = 0x40;
/**
* Creates a new Noise handshake.
*
@ -153,6 +158,9 @@ public class HandshakeState implements Destroyable {
if (pattern == null)
throw new IllegalArgumentException("Handshake pattern is not recognized");
byte flags = pattern[0];
int extraReqs = 0;
if ((flags & Pattern.FLAG_REMOTE_REQUIRED) != 0 && patternId.length() > 1)
extraReqs |= FALLBACK_POSSIBLE;
if (role == RESPONDER) {
// Reverse the pattern flags so that the responder is "local".
flags = Pattern.reverseFlags(flags);
@ -166,7 +174,7 @@ public class HandshakeState implements Destroyable {
symmetric = new SymmetricState(protocolName, cipher, hash);
isInitiator = (role == INITIATOR);
action = NO_ACTION;
requirements = computeRequirements(flags, prefix, role, false);
requirements = extraReqs | computeRequirements(flags, prefix, role, false);
patternIndex = 1;
// Create the DH objects that we will need later.
@ -410,8 +418,8 @@ public class HandshakeState implements Destroyable {
* more of the required parameters has not been supplied.
*
* @throws UnsupportedOperationException An attempt was made to start a
* "XXfallback" handshake pattern without first calling fallback() on a
* previous "IK" handshake.
* fallback handshake pattern without first calling fallback() on a
* previous handshake.
*
* @see #getAction()
* @see #writeMessage(byte[], int, byte[], int, int)
@ -424,10 +432,10 @@ public class HandshakeState implements Destroyable {
throw new IllegalStateException
("Handshake has already started; cannot start again");
}
if (pattern == Pattern.noise_pattern_XXfallback &&
if ((pattern[0] & Pattern.FLAG_REMOTE_EPHEM_REQ) != 0 &&
(requirements & FALLBACK_PREMSG) == 0) {
throw new UnsupportedOperationException
("Cannot start XXfallback pattern");
("Cannot start a fallback pattern");
}
// Check that we have satisfied all of the pattern requirements.
@ -487,11 +495,11 @@ public class HandshakeState implements Destroyable {
/**
* Falls back to the "XXfallback" handshake pattern.
*
* This function is used to help implement the "Noise Pipes" protocol.
* It resets a HandshakeState object with the handshake pattern "IK",
* converting it into an object with the handshake pattern "XXfallback".
* Information from the previous session such as the local keypair,
* the initiator's ephemeral key, the prologue value, and the
* This function is intended used to help implement the "Noise Pipes" protocol.
* It resets a HandshakeState object with the original handshake pattern
* (usually "IK"), converting it into an object with the handshake pattern
* "XXfallback". Information from the previous session such as the local
* keypair, the initiator's ephemeral key, the prologue value, and the
* pre-shared key, are passed to the new session.
*
* Once the fallback has been initiated, the application can set
@ -501,13 +509,12 @@ public class HandshakeState implements Destroyable {
* session.
*
* After setting any new parameters, the application calls start()
* again to restart the handshake from where it left off before
* the fallback.
* again to restart the handshake from where it left off before the fallback.
*
* Note that this function reverses the roles of initiator and responder.
*
* @throws UnsupportedOperationException The handshake pattern is
* not currently set to "IK".
* @throws UnsupportedOperationException The current handshake pattern
* is not compatible with "XXfallback".
*
* @throws IllegalStateException The previous protocol has not started
* or it has not reached the fallback position yet.
@ -519,9 +526,59 @@ public class HandshakeState implements Destroyable {
*/
public void fallback() throws NoSuchAlgorithmException
{
// Bail out if the previous pattern is not "IK".
if (pattern != Pattern.noise_pattern_IK)
throw new UnsupportedOperationException("Previous handshake pattern is not IK");
fallback("XXfallback");
}
/**
* Falls back to another handshake pattern.
*
* @param patternName The name of the pattern to fall back to;
* e.g. "XXfallback", "NXfallback", etc.
*
* This function resets a HandshakeState object with the original
* handshake pattern, and converts it into an object with the new handshake
* patternName. Information from the previous session such as the local
* keypair, the initiator's ephemeral key, the prologue value, and the
* pre-shared key, are passed to the new session.
*
* Once the fallback has been initiated, the application can set
* new values for the handshake parameters if the values from the
* previous session do not apply. For example, the application may
* use a different prologue for the fallback than for the original
* session.
*
* After setting any new parameters, the application calls start()
* again to restart the handshake from where it left off before the fallback.
*
* The new pattern may have greater key requirements than the original;
* for example changing from "NK" from "XXfallback" requires that the
* initiator's static public key be set. The application is responsible for
* setting any extra keys before calling start().
*
* Note that this function reverses the roles of initiator and responder.
*
* @throws UnsupportedOperationException The current handshake pattern
* is not compatible with the patternName, or patternName is not a
* fallback pattern.
*
* @throws IllegalStateException The previous protocol has not started
* or it has not reached the fallback position yet.
*
* @throws NoSuchAlgorithmException One of the cryptographic algorithms
* that is specified in the new protocolName is not supported.
*
* @see #start()
*/
public void fallback(String patternName) throws NoSuchAlgorithmException
{
// The original pattern must end in "K" for fallback to be possible.
if ((requirements & FALLBACK_POSSIBLE) == 0)
throw new UnsupportedOperationException("Previous handshake pattern does not support fallback");
// Check that "patternName" supports fallback.
byte[] newPattern = Pattern.lookup(patternName);
if (newPattern == null || (newPattern[0] & Pattern.FLAG_REMOTE_EPHEM_REQ) == 0)
throw new UnsupportedOperationException("New pattern is not a fallback pattern");
// The initiator should be waiting for a return message from the
// responder, and the responder should have failed on the first
@ -554,7 +611,7 @@ public class HandshakeState implements Destroyable {
isInitiator = true;
}
action = NO_ACTION;
pattern = Pattern.noise_pattern_XXfallback;
pattern = newPattern;
patternIndex = 1;
byte flags = pattern[0];
if (!isInitiator) {

View File

@ -224,7 +224,7 @@ class Pattern {
DHES
};
static final byte[] noise_pattern_IK = {
private static final byte[] noise_pattern_IK = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -257,7 +257,7 @@ class Pattern {
DHSE
};
static final byte[] noise_pattern_XXfallback = {
private static final byte[] noise_pattern_XXfallback = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
@ -273,6 +273,33 @@ class Pattern {
DHSE
};
private static final byte[] noise_pattern_NXfallback = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_EPHEMERAL |
FLAG_REMOTE_EPHEM_REQ,
E,
DHEE,
S,
DHSE
};
private static final byte[] noise_pattern_IXfallback = {
FLAG_LOCAL_STATIC |
FLAG_LOCAL_EPHEMERAL |
FLAG_REMOTE_STATIC |
FLAG_REMOTE_EPHEMERAL |
FLAG_REMOTE_REQUIRED |
FLAG_REMOTE_EPHEM_REQ,
E,
DHEE,
DHES,
S,
DHSE
};
/**
* Look up the description information for a pattern.
*
@ -313,6 +340,10 @@ class Pattern {
return noise_pattern_IX;
else if (name.equals("XXfallback"))
return noise_pattern_XXfallback;
else if (name.equals("NXfallback"))
return noise_pattern_NXfallback;
else if (name.equals("IXfallback"))
return noise_pattern_IXfallback;
return null;
}