blob: a79c64e055948c109d9459464bfe65de621248f2 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.car.encryptionrunner;
import android.text.TextUtils;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* During an {@link EncryptionRunner} handshake process, these are the messages returned as part
* of each step.
*/
public class HandshakeMessage {
/**
* States for handshake progress.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({HandshakeState.UNKNOWN, HandshakeState.IN_PROGRESS, HandshakeState.VERIFICATION_NEEDED,
HandshakeState.FINISHED, HandshakeState.INVALID, HandshakeState.RESUMING_SESSION,
HandshakeState.OOB_VERIFICATION_NEEDED})
public @interface HandshakeState {
/**
* The initial state, this value is not expected to be returned.
*/
int UNKNOWN = 0;
/**
* The handshake is in progress.
*/
int IN_PROGRESS = 1;
/**
* The handshake is complete, but verification of the code is needed.
*/
int VERIFICATION_NEEDED = 2;
/**
* The handshake is complete.
*/
int FINISHED = 3;
/**
* The handshake is complete and not successful.
*/
int INVALID = 4;
/**
* The handshake is complete, but extra verification is needed.
*/
int RESUMING_SESSION = 5;
/**
* The handshake is complete, but out of band verification of the code is needed.
*/
int OOB_VERIFICATION_NEEDED = 6;
}
@HandshakeState
private final int mHandshakeState;
private final Key mKey;
private final byte[] mNextMessage;
private final String mVerificationCode;
private final byte[] mOobVerificationCode;
/**
* @return Returns a builder for {@link HandshakeMessage}.
*/
public static Builder newBuilder() {
return new Builder();
}
/**
* Use the builder;
*/
private HandshakeMessage(
@HandshakeState int handshakeState,
@Nullable Key key,
@Nullable byte[] nextMessage,
@Nullable String verificationCode,
@Nullable byte[] oobVerificationCode) {
mHandshakeState = handshakeState;
mKey = key;
mNextMessage = nextMessage;
mVerificationCode = verificationCode;
mOobVerificationCode = oobVerificationCode;
}
/**
* Returns the next message to send in a handshake.
*/
@Nullable
public byte[] getNextMessage() {
return mNextMessage == null ? null : mNextMessage.clone();
}
/**
* Returns the state of the handshake.
*/
@HandshakeState
public int getHandshakeState() {
return mHandshakeState;
}
/**
* Returns the encryption key that can be used to encrypt data.
*/
@Nullable
public Key getKey() {
return mKey;
}
/**
* Returns a verification code to show to the user.
*/
@Nullable
public String getVerificationCode() {
return mVerificationCode;
}
/**
* Returns a verification code to be encrypted using an out-of-band key and sent to the remote
* device.
*/
@Nullable
public byte[] getOobVerificationCode() {
return mOobVerificationCode;
}
static class Builder {
@HandshakeState
int mHandshakeState;
Key mKey;
byte[] mNextMessage;
String mVerificationCode;
byte[] mOobVerificationCode;
Builder setHandshakeState(@HandshakeState int handshakeState) {
mHandshakeState = handshakeState;
return this;
}
Builder setKey(@Nullable Key key) {
mKey = key;
return this;
}
Builder setNextMessage(@Nullable byte[] nextMessage) {
mNextMessage = nextMessage == null ? null : nextMessage.clone();
return this;
}
Builder setVerificationCode(@Nullable String verificationCode) {
mVerificationCode = verificationCode;
return this;
}
Builder setOobVerificationCode(@NonNull byte[] oobVerificationCode) {
mOobVerificationCode = oobVerificationCode;
return this;
}
HandshakeMessage build() {
if (mHandshakeState == HandshakeState.UNKNOWN) {
throw new IllegalStateException("must set handshake state before calling build");
}
if (mHandshakeState == HandshakeState.VERIFICATION_NEEDED
&& TextUtils.isEmpty(mVerificationCode)) {
throw new IllegalStateException(
"State is verification needed, but verification code null.");
}
if (mHandshakeState == HandshakeState.OOB_VERIFICATION_NEEDED
&& (mOobVerificationCode == null || mOobVerificationCode.length == 0)) {
throw new IllegalStateException(
"State is OOB verification needed, but OOB verification code null.");
}
return new HandshakeMessage(mHandshakeState, mKey, mNextMessage, mVerificationCode,
mOobVerificationCode);
}
}
}