blob: f817a8fb02e4a4b6e5a0afad0cbdef5c02a816a0 [file] [log] [blame]
Robert Berry25f51352018-03-28 20:26:57 +01001/*
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
17package com.android.server.locksettings.recoverablekeystore.serialization;
18
19
20import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.CERT_PATH_ENCODING;
21import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.NAMESPACE;
22import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.OUTPUT_ENCODING;
23import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALGORITHM;
24import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS;
25import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY;
26import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS;
27import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID;
28import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL;
29import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS;
30import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST;
31import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_SNAPSHOT;
32import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_DERIVATION_PARAMS;
33import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_MATERIAL;
34import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_LOCK_SCREEN_UI_TYPE;
35import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MAX_ATTEMPTS;
36import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MEMORY_DIFFICULTY;
37import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SALT;
38import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SERVER_PARAMS;
39import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SNAPSHOT_VERSION;
40import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_TRUSTED_HARDWARE_CERT_PATH;
41import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_USER_SECRET_TYPE;
42
43import android.security.keystore.recovery.KeyChainProtectionParams;
44import android.security.keystore.recovery.KeyChainSnapshot;
45import android.security.keystore.recovery.KeyDerivationParams;
46import android.security.keystore.recovery.WrappedApplicationKey;
47import android.util.Base64;
48import android.util.Xml;
49
50import org.xmlpull.v1.XmlSerializer;
51
52import java.io.IOException;
53import java.io.OutputStream;
54import java.security.cert.CertPath;
55import java.security.cert.CertificateEncodingException;
56import java.util.List;
57
58/**
59 * Serializes a {@link KeyChainSnapshot} instance to XML.
60 */
61public class KeyChainSnapshotSerializer {
62
63 /**
64 * Serializes {@code keyChainSnapshot} to XML, writing to {@code outputStream}.
65 *
66 * @throws IOException if there was an IO error writing to the stream.
67 * @throws CertificateEncodingException if the {@link CertPath} from
68 * {@link KeyChainSnapshot#getTrustedHardwareCertPath()} is not encoded correctly.
69 */
70 public static void serialize(KeyChainSnapshot keyChainSnapshot, OutputStream outputStream)
71 throws IOException, CertificateEncodingException {
72 XmlSerializer xmlSerializer = Xml.newSerializer();
73 xmlSerializer.setOutput(outputStream, OUTPUT_ENCODING);
74 xmlSerializer.startDocument(
75 /*encoding=*/ null,
76 /*standalone=*/ null);
77 xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT);
78 writeKeyChainSnapshotProperties(xmlSerializer, keyChainSnapshot);
79 writeKeyChainProtectionParams(xmlSerializer,
80 keyChainSnapshot.getKeyChainProtectionParams());
81 writeApplicationKeys(xmlSerializer,
82 keyChainSnapshot.getWrappedApplicationKeys());
83 xmlSerializer.endTag(NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT);
84 xmlSerializer.endDocument();
85 }
86
87 private static void writeApplicationKeys(
88 XmlSerializer xmlSerializer, List<WrappedApplicationKey> wrappedApplicationKeys)
89 throws IOException {
90 xmlSerializer.startTag(NAMESPACE, TAG_APPLICATION_KEYS);
91 for (WrappedApplicationKey key : wrappedApplicationKeys) {
92 xmlSerializer.startTag(NAMESPACE, TAG_APPLICATION_KEY);
93 writeApplicationKeyProperties(xmlSerializer, key);
94 xmlSerializer.endTag(NAMESPACE, TAG_APPLICATION_KEY);
95 }
96 xmlSerializer.endTag(NAMESPACE, TAG_APPLICATION_KEYS);
97 }
98
99 private static void writeApplicationKeyProperties(
100 XmlSerializer xmlSerializer, WrappedApplicationKey applicationKey) throws IOException {
101 writePropertyTag(xmlSerializer, TAG_ALIAS, applicationKey.getAlias());
102 writePropertyTag(xmlSerializer, TAG_KEY_MATERIAL, applicationKey.getEncryptedKeyMaterial());
103 }
104
105 private static void writeKeyChainProtectionParams(
106 XmlSerializer xmlSerializer,
107 List<KeyChainProtectionParams> keyChainProtectionParamsList) throws IOException {
108 xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
109 for (KeyChainProtectionParams keyChainProtectionParams : keyChainProtectionParamsList) {
110 xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS);
111 writeKeyChainProtectionParamsProperties(xmlSerializer, keyChainProtectionParams);
112 xmlSerializer.endTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS);
113 }
114 xmlSerializer.endTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
115 }
116
117 private static void writeKeyChainProtectionParamsProperties(
118 XmlSerializer xmlSerializer, KeyChainProtectionParams keyChainProtectionParams)
119 throws IOException {
120 writePropertyTag(xmlSerializer, TAG_USER_SECRET_TYPE,
121 keyChainProtectionParams.getUserSecretType());
122 writePropertyTag(xmlSerializer, TAG_LOCK_SCREEN_UI_TYPE,
123 keyChainProtectionParams.getLockScreenUiFormat());
124
125 // NOTE: Do not serialize the 'secret' field. It should never be set anyway for snapshots
126 // we generate.
127
128 writeKeyDerivationParams(xmlSerializer, keyChainProtectionParams.getKeyDerivationParams());
129 }
130
131 private static void writeKeyDerivationParams(
132 XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
133 throws IOException {
134 xmlSerializer.startTag(NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
135 writeKeyDerivationParamsProperties(
136 xmlSerializer, keyDerivationParams);
137 xmlSerializer.endTag(NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
138 }
139
140 private static void writeKeyDerivationParamsProperties(
141 XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
142 throws IOException {
143 writePropertyTag(xmlSerializer, TAG_ALGORITHM, keyDerivationParams.getAlgorithm());
144 writePropertyTag(xmlSerializer, TAG_SALT, keyDerivationParams.getSalt());
145 writePropertyTag(xmlSerializer, TAG_MEMORY_DIFFICULTY,
146 keyDerivationParams.getMemoryDifficulty());
147 }
148
149 private static void writeKeyChainSnapshotProperties(
150 XmlSerializer xmlSerializer, KeyChainSnapshot keyChainSnapshot)
151 throws IOException, CertificateEncodingException {
152
153 writePropertyTag(xmlSerializer, TAG_SNAPSHOT_VERSION,
154 keyChainSnapshot.getSnapshotVersion());
155 writePropertyTag(xmlSerializer, TAG_MAX_ATTEMPTS, keyChainSnapshot.getMaxAttempts());
156 writePropertyTag(xmlSerializer, TAG_COUNTER_ID, keyChainSnapshot.getCounterId());
157 writePropertyTag(xmlSerializer, TAG_RECOVERY_KEY_MATERIAL,
158 keyChainSnapshot.getEncryptedRecoveryKeyBlob());
159 writePropertyTag(xmlSerializer, TAG_SERVER_PARAMS, keyChainSnapshot.getServerParams());
160 writePropertyTag(xmlSerializer, TAG_TRUSTED_HARDWARE_CERT_PATH,
161 keyChainSnapshot.getTrustedHardwareCertPath());
162 }
163
164 private static void writePropertyTag(
165 XmlSerializer xmlSerializer, String propertyName, long propertyValue)
166 throws IOException {
167 xmlSerializer.startTag(NAMESPACE, propertyName);
168 xmlSerializer.text(Long.toString(propertyValue));
169 xmlSerializer.endTag(NAMESPACE, propertyName);
170 }
171
172 private static void writePropertyTag(
173 XmlSerializer xmlSerializer, String propertyName, String propertyValue)
174 throws IOException {
175 xmlSerializer.startTag(NAMESPACE, propertyName);
176 xmlSerializer.text(propertyValue);
177 xmlSerializer.endTag(NAMESPACE, propertyName);
178 }
179
180 private static void writePropertyTag(
181 XmlSerializer xmlSerializer, String propertyName, byte[] propertyValue)
182 throws IOException {
183 xmlSerializer.startTag(NAMESPACE, propertyName);
184 xmlSerializer.text(Base64.encodeToString(propertyValue, /*flags=*/ Base64.DEFAULT));
185 xmlSerializer.endTag(NAMESPACE, propertyName);
186 }
187
188 private static void writePropertyTag(
189 XmlSerializer xmlSerializer, String propertyName, CertPath certPath)
190 throws IOException, CertificateEncodingException {
191 writePropertyTag(xmlSerializer, propertyName, certPath.getEncoded(CERT_PATH_ENCODING));
192 }
193
194 // Statics only
195 private KeyChainSnapshotSerializer() {}
196}