1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.widget; 18 19 import android.annotation.IntDef; 20 import android.annotation.Nullable; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.service.gatekeeper.GateKeeperResponse; 24 import android.util.Slog; 25 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 29 /** 30 * Response object for a ILockSettings credential verification request. 31 * @hide 32 */ 33 public final class VerifyCredentialResponse implements Parcelable { 34 35 public static final int RESPONSE_ERROR = -1; 36 public static final int RESPONSE_OK = 0; 37 public static final int RESPONSE_RETRY = 1; 38 @IntDef({RESPONSE_ERROR, 39 RESPONSE_OK, 40 RESPONSE_RETRY}) 41 @Retention(RetentionPolicy.SOURCE) 42 @interface ResponseCode {} 43 44 public static final VerifyCredentialResponse OK = new VerifyCredentialResponse.Builder() 45 .build(); 46 public static final VerifyCredentialResponse ERROR = fromError(); 47 private static final String TAG = "VerifyCredentialResponse"; 48 49 private final @ResponseCode int mResponseCode; 50 private final int mTimeout; 51 @Nullable private final byte[] mGatekeeperHAT; 52 private final long mGatekeeperPasswordHandle; 53 54 public static final Parcelable.Creator<VerifyCredentialResponse> CREATOR 55 = new Parcelable.Creator<VerifyCredentialResponse>() { 56 @Override 57 public VerifyCredentialResponse createFromParcel(Parcel source) { 58 final @ResponseCode int responseCode = source.readInt(); 59 final int timeout = source.readInt(); 60 final byte[] gatekeeperHAT = source.createByteArray(); 61 long gatekeeperPasswordHandle = source.readLong(); 62 63 return new VerifyCredentialResponse(responseCode, timeout, gatekeeperHAT, 64 gatekeeperPasswordHandle); 65 } 66 67 @Override 68 public VerifyCredentialResponse[] newArray(int size) { 69 return new VerifyCredentialResponse[size]; 70 } 71 }; 72 73 public static class Builder { 74 @Nullable private byte[] mGatekeeperHAT; 75 private long mGatekeeperPasswordHandle; 76 77 /** 78 * @param gatekeeperHAT Gatekeeper HardwareAuthToken, minted upon successful authentication. 79 */ setGatekeeperHAT(byte[] gatekeeperHAT)80 public Builder setGatekeeperHAT(byte[] gatekeeperHAT) { 81 mGatekeeperHAT = gatekeeperHAT; 82 return this; 83 } 84 setGatekeeperPasswordHandle(long gatekeeperPasswordHandle)85 public Builder setGatekeeperPasswordHandle(long gatekeeperPasswordHandle) { 86 mGatekeeperPasswordHandle = gatekeeperPasswordHandle; 87 return this; 88 } 89 90 /** 91 * Builds a VerifyCredentialResponse with {@link #RESPONSE_OK} and any other parameters 92 * that were preveiously set. 93 * @return 94 */ build()95 public VerifyCredentialResponse build() { 96 return new VerifyCredentialResponse(RESPONSE_OK, 97 0 /* timeout */, 98 mGatekeeperHAT, 99 mGatekeeperPasswordHandle); 100 } 101 } 102 103 /** 104 * Since timeouts are always an error, provide a way to create the VerifyCredentialResponse 105 * object directly. None of the other fields (Gatekeeper HAT, Gatekeeper Password, etc) 106 * are valid in this case. Similarly, the response code will always be 107 * {@link #RESPONSE_RETRY}. 108 */ fromTimeout(int timeout)109 public static VerifyCredentialResponse fromTimeout(int timeout) { 110 return new VerifyCredentialResponse(RESPONSE_RETRY, 111 timeout, 112 null /* gatekeeperHAT */, 113 0L /* gatekeeperPasswordHandle */); 114 } 115 116 /** 117 * Since error (incorrect password) should never result in any of the other fields from 118 * being populated, provide a default method to return a VerifyCredentialResponse. 119 */ fromError()120 public static VerifyCredentialResponse fromError() { 121 return new VerifyCredentialResponse(RESPONSE_ERROR, 122 0 /* timeout */, 123 null /* gatekeeperHAT */, 124 0L /* gatekeeperPasswordHandle */); 125 } 126 VerifyCredentialResponse(@esponseCode int responseCode, int timeout, @Nullable byte[] gatekeeperHAT, long gatekeeperPasswordHandle)127 private VerifyCredentialResponse(@ResponseCode int responseCode, int timeout, 128 @Nullable byte[] gatekeeperHAT, long gatekeeperPasswordHandle) { 129 mResponseCode = responseCode; 130 mTimeout = timeout; 131 mGatekeeperHAT = gatekeeperHAT; 132 mGatekeeperPasswordHandle = gatekeeperPasswordHandle; 133 } 134 stripPayload()135 public VerifyCredentialResponse stripPayload() { 136 return new VerifyCredentialResponse(mResponseCode, mTimeout, 137 null /* gatekeeperHAT */, 0L /* gatekeeperPasswordHandle */); 138 } 139 140 @Override writeToParcel(Parcel dest, int flags)141 public void writeToParcel(Parcel dest, int flags) { 142 dest.writeInt(mResponseCode); 143 dest.writeInt(mTimeout); 144 dest.writeByteArray(mGatekeeperHAT); 145 dest.writeLong(mGatekeeperPasswordHandle); 146 } 147 148 @Override describeContents()149 public int describeContents() { 150 return 0; 151 } 152 153 @Nullable getGatekeeperHAT()154 public byte[] getGatekeeperHAT() { 155 return mGatekeeperHAT; 156 } 157 getGatekeeperPasswordHandle()158 public long getGatekeeperPasswordHandle() { 159 return mGatekeeperPasswordHandle; 160 } 161 containsGatekeeperPasswordHandle()162 public boolean containsGatekeeperPasswordHandle() { 163 return mGatekeeperPasswordHandle != 0L; 164 } 165 getTimeout()166 public int getTimeout() { 167 return mTimeout; 168 } 169 getResponseCode()170 public @ResponseCode int getResponseCode() { 171 return mResponseCode; 172 } 173 isMatched()174 public boolean isMatched() { 175 return mResponseCode == RESPONSE_OK; 176 } 177 178 @Override toString()179 public String toString() { 180 return "Response: " + mResponseCode 181 + ", GK HAT: " + (mGatekeeperHAT != null) 182 + ", GK PW: " + (mGatekeeperPasswordHandle != 0L); 183 } 184 fromGateKeeperResponse( GateKeeperResponse gateKeeperResponse)185 public static VerifyCredentialResponse fromGateKeeperResponse( 186 GateKeeperResponse gateKeeperResponse) { 187 int responseCode = gateKeeperResponse.getResponseCode(); 188 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { 189 return fromTimeout(gateKeeperResponse.getTimeout()); 190 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) { 191 byte[] token = gateKeeperResponse.getPayload(); 192 if (token == null) { 193 // something's wrong if there's no payload with a challenge 194 Slog.e(TAG, "verifyChallenge response had no associated payload"); 195 return fromError(); 196 } else { 197 return new VerifyCredentialResponse.Builder().setGatekeeperHAT(token).build(); 198 } 199 } else { 200 return fromError(); 201 } 202 } 203 } 204