Skip to content

Commit

Permalink
Merge pull request #261 from Netflix/sender-recipient
Browse files Browse the repository at this point in the history
Remove sender & recipient fields; verify remote entity identity if specified.
  • Loading branch information
wmiaw authored Apr 4, 2018
2 parents 3a8732c + ea9e2da commit cb40f2e
Show file tree
Hide file tree
Showing 64 changed files with 1,448 additions and 2,512 deletions.
1 change: 1 addition & 0 deletions core/src/main/java/com/netflix/msl/MslError.java
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ public class MslError {
public static final MslError MESSAGE_REPLAYED_UNRECOVERABLE = new MslError(6040, ResponseCode.ENTITY_REAUTH, "Non-replayable message replayed with a sequence number that is too far out of sync to recover.");
public static final MslError UNEXPECTED_LOCAL_MESSAGE_SENDER = new MslError(6041, ResponseCode.FAIL, "Message sender is equal to the local entity.");
public static final MslError UNENCRYPTED_MESSAGE_WITH_USERAUTHDATA = new MslError(6042, ResponseCode.FAIL, "User authentication data included in unencrypted message header.");
public static final MslError MESSAGE_SENDER_MISMATCH = new MslError(6043, ResponseCode.FAIL, "Message sender entity identity does not match expected identity.");

// 7 Key Exchange
public static final MslError UNIDENTIFIED_KEYX_SCHEME = new MslError(7000, ResponseCode.FAIL, "Unable to identify key exchange scheme.");
Expand Down
25 changes: 1 addition & 24 deletions core/src/main/java/com/netflix/msl/msg/ErrorHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
* {@code
* errordata = {
* "#mandatory" : [ "messageid", "errorcode" ],
* "recipient" : "string",
* "timestamp" : "int64(0,2^53^)",
* "messageid" : "int64(0,2^53^)",
* "errorcode" : "int32(0,-)",
Expand All @@ -52,7 +51,6 @@
* "usermsg" : "string",
* }} where:
* <ul>
* <li>{@code recipient} is the intended recipient's entity identity</li>
* <li>{@code timestamp} is the sender time when the header is created in seconds since the UNIX epoch</li>
* <li>{@code messageid} is the message ID</li>
* <li>{@code errorcode} is the error code</li>
Expand All @@ -68,8 +66,6 @@ public class ErrorHeader extends Header {
private static final long MILLISECONDS_PER_SECOND = 1000;

// Message error data.
/** Key recipient. */
private static final String KEY_RECIPIENT = "recipient";
/** Key timestamp. */
private static final String KEY_TIMESTAMP = "timestamp";
/** Key message ID. */
Expand All @@ -88,7 +84,6 @@ public class ErrorHeader extends Header {
*
* @param ctx MSL context.
* @param entityAuthData the entity authentication data.
* @param recipient the intended recipient's entity identity. May be null.
* @param messageId the message ID.
* @param errorCode the error code.
* @param internalCode the internal code. Negative to indicate no code.
Expand All @@ -97,7 +92,7 @@ public class ErrorHeader extends Header {
* @throws MslMessageException if no entity authentication data is
* provided.
*/
public ErrorHeader(final MslContext ctx, final EntityAuthenticationData entityAuthData, final String recipient, final long messageId, final ResponseCode errorCode, final int internalCode, final String errorMsg, final String userMsg) throws MslMessageException {
public ErrorHeader(final MslContext ctx, final EntityAuthenticationData entityAuthData, final long messageId, final ResponseCode errorCode, final int internalCode, final String errorMsg, final String userMsg) throws MslMessageException {
// Message ID must be within range.
if (messageId < 0 || messageId > MslConstants.MAX_LONG_VALUE)
throw new MslInternalException("Message ID " + messageId + " is out of range.");
Expand All @@ -106,13 +101,8 @@ public ErrorHeader(final MslContext ctx, final EntityAuthenticationData entityAu
if (entityAuthData == null)
throw new MslMessageException(MslError.MESSAGE_ENTITY_NOT_FOUND);

// Only include the recipient if the message will be encrypted.
final EntityAuthenticationScheme scheme = entityAuthData.getScheme();
final boolean encrypted = scheme.encrypts();

this.ctx = ctx;
this.entityAuthData = entityAuthData;
this.recipient = (encrypted) ? recipient : null;
this.timestamp = ctx.getTime() / MILLISECONDS_PER_SECOND;
this.messageId = messageId;
this.errorCode = errorCode;
Expand All @@ -123,7 +113,6 @@ public ErrorHeader(final MslContext ctx, final EntityAuthenticationData entityAu
// Construct the error data.
final MslEncoderFactory encoder = ctx.getMslEncoderFactory();
errordata = encoder.createObject();
if (this.recipient != null) errordata.put(KEY_RECIPIENT, this.recipient);
errordata.put(KEY_TIMESTAMP, this.timestamp);
errordata.put(KEY_MESSAGE_ID, this.messageId);
errordata.put(KEY_ERROR_CODE, this.errorCode.intValue());
Expand Down Expand Up @@ -189,7 +178,6 @@ protected ErrorHeader(final MslContext ctx, final byte[] errordataBytes, final E
}

try {
recipient = (errordata.has(KEY_RECIPIENT)) ? errordata.getString(KEY_RECIPIENT) : null;
timestamp = (errordata.has(KEY_TIMESTAMP)) ? errordata.getLong(KEY_TIMESTAMP) : null;

// If we do not recognize the error code then default to fail.
Expand Down Expand Up @@ -224,13 +212,6 @@ public EntityAuthenticationData getEntityAuthenticationData() {
return entityAuthData;
}

/**
* @return the recipient. May be null.
*/
public String getRecipient() {
return recipient;
}

/**
* @return the timestamp. May be null.
*/
Expand Down Expand Up @@ -336,7 +317,6 @@ public boolean equals(final Object obj) {
if (!(obj instanceof ErrorHeader)) return false;
final ErrorHeader that = (ErrorHeader)obj;
return entityAuthData.equals(that.entityAuthData) &&
(recipient == that.recipient || (recipient != null && recipient.equals(that.recipient))) &&
(timestamp != null && timestamp.equals(that.timestamp) ||
timestamp == null && that.timestamp == null) &&
messageId == that.messageId &&
Expand All @@ -352,7 +332,6 @@ public boolean equals(final Object obj) {
@Override
public int hashCode() {
return entityAuthData.hashCode() ^
((recipient != null) ? recipient.hashCode() : 0) ^
((timestamp != null) ? timestamp.hashCode() : 0) ^
Long.valueOf(messageId).hashCode() ^
errorCode.hashCode() ^
Expand All @@ -369,8 +348,6 @@ public int hashCode() {
/** Error data. */
private final MslObject errordata;

/** Recipient. */
private final String recipient;
/** Timestamp in seconds since the epoch. */
private final Long timestamp;
/** Message ID. */
Expand Down
37 changes: 12 additions & 25 deletions core/src/main/java/com/netflix/msl/msg/MessageBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,17 +182,16 @@ private static KeyExchangeData issueMasterToken(final MslContext ctx, final MslE
* @param masterToken master token. May be null unless a user ID token is
* provided.
* @param userIdToken user ID token. May be null.
* @param recipient message recipient. May be null.
* @param messageId the message ID to use. Must be within range.
* @return the message builder.
* @throws MslException if a user ID token is not bound to its
* corresponding master token.
*/
public static MessageBuilder createRequest(final MslContext ctx, final MasterToken masterToken, final UserIdToken userIdToken, final String recipient, final long messageId) throws MslException {
public static MessageBuilder createRequest(final MslContext ctx, final MasterToken masterToken, final UserIdToken userIdToken, final long messageId) throws MslException {
if (messageId < 0 || messageId > MslConstants.MAX_LONG_VALUE)
throw new MslInternalException("Message ID " + messageId + " is outside the valid range.");
final MessageCapabilities capabilities = ctx.getMessageCapabilities();
return new MessageBuilder(ctx, recipient, messageId, capabilities, masterToken, userIdToken, null, null, null, null, null);
return new MessageBuilder(ctx, messageId, capabilities, masterToken, userIdToken, null, null, null, null, null);
}

/**
Expand All @@ -202,15 +201,14 @@ public static MessageBuilder createRequest(final MslContext ctx, final MasterTok
* @param masterToken master token. May be null unless a user ID token is
* provided.
* @param userIdToken user ID token. May be null.
* @param recipient message recipient. May be null.
* @return the message builder.
* @throws MslException if a user ID token is not bound to its
* corresponding master token.
*/
public static MessageBuilder createRequest(final MslContext ctx, final MasterToken masterToken, final UserIdToken userIdToken, final String recipient) throws MslException {
public static MessageBuilder createRequest(final MslContext ctx, final MasterToken masterToken, final UserIdToken userIdToken) throws MslException {
final long messageId = MslUtils.getRandomLong(ctx);
final MessageCapabilities capabilities = ctx.getMessageCapabilities();
return new MessageBuilder(ctx, recipient, messageId, capabilities, masterToken, userIdToken, null, null, null, null, null);
return new MessageBuilder(ctx, messageId, capabilities, masterToken, userIdToken, null, null, null, null, null);
}

/**
Expand Down Expand Up @@ -238,9 +236,6 @@ public static MessageBuilder createResponse(final MslContext ctx, final MessageH
UserIdToken userIdToken = requestHeader.getUserIdToken();
final UserAuthenticationData userAuthData = requestHeader.getUserAuthenticationData();

// The response recipient is the requesting entity.
final String recipient = (masterToken != null) ? masterToken.getIdentity() : entityAuthData.getIdentity();

// The response message ID must be equal to the request message ID + 1.
final long requestMessageId = requestHeader.getMessageId();
final long messageId = incrementMessageId(requestMessageId);
Expand Down Expand Up @@ -343,10 +338,10 @@ else if (requestHeader.isRenewable() && userAuthMasterToken != null && userAuthD
final MasterToken peerMasterToken = (keyResponseData != null) ? keyResponseData.getMasterToken() : requestHeader.getPeerMasterToken();
final UserIdToken peerUserIdToken = requestHeader.getPeerUserIdToken();
final Set<ServiceToken> peerServiceTokens = requestHeader.getPeerServiceTokens();
return new MessageBuilder(ctx, recipient, messageId, capabilities, peerMasterToken, peerUserIdToken, peerServiceTokens, masterToken, userIdToken, serviceTokens, keyExchangeData);
return new MessageBuilder(ctx, messageId, capabilities, peerMasterToken, peerUserIdToken, peerServiceTokens, masterToken, userIdToken, serviceTokens, keyExchangeData);
} else {
final MasterToken localMasterToken = (keyResponseData != null) ? keyResponseData.getMasterToken() : masterToken;
return new MessageBuilder(ctx, recipient, messageId, capabilities, localMasterToken, userIdToken, serviceTokens, null, null, null, keyExchangeData);
return new MessageBuilder(ctx, messageId, capabilities, localMasterToken, userIdToken, serviceTokens, null, null, null, keyExchangeData);
}
} catch (final MslException e) {
e.setMasterToken(masterToken);
Expand Down Expand Up @@ -377,9 +372,6 @@ public static MessageBuilder createIdempotentResponse(final MslContext ctx, fina
final UserIdToken userIdToken = requestHeader.getUserIdToken();
final UserAuthenticationData userAuthData = requestHeader.getUserAuthenticationData();

// The response recipient is the requesting entity.
final String recipient = (masterToken != null) ? masterToken.getIdentity() : entityAuthData.getIdentity();

// The response message ID must be equal to the request message ID + 1.
final long requestMessageId = requestHeader.getMessageId();
final long messageId = incrementMessageId(requestMessageId);
Expand All @@ -398,10 +390,10 @@ public static MessageBuilder createIdempotentResponse(final MslContext ctx, fina
final MasterToken peerMasterToken = (keyResponseData != null) ? keyResponseData.getMasterToken() : requestHeader.getPeerMasterToken();
final UserIdToken peerUserIdToken = requestHeader.getPeerUserIdToken();
final Set<ServiceToken> peerServiceTokens = requestHeader.getPeerServiceTokens();
return new MessageBuilder(ctx, recipient, messageId, capabilities, peerMasterToken, peerUserIdToken, peerServiceTokens, masterToken, userIdToken, serviceTokens, null);
return new MessageBuilder(ctx, messageId, capabilities, peerMasterToken, peerUserIdToken, peerServiceTokens, masterToken, userIdToken, serviceTokens, null);
} else {
final MasterToken localMasterToken = (keyResponseData != null) ? keyResponseData.getMasterToken() : masterToken;
return new MessageBuilder(ctx, recipient, messageId, capabilities, localMasterToken, userIdToken, serviceTokens, null, null, null, null);
return new MessageBuilder(ctx, messageId, capabilities, localMasterToken, userIdToken, serviceTokens, null, null, null, null);
}
} catch (final MslException e) {
e.setMasterToken(masterToken);
Expand All @@ -419,7 +411,6 @@ public static MessageBuilder createIdempotentResponse(final MslContext ctx, fina
* specified (i.e. unknown) then a random message ID will be generated.</p>
*
* @param ctx MSL context.
* @param recipient error response recipient. May be null.
* @param requestMessageId message ID of request. May be null.
* @param error the MSL error.
* @param userMessage localized user-consumable error message. May be null.
Expand All @@ -431,7 +422,7 @@ public static MessageBuilder createIdempotentResponse(final MslContext ctx, fina
* @throws MslMessageException if no entity authentication data was
* returned by the MSL context.
*/
public static ErrorHeader createErrorResponse(final MslContext ctx, final String recipient, final Long requestMessageId, final MslError error, final String userMessage) throws MslCryptoException, MslEntityAuthException, MslMessageException {
public static ErrorHeader createErrorResponse(final MslContext ctx, final Long requestMessageId, final MslError error, final String userMessage) throws MslCryptoException, MslEntityAuthException, MslMessageException {
final EntityAuthenticationData entityAuthData = ctx.getEntityAuthenticationData(null);
// If we have the request message ID then the error response message ID
// must be equal to the request message ID + 1.
Expand All @@ -446,15 +437,14 @@ public static ErrorHeader createErrorResponse(final MslContext ctx, final String
final ResponseCode errorCode = error.getResponseCode();
final int internalCode = error.getInternalCode();
final String errorMsg = error.getMessage();
return new ErrorHeader(ctx, entityAuthData, recipient, messageId, errorCode, internalCode, errorMsg, userMessage);
return new ErrorHeader(ctx, entityAuthData, messageId, errorCode, internalCode, errorMsg, userMessage);
}

/**
* Create a new message builder with the provided tokens and key exchange
* data if a master token was issued or renewed.
*
* @param ctx MSL context.
* @param recipient message recipient. May be null.
* @param messageId message ID.
* @param capabilities message capabilities.
* @param masterToken master token. May be null unless a user ID token is
Expand All @@ -470,7 +460,7 @@ public static ErrorHeader createErrorResponse(final MslContext ctx, final String
* @throws MslException if a user ID token is not bound to its master
* token.
*/
private MessageBuilder(final MslContext ctx, final String recipient, final long messageId, final MessageCapabilities capabilities, final MasterToken masterToken, final UserIdToken userIdToken, final Set<ServiceToken> serviceTokens, final MasterToken peerMasterToken, final UserIdToken peerUserIdToken, final Set<ServiceToken> peerServiceTokens, final KeyExchangeData keyExchangeData) throws MslException {
private MessageBuilder(final MslContext ctx, final long messageId, final MessageCapabilities capabilities, final MasterToken masterToken, final UserIdToken userIdToken, final Set<ServiceToken> serviceTokens, final MasterToken peerMasterToken, final UserIdToken peerUserIdToken, final Set<ServiceToken> peerServiceTokens, final KeyExchangeData keyExchangeData) throws MslException {
// Primary and peer token combinations will be verified when the
// message header is constructed. So delay those checks in favor of
// avoiding duplicate code.
Expand All @@ -479,7 +469,6 @@ private MessageBuilder(final MslContext ctx, final String recipient, final long

// Set the primary fields.
this.ctx = ctx;
this.recipient = recipient;
this.messageId = messageId;
this.capabilities = capabilities;
this.masterToken = masterToken;
Expand Down Expand Up @@ -625,7 +614,7 @@ public MessageHeader getHeader() throws MslCryptoException, MslMasterTokenExcept
} else {
nonReplayableId = null;
}
final HeaderData headerData = new HeaderData(recipient, messageId, nonReplayableId, renewable, handshake, capabilities, keyRequestData, response, userAuthData, userIdToken, tokens);
final HeaderData headerData = new HeaderData(messageId, nonReplayableId, renewable, handshake, capabilities, keyRequestData, response, userAuthData, userIdToken, tokens);
final Set<ServiceToken> peerTokens = new HashSet<ServiceToken>(peerServiceTokens.values());
final HeaderPeerData peerData = new HeaderPeerData(peerMasterToken, peerUserIdToken, peerTokens);

Expand Down Expand Up @@ -1140,8 +1129,6 @@ public Set<ServiceToken> getPeerServiceTokens() {

/** Message header master token. */
private MasterToken masterToken;
/** Message recipient. */
private final String recipient;
/** Header data message ID. */
private long messageId;
/** Key exchange data. */
Expand Down
13 changes: 6 additions & 7 deletions core/src/main/java/com/netflix/msl/msg/MessageContext.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2012-2014 Netflix, Inc. All rights reserved.
* Copyright (c) 2012-2018 Netflix, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -98,16 +98,15 @@ public int intValue() {
public Map<String,ICryptoContext> getCryptoContexts();

/**
* <p>Called to identify the entity identity the message application data
* is intended for. If the identity is not known this method must return
* {@code null}.</p>
* <p>Called to identify the expected remote entity identity. If the remote
* entity identity is not known this method must return {@code null}.</p>
*
* <p>Trusted network servers may always return {@code null}.</p>
*
* @return the entity identity of the application data recipient or
* {@code null} if the identity is not known.
* @return the remote entity identity or {@code null} if the identity is
* not known.
*/
public String getRecipient();
public String getRemoteEntityIdentity();

/**
* <p>Called to determine if the message application data must be
Expand Down
Loading

0 comments on commit cb40f2e

Please sign in to comment.