Merge "Add trusty_rkp_set_uds_cert for UdsCert provisioning" into main

This commit is contained in:
Treehugger Robot 2024-07-29 15:53:54 +00:00 committed by Gerrit Code Review
commit 69c7daf1a7
4 changed files with 358 additions and 2 deletions

View file

@ -44,7 +44,7 @@ cc_binary {
"libtrusty",
"libkeymaster_messages",
"libkeymaster3device",
"android.hardware.keymaster@3.0"
"android.hardware.keymaster@3.0",
],
}
@ -74,7 +74,7 @@ cc_binary {
"libtrusty",
"libkeymaster_messages",
"libkeymaster4",
"android.hardware.keymaster@4.0"
"android.hardware.keymaster@4.0",
],
vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
@ -208,3 +208,36 @@ cc_binary {
"-Werror",
],
}
prebuilt_etc {
name: "rkp_uds_cert_test.xml",
vendor: true,
src: "set_uds_certs/rkp_uds_cert_test.xml",
}
cc_binary {
name: "trusty_rkp_set_uds_cert",
vendor: true,
srcs: [
"set_uds_certs/set_uds_certificates.cpp",
"ipc/trusty_keymaster_ipc.cpp",
],
local_include_dirs: ["include"],
shared_libs: [
"libc",
"libcrypto",
"liblog",
"libtrusty",
"libhardware",
"libkeymaster_messages",
"libutils",
"libxml2",
],
cflags: [
"-Wall",
"-Werror",
],
}

View file

@ -78,6 +78,8 @@ enum keymaster_command : uint32_t {
KM_SET_ATTESTATION_IDS = (0xc000 << KEYMASTER_REQ_SHIFT),
KM_SET_ATTESTATION_IDS_KM3 = (0xc001 << KEYMASTER_REQ_SHIFT),
KM_CONFIGURE_BOOT_PATCHLEVEL = (0xd000 << KEYMASTER_REQ_SHIFT),
KM_APPEND_UDS_CERT_CHAIN = (0xe0000 << KEYMASTER_REQ_SHIFT),
KM_CLEAR_UDS_CERT_CHAIN = (0xe0001 << KEYMASTER_REQ_SHIFT),
};
#ifdef __ANDROID__

View file

@ -0,0 +1,42 @@
<?xml version="1.0"?>
<PixelUdsCertificates>
<CertificateChain>
<NumberOfCertificates>3</NumberOfCertificates>
<Certificate format="pem">
-----BEGIN CERTIFICATE-----
MIIBWTCB3qADAgECAgUA3q2+7zAMBggqhkjOPQQDAwUAMBIxEDAOBgNVBAMMB0dT
TUkxLjAwIhgPMjAyNDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowEjEQMA4G
A1UEAwwHR1NNSTEuMDB2MBAGByqGSM49AgEGBSuBBAAiA2IABFsNPdsPmx2NKNiT
7oReF36HTXjftRfGffYgPf/vEhrT7XLJ7dThkcb+OFYWYlOckdk3DRgqTNWQXsot
UsZhwRveU8huEjOBO5+dwDiWPs+s9jSRAn5inlTqJ0YGAmdHRzAMBggqhkjOPQQD
AwUAA2gAMGUCMQCuiJwmRWOgfWbqdSlnXfhCbphjdWc6sHelLkkM21vxQ3RZkhC2
ERh90RA1rxB+XTgCMHZrYG3leS0PEoz5hUviv27LbBHBU6GeOzrS2e0VH0BMSNXN
iP9Wnit+mJw58niEGw==
-----END CERTIFICATE-----
</Certificate>
<Certificate format="pem">
-----BEGIN CERTIFICATE-----
MIIBWTCB3qADAgECAgUA3q2+7zAMBggqhkjOPQQDAwUAMBIxEDAOBgNVBAMMB0dT
TUkxLjAwIhgPMjAyNDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowEjEQMA4G
A1UEAwwHR1NNSTEuMDB2MBAGByqGSM49AgEGBSuBBAAiA2IABFsNPdsPmx2NKNiT
7oReF36HTXjftRfGffYgPf/vEhrT7XLJ7dThkcb+OFYWYlOckdk3DRgqTNWQXsot
UsZhwRveU8huEjOBO5+dwDiWPs+s9jSRAn5inlTqJ0YGAmdHRzAMBggqhkjOPQQD
AwUAA2gAMGUCMQCuiJwmRWOgfWbqdSlnXfhCbphjdWc6sHelLkkM21vxQ3RZkhC2
ERh90RA1rxB+XTgCMHZrYG3leS0PEoz5hUviv27LbBHBU6GeOzrS2e0VH0BMSNXN
iP9Wnit+mJw58niEGw==
-----END CERTIFICATE-----
</Certificate>
<Certificate format="pem">
-----BEGIN CERTIFICATE-----
MIIBWTCB3qADAgECAgUA3q2+7zAMBggqhkjOPQQDAwUAMBIxEDAOBgNVBAMMB0dT
TUkxLjAwIhgPMjAyNDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowEjEQMA4G
A1UEAwwHR1NNSTEuMDB2MBAGByqGSM49AgEGBSuBBAAiA2IABFsNPdsPmx2NKNiT
7oReF36HTXjftRfGffYgPf/vEhrT7XLJ7dThkcb+OFYWYlOckdk3DRgqTNWQXsot
UsZhwRveU8huEjOBO5+dwDiWPs+s9jSRAn5inlTqJ0YGAmdHRzAMBggqhkjOPQQD
AwUAA2gAMGUCMQCuiJwmRWOgfWbqdSlnXfhCbphjdWc6sHelLkkM21vxQ3RZkhC2
ERh90RA1rxB+XTgCMHZrYG3leS0PEoz5hUviv27LbBHBU6GeOzrS2e0VH0BMSNXN
iP9Wnit+mJw58niEGw==
-----END CERTIFICATE-----
</Certificate>
</CertificateChain>
</PixelUdsCertificates>

