1 /*
2  * Copyright (C) 2018 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 android.security.keystore.recovery;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import com.android.internal.util.Preconditions;
26 
27 /**
28  * Helper class with data necessary recover a single application key, given a recovery key.
29  *
30  * <ul>
31  *   <li>Alias - Keystore alias of the key.
32  *   <li>Encrypted key material.
33  * </ul>
34  *
35  * Note that Application info is not included. Recovery Agent can only make its own keys
36  * recoverable.
37  *
38  * @hide
39  */
40 @SystemApi
41 public final class WrappedApplicationKey implements Parcelable {
42     private String mAlias;
43     // The only supported format is AES-256 symmetric key.
44     private byte[] mEncryptedKeyMaterial;
45     // The optional metadata that's authenticated (but unencrypted) with the key material.
46     private byte[] mMetadata;
47 
48     // IMPORTANT! PLEASE READ!
49     // -----------------------
50     // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following:
51     // - Update the #writeToParcel(Parcel) method below
52     // - Update the #(Parcel) constructor below
53     // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody
54     //     accidentally breaks your fields in the Parcel in the future.
55     // - Update com.android.server.locksettings.recoverablekeystore.serialization
56     //     .KeyChainSnapshotSerializer to correctly serialize your new field
57     // - Update com.android.server.locksettings.recoverablekeystore.serialization
58     //     .KeyChainSnapshotSerializer to correctly deserialize your new field
59     // - Update com.android.server.locksettings.recoverablekeystore.serialization
60     //     .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field
61     //     in the future.
62 
63     /**
64      * Builder for creating {@link WrappedApplicationKey}.
65      */
66     public static class Builder {
67         private WrappedApplicationKey mInstance = new WrappedApplicationKey();
68 
69         /**
70          * Sets Application-specific alias of the key.
71          *
72          * @param alias The alias.
73          * @return This builder.
74          */
setAlias(@onNull String alias)75         public @NonNull Builder setAlias(@NonNull String alias) {
76             mInstance.mAlias = alias;
77             return this;
78         }
79 
80         /**
81          * Sets key material encrypted by recovery key.
82          *
83          * @param encryptedKeyMaterial The key material
84          * @return This builder
85          */
setEncryptedKeyMaterial(@onNull byte[] encryptedKeyMaterial)86         public @NonNull Builder setEncryptedKeyMaterial(@NonNull byte[] encryptedKeyMaterial) {
87             mInstance.mEncryptedKeyMaterial = encryptedKeyMaterial;
88             return this;
89         }
90 
91         /**
92          * Sets the metadata that is authenticated (but unecrypted) with the key material.
93          *
94          * @param metadata The metadata
95          * @return This builder
96          */
setMetadata(@ullable byte[] metadata)97         public @NonNull Builder setMetadata(@Nullable byte[] metadata) {
98             mInstance.mMetadata = metadata;
99             return this;
100         }
101 
102         /**
103          * Creates a new {@link WrappedApplicationKey} instance.
104          *
105          * @return new instance
106          * @throws NullPointerException if some required fields were not set.
107          */
build()108         public @NonNull WrappedApplicationKey build() {
109             Preconditions.checkNotNull(mInstance.mAlias);
110             Preconditions.checkNotNull(mInstance.mEncryptedKeyMaterial);
111             return mInstance;
112         }
113     }
114 
WrappedApplicationKey()115     private WrappedApplicationKey() { }
116 
117     /**
118      * @deprecated Use the builder instead.
119      * @hide
120      */
121     @Deprecated
WrappedApplicationKey(@onNull String alias, @NonNull byte[] encryptedKeyMaterial)122     public WrappedApplicationKey(@NonNull String alias, @NonNull byte[] encryptedKeyMaterial) {
123         mAlias = Preconditions.checkNotNull(alias);
124         mEncryptedKeyMaterial = Preconditions.checkNotNull(encryptedKeyMaterial);
125     }
126 
127     /**
128      * Application-specific alias of the key.
129      *
130      * @see java.security.KeyStore.aliases
131      */
getAlias()132     public @NonNull String getAlias() {
133         return mAlias;
134     }
135 
136     /** Key material encrypted by recovery key. */
getEncryptedKeyMaterial()137     public @NonNull byte[] getEncryptedKeyMaterial() {
138         return mEncryptedKeyMaterial;
139     }
140 
141     /** The metadata with the key. */
getMetadata()142     public @Nullable byte[] getMetadata() {
143         return mMetadata;
144     }
145 
146     public static final @NonNull Parcelable.Creator<WrappedApplicationKey> CREATOR =
147             new Parcelable.Creator<WrappedApplicationKey>() {
148                 public WrappedApplicationKey createFromParcel(Parcel in) {
149                     return new WrappedApplicationKey(in);
150                 }
151 
152                 public WrappedApplicationKey[] newArray(int length) {
153                     return new WrappedApplicationKey[length];
154                 }
155             };
156 
157     @Override
writeToParcel(Parcel out, int flags)158     public void writeToParcel(Parcel out, int flags) {
159         out.writeString(mAlias);
160         out.writeByteArray(mEncryptedKeyMaterial);
161         out.writeByteArray(mMetadata);
162     }
163 
164     /**
165      * @hide
166      */
WrappedApplicationKey(Parcel in)167     protected WrappedApplicationKey(Parcel in) {
168         mAlias = in.readString();
169         mEncryptedKeyMaterial = in.createByteArray();
170         // Check if there is still data to be read.
171         if (in.dataAvail() > 0) {
172             mMetadata = in.createByteArray();
173         }
174     }
175 
176     @Override
describeContents()177     public int describeContents() {
178         return 0;
179     }
180 }
181