1 /*
2 * Copyright (C) 2020 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 #include <errno.h>
18 #include <getopt.h>
19 #include <libxml/xmlreader.h>
20 #include <openssl/pem.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/uio.h>
26 #include <unistd.h>
27 #include <string>
28
29 #include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
30
31 static const char* _sopts = "h";
32 static const struct option _lopts[] = {
33 {"help", no_argument, 0, 'h'},
34 {0, 0, 0, 0},
35 };
36
37 static const char* usage =
38 "Usage: %s [options] xml-file\n"
39 "\n"
40 "options:\n"
41 " -h, --help prints this message and exit\n"
42 "\n";
43
print_usage_and_exit(const char * prog,int code)44 static void print_usage_and_exit(const char* prog, int code) {
45 fprintf(stderr, usage, prog);
46 exit(code);
47 }
48
parse_options(int argc,char ** argv)49 static void parse_options(int argc, char** argv) {
50 int c;
51 int oidx = 0;
52
53 while (1) {
54 c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
55 if (c == -1) {
56 break; /* done */
57 }
58
59 switch (c) {
60 case 'h':
61 print_usage_and_exit(argv[0], EXIT_SUCCESS);
62 break;
63
64 default:
65 print_usage_and_exit(argv[0], EXIT_FAILURE);
66 }
67 }
68 }
69
70 struct AppendUdsCertificateRequest : public keymaster::KeymasterMessage {
AppendUdsCertificateRequestAppendUdsCertificateRequest71 explicit AppendUdsCertificateRequest(int32_t ver = keymaster::kDefaultMessageVersion)
72 : KeymasterMessage(ver) {}
73
SerializedSizeAppendUdsCertificateRequest74 size_t SerializedSize() const override { return cert_data.SerializedSize(); }
SerializeAppendUdsCertificateRequest75 uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
76 return cert_data.Serialize(buf, end);
77 }
DeserializeAppendUdsCertificateRequest78 bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
79 return cert_data.Deserialize(buf_ptr, end);
80 }
81
82 keymaster::Buffer cert_data;
83 };
84
85 struct ClearUdsCertificateRequest : public keymaster::KeymasterMessage {
ClearUdsCertificateRequestClearUdsCertificateRequest86 explicit ClearUdsCertificateRequest(int32_t ver = keymaster::kDefaultMessageVersion)
87 : KeymasterMessage(ver) {}
88
SerializedSizeClearUdsCertificateRequest89 size_t SerializedSize() const override { return 0; }
SerializeClearUdsCertificateRequest90 uint8_t* Serialize(uint8_t* buf, const uint8_t*) const override { return buf; }
DeserializeClearUdsCertificateRequest91 bool Deserialize(const uint8_t**, const uint8_t*) override { return true; };
92 };
93
94 struct KeymasterNoResponse : public keymaster::KeymasterResponse{
KeymasterNoResponseKeymasterNoResponse95 explicit KeymasterNoResponse(int32_t ver = keymaster::kDefaultMessageVersion)
96 : keymaster::KeymasterResponse(ver) {}
97
NonErrorSerializedSizeKeymasterNoResponse98 size_t NonErrorSerializedSize() const override { return 0; }
NonErrorSerializeKeymasterNoResponse99 uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
NonErrorDeserializeKeymasterNoResponse100 bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
101 };
102
103 struct AppendUdsCertificateResponse : public KeymasterNoResponse {};
104 struct ClearUdsCertificateResponse : public KeymasterNoResponse {};
105
set_uds_cert_bin(uint32_t cmd,const void * cert_data,size_t cert_data_size)106 static int set_uds_cert_bin(uint32_t cmd, const void* cert_data, size_t cert_data_size) {
107 int ret;
108
109 AppendUdsCertificateRequest req;
110 req.cert_data.Reinitialize(cert_data, cert_data_size);
111 AppendUdsCertificateResponse rsp;
112
113 ret = trusty_keymaster_send(cmd, req, &rsp);
114 if (ret) {
115 fprintf(stderr, "trusty_keymaster_send cmd 0x%x failed %d\n", cmd, ret);
116 return ret;
117 }
118
119 return 0;
120 }
121
set_uds_cert_pem(uint32_t cmd,const xmlChar * pemkey)122 static int set_uds_cert_pem(uint32_t cmd, const xmlChar* pemkey) {
123 int ret;
124 int sslret;
125
126 /* Convert from pem to binary */
127 BIO* bio = BIO_new_mem_buf(pemkey, xmlStrlen(pemkey));
128 if (!bio) {
129 fprintf(stderr, "BIO_new_mem_buf failed\n");
130 ERR_print_errors_fp(stderr);
131 return -1;
132 }
133
134 char* key_name;
135 char* key_header;
136 uint8_t* key;
137 long keylen;
138 sslret = PEM_read_bio(bio, &key_name, &key_header, &key, &keylen);
139 BIO_free(bio);
140
141 if (!sslret) {
142 fprintf(stderr, "PEM_read_bio failed\n");
143 ERR_print_errors_fp(stderr);
144 return -1;
145 }
146
147 /* Send key in binary format to trusty */
148 ret = set_uds_cert_bin(cmd, key, keylen);
149
150 OPENSSL_free(key_name);
151 OPENSSL_free(key_header);
152 OPENSSL_free(key);
153
154 return ret;
155 }
156
set_uds_cert(uint32_t cmd,const xmlChar * format,const xmlChar * str)157 static int set_uds_cert(uint32_t cmd, const xmlChar* format, const xmlChar* str) {
158 int ret;
159
160 if (xmlStrEqual(format, BAD_CAST "pem")) {
161 ret = set_uds_cert_pem(cmd, str);
162 } else {
163 printf("unsupported key/cert format: %s\n", format);
164 return -1;
165 }
166 return ret;
167 }
168
169 // TODO: Guard by Production Mode
clear_cert_chain()170 static int clear_cert_chain() {
171 int ret;
172 ClearUdsCertificateRequest req;
173 ClearUdsCertificateResponse rsp;
174
175 ret = trusty_keymaster_send(KM_CLEAR_UDS_CERT_CHAIN, req, &rsp);
176 if (ret) {
177 fprintf(stderr, "%s: trusty_keymaster_send failed %d\n", __func__, ret);
178 return ret;
179 }
180 return 0;
181 }
182
process_xml(xmlTextReaderPtr xml)183 static int process_xml(xmlTextReaderPtr xml) {
184 int ret;
185 const xmlChar* element = NULL;
186 const xmlChar* element_format = NULL;
187 bool isPixelUdsCert = false;
188
189 while ((ret = xmlTextReaderRead(xml)) == 1) {
190 int nodetype = xmlTextReaderNodeType(xml);
191 const xmlChar *name, *value;
192 name = xmlTextReaderConstName(xml);
193 switch (nodetype) {
194 case XML_READER_TYPE_ELEMENT:
195 element = name;
196 element_format = xmlTextReaderGetAttribute(xml, BAD_CAST "format");
197 if (isPixelUdsCert || xmlStrEqual(name, BAD_CAST "PixelUdsCertificates")) {
198 // The first element name must be "PixelUdsCertificates"
199 isPixelUdsCert = true;
200 } else {
201 fprintf(stderr, "Not a PixelUdsCertificates: \"%s\"\n", name);
202 return -1;
203 }
204 if (xmlStrEqual(name, BAD_CAST "CertificateChain")) {
205 ret = clear_cert_chain();
206 if (ret) {
207 fprintf(stderr, "%s: Clear cert chain cmd failed, %d\n", element, ret);
208 return ret;
209 }
210 printf("%s: Clear cert chain cmd done\n", element);
211 }
212 break;
213 case XML_READER_TYPE_TEXT:
214 value = xmlTextReaderConstValue(xml);
215 uint32_t cmd;
216 if (xmlStrEqual(element, BAD_CAST "Certificate")) {
217 cmd = KM_APPEND_UDS_CERT_CHAIN;
218 } else {
219 break;
220 }
221
222 ret = set_uds_cert(cmd, element_format, value);
223 if (ret) {
224 fprintf(stderr, "%s, format %s: Cmd 0x%x failed, %d\n", element, element_format,
225 cmd, ret);
226 return ret;
227 }
228 printf("%s, format %s: Cmd 0x%x done\n", element, element_format, cmd);
229 break;
230 case XML_READER_TYPE_END_ELEMENT:
231 element = NULL;
232 break;
233 }
234 }
235 return ret;
236 }
237
parse_and_provision_xml_file(const char * filename)238 static int parse_and_provision_xml_file(const char* filename) {
239 int ret;
240 xmlTextReaderPtr xml = xmlReaderForFile(filename, NULL, 0);
241 if (!xml) {
242 fprintf(stderr, "failed to open %s\n", filename);
243 return -1;
244 }
245
246 ret = process_xml(xml);
247
248 xmlFreeTextReader(xml);
249 if (ret != 0) {
250 fprintf(stderr, "Failed to parse or process %s\n", filename);
251 return -1;
252 }
253
254 return 0;
255 }
256
main(int argc,char ** argv)257 int main(int argc, char** argv) {
258 int ret = 0;
259
260 parse_options(argc, argv);
261 if (optind + 1 != argc) {
262 print_usage_and_exit(argv[0], EXIT_FAILURE);
263 }
264
265 ret = trusty_keymaster_connect();
266 if (ret) {
267 fprintf(stderr, "trusty_keymaster_connect failed %d\n", ret);
268 return EXIT_FAILURE;
269 }
270
271 ret = parse_and_provision_xml_file(argv[optind]);
272 if (ret) {
273 fprintf(stderr, "parse_and_provision_xml_file failed %d\n", ret);
274 trusty_keymaster_disconnect();
275 return EXIT_FAILURE;
276 }
277
278 return EXIT_SUCCESS;
279 }
280