View file

@ -0,0 +1,279 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <getopt.h>
#include <libxml/xmlreader.h>
#include <openssl/pem.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#include <string>
#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
static const char* _sopts = "h";
static const struct option _lopts[] = {
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0},
};
static const char* usage =
"Usage: %s [options] xml-file\n"
"\n"
"options:\n"
" -h, --help prints this message and exit\n"
"\n";
static void print_usage_and_exit(const char* prog, int code) {
fprintf(stderr, usage, prog);
exit(code);
}
static void parse_options(int argc, char** argv) {
int c;
int oidx = 0;
while (1) {
c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
if (c == -1) {
break; /* done */
}
switch (c) {
case 'h':
print_usage_and_exit(argv[0], EXIT_SUCCESS);
break;
default:
print_usage_and_exit(argv[0], EXIT_FAILURE);
}
}
}
struct AppendUdsCertificateRequest : public keymaster::KeymasterMessage {
explicit AppendUdsCertificateRequest(int32_t ver = keymaster::kDefaultMessageVersion)
: KeymasterMessage(ver) {}
size_t SerializedSize() const override { return cert_data.SerializedSize(); }
uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
return cert_data.Serialize(buf, end);
}
bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
return cert_data.Deserialize(buf_ptr, end);
}
keymaster::Buffer cert_data;
};
struct ClearUdsCertificateRequest : public keymaster::KeymasterMessage {
explicit ClearUdsCertificateRequest(int32_t ver = keymaster::kDefaultMessageVersion)
: KeymasterMessage(ver) {}
size_t SerializedSize() const override { return 0; }
uint8_t* Serialize(uint8_t* buf, const uint8_t*) const override { return buf; }
bool Deserialize(const uint8_t**, const uint8_t*) override { return true; };
};
struct KeymasterNoResponse : public keymaster::KeymasterResponse{
explicit KeymasterNoResponse(int32_t ver = keymaster::kDefaultMessageVersion)
: keymaster::KeymasterResponse(ver) {}
size_t NonErrorSerializedSize() const override { return 0; }
uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
};
struct AppendUdsCertificateResponse : public KeymasterNoResponse {};
struct ClearUdsCertificateResponse : public KeymasterNoResponse {};
static int set_uds_cert_bin(uint32_t cmd, const void* cert_data, size_t cert_data_size) {
int ret;
AppendUdsCertificateRequest req;
req.cert_data.Reinitialize(cert_data, cert_data_size);
AppendUdsCertificateResponse rsp;
ret = trusty_keymaster_send(cmd, req, &rsp);
if (ret) {
fprintf(stderr, "trusty_keymaster_send cmd 0x%x failed %d\n", cmd, ret);
return ret;
}
return 0;
}
static int set_uds_cert_pem(uint32_t cmd, const xmlChar* pemkey) {
int ret;
int sslret;
/* Convert from pem to binary */
BIO* bio = BIO_new_mem_buf(pemkey, xmlStrlen(pemkey));
if (!bio) {
fprintf(stderr, "BIO_new_mem_buf failed\n");
ERR_print_errors_fp(stderr);
return -1;
}
char* key_name;
char* key_header;
uint8_t* key;
long keylen;
sslret = PEM_read_bio(bio, &key_name, &key_header, &key, &keylen);
BIO_free(bio);
if (!sslret) {
fprintf(stderr, "PEM_read_bio failed\n");
ERR_print_errors_fp(stderr);
return -1;
}
/* Send key in binary format to trusty */
ret = set_uds_cert_bin(cmd, key, keylen);
OPENSSL_free(key_name);
OPENSSL_free(key_header);
OPENSSL_free(key);
return ret;
}
static int set_uds_cert(uint32_t cmd, const xmlChar* format, const xmlChar* str) {
int ret;
if (xmlStrEqual(format, BAD_CAST "pem")) {
ret = set_uds_cert_pem(cmd, str);
} else {
printf("unsupported key/cert format: %s\n", format);
return -1;
}
return ret;
}
// TODO: Guard by Production Mode
static int clear_cert_chain() {
int ret;
ClearUdsCertificateRequest req;
ClearUdsCertificateResponse rsp;
ret = trusty_keymaster_send(KM_CLEAR_UDS_CERT_CHAIN, req, &rsp);
if (ret) {
fprintf(stderr, "%s: trusty_keymaster_send failed %d\n", __func__, ret);
return ret;
}
return 0;
}
static int process_xml(xmlTextReaderPtr xml) {
int ret;
const xmlChar* element = NULL;
const xmlChar* element_format = NULL;
bool isPixelUdsCert = false;
while ((ret = xmlTextReaderRead(xml)) == 1) {
int nodetype = xmlTextReaderNodeType(xml);
const xmlChar *name, *value;
name = xmlTextReaderConstName(xml);
switch (nodetype) {
case XML_READER_TYPE_ELEMENT:
element = name;
element_format = xmlTextReaderGetAttribute(xml, BAD_CAST "format");
if (isPixelUdsCert || xmlStrEqual(name, BAD_CAST "PixelUdsCertificates")) {
// The first element name must be "PixelUdsCertificates"
isPixelUdsCert = true;
} else {
fprintf(stderr, "Not a PixelUdsCertificates: \"%s\"\n", name);
return -1;
}
if (xmlStrEqual(name, BAD_CAST "CertificateChain")) {
ret = clear_cert_chain();
if (ret) {
fprintf(stderr, "%s: Clear cert chain cmd failed, %d\n", element, ret);
return ret;
}
printf("%s: Clear cert chain cmd done\n", element);
}
break;
case XML_READER_TYPE_TEXT:
value = xmlTextReaderConstValue(xml);
uint32_t cmd;
if (xmlStrEqual(element, BAD_CAST "Certificate")) {
cmd = KM_APPEND_UDS_CERT_CHAIN;
} else {
break;
}
ret = set_uds_cert(cmd, element_format, value);
if (ret) {
fprintf(stderr, "%s, format %s: Cmd 0x%x failed, %d\n", element, element_format,
cmd, ret);
return ret;
}
printf("%s, format %s: Cmd 0x%x done\n", element, element_format, cmd);
break;
case XML_READER_TYPE_END_ELEMENT:
element = NULL;
break;
}
}
return ret;
}
static int parse_and_provision_xml_file(const char* filename) {
int ret;
xmlTextReaderPtr xml = xmlReaderForFile(filename, NULL, 0);
if (!xml) {
fprintf(stderr, "failed to open %s\n", filename);
return -1;
}
ret = process_xml(xml);
xmlFreeTextReader(xml);
if (ret != 0) {
fprintf(stderr, "Failed to parse or process %s\n", filename);
return -1;
}
return 0;
}
int main(int argc, char** argv) {
int ret = 0;
parse_options(argc, argv);
if (optind + 1 != argc) {
print_usage_and_exit(argv[0], EXIT_FAILURE);
}
ret = trusty_keymaster_connect();
if (ret) {
fprintf(stderr, "trusty_keymaster_connect failed %d\n", ret);
return EXIT_FAILURE;
}
ret = parse_and_provision_xml_file(argv[optind]);
if (ret) {
fprintf(stderr, "parse_and_provision_xml_file failed %d\n", ret);
trusty_keymaster_disconnect();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}