1 /*
2  * Copyright 2022 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 <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <unistd.h>
20 #include <vm_payload_restricted.h>
21 
22 #include <string_view>
23 #include <vector>
24 
25 #include "compos_key.h"
26 
27 using android::base::Error;
28 using android::base::ReadFdToString;
29 using android::base::Result;
30 using android::base::WriteFully;
31 using namespace std::literals;
32 using compos_key::Ed25519KeyPair;
33 using compos_key::Seed;
34 
35 namespace {
36 
37 constexpr const char* kSigningKeySeedIdentifier = "CompOS signing key seed";
38 
getSigningKey()39 Result<Ed25519KeyPair> getSigningKey() {
40     Seed seed;
41     AVmPayload_getVmInstanceSecret(kSigningKeySeedIdentifier, strlen(kSigningKeySeedIdentifier),
42                                    seed.data(), seed.size());
43     return compos_key::keyFromSeed(seed);
44 }
45 
write_public_key()46 int write_public_key() {
47     auto key_pair = getSigningKey();
48     if (!key_pair.ok()) {
49         LOG(ERROR) << key_pair.error();
50         return 1;
51     }
52     if (!WriteFully(STDOUT_FILENO, key_pair->public_key.data(), key_pair->public_key.size())) {
53         PLOG(ERROR) << "Write failed";
54         return 1;
55     }
56     return 0;
57 }
58 
write_bcc()59 int write_bcc() {
60     size_t bcc_size = AVmPayload_getDiceAttestationChain(nullptr, 0);
61     std::vector<uint8_t> bcc(bcc_size);
62     AVmPayload_getDiceAttestationChain(bcc.data(), bcc.size());
63 
64     if (!WriteFully(STDOUT_FILENO, bcc.data(), bcc.size())) {
65         PLOG(ERROR) << "Write failed";
66         return 1;
67     }
68 
69     return 0;
70 }
71 
sign_input()72 int sign_input() {
73     std::string to_sign;
74     if (!ReadFdToString(STDIN_FILENO, &to_sign)) {
75         PLOG(ERROR) << "Read failed";
76         return 1;
77     }
78 
79     auto key_pair = getSigningKey();
80     if (!key_pair.ok()) {
81         LOG(ERROR) << key_pair.error();
82         return 1;
83     }
84 
85     auto signature =
86             compos_key::sign(key_pair->private_key,
87                              reinterpret_cast<const uint8_t*>(to_sign.data()), to_sign.size());
88     if (!signature.ok()) {
89         LOG(ERROR) << signature.error();
90         return 1;
91     }
92 
93     if (!WriteFully(STDOUT_FILENO, signature->data(), signature->size())) {
94         PLOG(ERROR) << "Write failed";
95         return 1;
96     }
97     return 0;
98 }
99 } // namespace
100 
main(int argc,char ** argv)101 int main(int argc, char** argv) {
102     android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
103 
104     if (argc == 2) {
105         if (argv[1] == "public_key"sv) {
106             return write_public_key();
107         } else if (argv[1] == "bcc"sv) {
108             return write_bcc();
109         } else if (argv[1] == "sign"sv) {
110             return sign_input();
111         }
112     }
113 
114     LOG(INFO) << "Usage: compos_key_helper <command>. Available commands are:\n"
115                  "public_key   Write current public key to stdout\n"
116                  "sign         Consume stdin, sign it and write signature to stdout\n";
117     return 1;
118 }
119