xref: /aosp_15_r20/system/core/trusty/keymaster/set_uds_certs/set_uds_certificates.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
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