xref: /aosp_15_r20/system/security/ondevice-signing/CertUtils.cpp (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1*e1997b9aSAndroid Build Coastguard Worker /*
2*e1997b9aSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*e1997b9aSAndroid Build Coastguard Worker  *
4*e1997b9aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e1997b9aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e1997b9aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e1997b9aSAndroid Build Coastguard Worker  *
8*e1997b9aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e1997b9aSAndroid Build Coastguard Worker  *
10*e1997b9aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e1997b9aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e1997b9aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e1997b9aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e1997b9aSAndroid Build Coastguard Worker  * limitations under the License.
15*e1997b9aSAndroid Build Coastguard Worker  */
16*e1997b9aSAndroid Build Coastguard Worker 
17*e1997b9aSAndroid Build Coastguard Worker #include "CertUtils.h"
18*e1997b9aSAndroid Build Coastguard Worker 
19*e1997b9aSAndroid Build Coastguard Worker #include <android-base/logging.h>
20*e1997b9aSAndroid Build Coastguard Worker #include <android-base/result.h>
21*e1997b9aSAndroid Build Coastguard Worker 
22*e1997b9aSAndroid Build Coastguard Worker #include <openssl/bn.h>
23*e1997b9aSAndroid Build Coastguard Worker #include <openssl/crypto.h>
24*e1997b9aSAndroid Build Coastguard Worker #include <openssl/rsa.h>
25*e1997b9aSAndroid Build Coastguard Worker #include <openssl/x509.h>
26*e1997b9aSAndroid Build Coastguard Worker #include <openssl/x509v3.h>
27*e1997b9aSAndroid Build Coastguard Worker 
28*e1997b9aSAndroid Build Coastguard Worker #include <vector>
29*e1997b9aSAndroid Build Coastguard Worker 
30*e1997b9aSAndroid Build Coastguard Worker #include "KeyConstants.h"
31*e1997b9aSAndroid Build Coastguard Worker 
32*e1997b9aSAndroid Build Coastguard Worker // Common properties for all of our certificates.
33*e1997b9aSAndroid Build Coastguard Worker constexpr int kCertLifetimeSeconds = 10 * 365 * 24 * 60 * 60;
34*e1997b9aSAndroid Build Coastguard Worker const char* const kIssuerCountry = "US";
35*e1997b9aSAndroid Build Coastguard Worker const char* const kIssuerOrg = "Android";
36*e1997b9aSAndroid Build Coastguard Worker 
37*e1997b9aSAndroid Build Coastguard Worker using android::base::ErrnoError;
38*e1997b9aSAndroid Build Coastguard Worker using android::base::Error;
39*e1997b9aSAndroid Build Coastguard Worker using android::base::Result;
40*e1997b9aSAndroid Build Coastguard Worker 
loadX509(const std::string & path)41*e1997b9aSAndroid Build Coastguard Worker static Result<bssl::UniquePtr<X509>> loadX509(const std::string& path) {
42*e1997b9aSAndroid Build Coastguard Worker     X509* rawCert;
43*e1997b9aSAndroid Build Coastguard Worker     auto f = fopen(path.c_str(), "re");
44*e1997b9aSAndroid Build Coastguard Worker     if (f == nullptr) {
45*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to open " << path;
46*e1997b9aSAndroid Build Coastguard Worker     }
47*e1997b9aSAndroid Build Coastguard Worker     if (!d2i_X509_fp(f, &rawCert)) {
48*e1997b9aSAndroid Build Coastguard Worker         fclose(f);
49*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Unable to decode x509 cert at " << path;
50*e1997b9aSAndroid Build Coastguard Worker     }
51*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<X509> cert(rawCert);
52*e1997b9aSAndroid Build Coastguard Worker 
53*e1997b9aSAndroid Build Coastguard Worker     fclose(f);
54*e1997b9aSAndroid Build Coastguard Worker     return cert;
55*e1997b9aSAndroid Build Coastguard Worker }
56*e1997b9aSAndroid Build Coastguard Worker 
add_ext(X509V3_CTX * context,X509 * cert,int nid,const char * value)57*e1997b9aSAndroid Build Coastguard Worker static bool add_ext(X509V3_CTX* context, X509* cert, int nid, const char* value) {
58*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<X509_EXTENSION> ex(X509V3_EXT_nconf_nid(nullptr, context, nid, value));
59*e1997b9aSAndroid Build Coastguard Worker     if (!ex) {
60*e1997b9aSAndroid Build Coastguard Worker         return false;
61*e1997b9aSAndroid Build Coastguard Worker     }
62*e1997b9aSAndroid Build Coastguard Worker 
63*e1997b9aSAndroid Build Coastguard Worker     X509_add_ext(cert, ex.get(), -1);
64*e1997b9aSAndroid Build Coastguard Worker     return true;
65*e1997b9aSAndroid Build Coastguard Worker }
66*e1997b9aSAndroid Build Coastguard Worker 
addNameEntry(X509_NAME * name,const char * field,const char * value)67*e1997b9aSAndroid Build Coastguard Worker static void addNameEntry(X509_NAME* name, const char* field, const char* value) {
68*e1997b9aSAndroid Build Coastguard Worker     X509_NAME_add_entry_by_txt(name, field, MBSTRING_ASC,
69*e1997b9aSAndroid Build Coastguard Worker                                reinterpret_cast<const unsigned char*>(value), -1, -1, 0);
70*e1997b9aSAndroid Build Coastguard Worker }
71*e1997b9aSAndroid Build Coastguard Worker 
getRsaFromModulus(const std::vector<uint8_t> & publicKey)72*e1997b9aSAndroid Build Coastguard Worker static Result<bssl::UniquePtr<RSA>> getRsaFromModulus(const std::vector<uint8_t>& publicKey) {
73*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<BIGNUM> n(BN_new());
74*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<BIGNUM> e(BN_new());
75*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<RSA> rsaPubkey(RSA_new());
76*e1997b9aSAndroid Build Coastguard Worker     if (!n || !e || !rsaPubkey || !BN_bin2bn(publicKey.data(), publicKey.size(), n.get()) ||
77*e1997b9aSAndroid Build Coastguard Worker         !BN_set_word(e.get(), kRsaKeyExponent) ||
78*e1997b9aSAndroid Build Coastguard Worker         !RSA_set0_key(rsaPubkey.get(), n.get(), e.get(), /*d=*/nullptr)) {
79*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to create RSA key";
80*e1997b9aSAndroid Build Coastguard Worker     }
81*e1997b9aSAndroid Build Coastguard Worker     // RSA_set0_key takes ownership of |n| and |e| on success.
82*e1997b9aSAndroid Build Coastguard Worker     (void)n.release();
83*e1997b9aSAndroid Build Coastguard Worker     (void)e.release();
84*e1997b9aSAndroid Build Coastguard Worker 
85*e1997b9aSAndroid Build Coastguard Worker     return rsaPubkey;
86*e1997b9aSAndroid Build Coastguard Worker }
87*e1997b9aSAndroid Build Coastguard Worker 
modulusToRsaPkey(const std::vector<uint8_t> & publicKey)88*e1997b9aSAndroid Build Coastguard Worker static Result<bssl::UniquePtr<EVP_PKEY>> modulusToRsaPkey(const std::vector<uint8_t>& publicKey) {
89*e1997b9aSAndroid Build Coastguard Worker     // "publicKey" corresponds to the raw public key bytes - need to create
90*e1997b9aSAndroid Build Coastguard Worker     // a new RSA key with the correct exponent.
91*e1997b9aSAndroid Build Coastguard Worker     auto rsaPubkey = getRsaFromModulus(publicKey);
92*e1997b9aSAndroid Build Coastguard Worker     if (!rsaPubkey.ok()) {
93*e1997b9aSAndroid Build Coastguard Worker         return rsaPubkey.error();
94*e1997b9aSAndroid Build Coastguard Worker     }
95*e1997b9aSAndroid Build Coastguard Worker 
96*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<EVP_PKEY> public_key(EVP_PKEY_new());
97*e1997b9aSAndroid Build Coastguard Worker     if (!EVP_PKEY_assign_RSA(public_key.get(), rsaPubkey->release())) {
98*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to assign key";
99*e1997b9aSAndroid Build Coastguard Worker     }
100*e1997b9aSAndroid Build Coastguard Worker     return public_key;
101*e1997b9aSAndroid Build Coastguard Worker }
102*e1997b9aSAndroid Build Coastguard Worker 
verifySignature(const std::string & message,const std::string & signature,const std::vector<uint8_t> & publicKey)103*e1997b9aSAndroid Build Coastguard Worker Result<void> verifySignature(const std::string& message, const std::string& signature,
104*e1997b9aSAndroid Build Coastguard Worker                              const std::vector<uint8_t>& publicKey) {
105*e1997b9aSAndroid Build Coastguard Worker     auto rsaKey = getRsaFromModulus(publicKey);
106*e1997b9aSAndroid Build Coastguard Worker     if (!rsaKey.ok()) {
107*e1997b9aSAndroid Build Coastguard Worker         return rsaKey.error();
108*e1997b9aSAndroid Build Coastguard Worker     }
109*e1997b9aSAndroid Build Coastguard Worker     uint8_t hashBuf[SHA256_DIGEST_LENGTH];
110*e1997b9aSAndroid Build Coastguard Worker     SHA256(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(message.c_str())),
111*e1997b9aSAndroid Build Coastguard Worker            message.length(), hashBuf);
112*e1997b9aSAndroid Build Coastguard Worker 
113*e1997b9aSAndroid Build Coastguard Worker     bool success = RSA_verify(NID_sha256, hashBuf, sizeof(hashBuf),
114*e1997b9aSAndroid Build Coastguard Worker                               (const uint8_t*)signature.c_str(), signature.length(), rsaKey->get());
115*e1997b9aSAndroid Build Coastguard Worker 
116*e1997b9aSAndroid Build Coastguard Worker     if (!success) {
117*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to verify signature";
118*e1997b9aSAndroid Build Coastguard Worker     }
119*e1997b9aSAndroid Build Coastguard Worker     return {};
120*e1997b9aSAndroid Build Coastguard Worker }
121*e1997b9aSAndroid Build Coastguard Worker 
createSelfSignedCertificate(const std::vector<uint8_t> & publicKey,const std::function<Result<std::string> (const std::string &)> & signFunction,const std::string & path)122*e1997b9aSAndroid Build Coastguard Worker Result<void> createSelfSignedCertificate(
123*e1997b9aSAndroid Build Coastguard Worker     const std::vector<uint8_t>& publicKey,
124*e1997b9aSAndroid Build Coastguard Worker     const std::function<Result<std::string>(const std::string&)>& signFunction,
125*e1997b9aSAndroid Build Coastguard Worker     const std::string& path) {
126*e1997b9aSAndroid Build Coastguard Worker     auto rsa_pkey = modulusToRsaPkey(publicKey);
127*e1997b9aSAndroid Build Coastguard Worker     if (!rsa_pkey.ok()) {
128*e1997b9aSAndroid Build Coastguard Worker         return rsa_pkey.error();
129*e1997b9aSAndroid Build Coastguard Worker     }
130*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<X509> x509(X509_new());
131*e1997b9aSAndroid Build Coastguard Worker     if (!x509) {
132*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Unable to allocate x509 container";
133*e1997b9aSAndroid Build Coastguard Worker     }
134*e1997b9aSAndroid Build Coastguard Worker     X509_set_version(x509.get(), 2);
135*e1997b9aSAndroid Build Coastguard Worker     X509_gmtime_adj(X509_get_notBefore(x509.get()), 0);
136*e1997b9aSAndroid Build Coastguard Worker     X509_gmtime_adj(X509_get_notAfter(x509.get()), kCertLifetimeSeconds);
137*e1997b9aSAndroid Build Coastguard Worker     ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), kRootSubject.serialNumber);
138*e1997b9aSAndroid Build Coastguard Worker 
139*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<X509_ALGOR> algor(X509_ALGOR_new());
140*e1997b9aSAndroid Build Coastguard Worker     if (!algor ||
141*e1997b9aSAndroid Build Coastguard Worker         !X509_ALGOR_set0(algor.get(), OBJ_nid2obj(NID_sha256WithRSAEncryption), V_ASN1_NULL,
142*e1997b9aSAndroid Build Coastguard Worker                          NULL) ||
143*e1997b9aSAndroid Build Coastguard Worker         !X509_set1_signature_algo(x509.get(), algor.get())) {
144*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Unable to set x509 signature algorithm";
145*e1997b9aSAndroid Build Coastguard Worker     }
146*e1997b9aSAndroid Build Coastguard Worker 
147*e1997b9aSAndroid Build Coastguard Worker     if (!X509_set_pubkey(x509.get(), rsa_pkey.value().get())) {
148*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Unable to set x509 public key";
149*e1997b9aSAndroid Build Coastguard Worker     }
150*e1997b9aSAndroid Build Coastguard Worker 
151*e1997b9aSAndroid Build Coastguard Worker     X509_NAME* subjectName = X509_get_subject_name(x509.get());
152*e1997b9aSAndroid Build Coastguard Worker     if (!subjectName) {
153*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Unable to get x509 subject name";
154*e1997b9aSAndroid Build Coastguard Worker     }
155*e1997b9aSAndroid Build Coastguard Worker     addNameEntry(subjectName, "C", kIssuerCountry);
156*e1997b9aSAndroid Build Coastguard Worker     addNameEntry(subjectName, "O", kIssuerOrg);
157*e1997b9aSAndroid Build Coastguard Worker     addNameEntry(subjectName, "CN", kRootSubject.commonName);
158*e1997b9aSAndroid Build Coastguard Worker     if (!X509_set_issuer_name(x509.get(), subjectName)) {
159*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Unable to set x509 issuer name";
160*e1997b9aSAndroid Build Coastguard Worker     }
161*e1997b9aSAndroid Build Coastguard Worker 
162*e1997b9aSAndroid Build Coastguard Worker     X509V3_CTX context = {};
163*e1997b9aSAndroid Build Coastguard Worker     X509V3_set_ctx(&context, x509.get(), x509.get(), nullptr, nullptr, 0);
164*e1997b9aSAndroid Build Coastguard Worker     add_ext(&context, x509.get(), NID_basic_constraints, "CA:TRUE");
165*e1997b9aSAndroid Build Coastguard Worker     add_ext(&context, x509.get(), NID_key_usage, "critical,keyCertSign,cRLSign,digitalSignature");
166*e1997b9aSAndroid Build Coastguard Worker     add_ext(&context, x509.get(), NID_subject_key_identifier, "hash");
167*e1997b9aSAndroid Build Coastguard Worker     add_ext(&context, x509.get(), NID_authority_key_identifier, "keyid:always");
168*e1997b9aSAndroid Build Coastguard Worker 
169*e1997b9aSAndroid Build Coastguard Worker     // Get the data to be signed
170*e1997b9aSAndroid Build Coastguard Worker     unsigned char* to_be_signed_buf(nullptr);
171*e1997b9aSAndroid Build Coastguard Worker     size_t to_be_signed_length = i2d_re_X509_tbs(x509.get(), &to_be_signed_buf);
172*e1997b9aSAndroid Build Coastguard Worker 
173*e1997b9aSAndroid Build Coastguard Worker     auto signed_data = signFunction(
174*e1997b9aSAndroid Build Coastguard Worker         std::string(reinterpret_cast<const char*>(to_be_signed_buf), to_be_signed_length));
175*e1997b9aSAndroid Build Coastguard Worker     if (!signed_data.ok()) {
176*e1997b9aSAndroid Build Coastguard Worker         return signed_data.error();
177*e1997b9aSAndroid Build Coastguard Worker     }
178*e1997b9aSAndroid Build Coastguard Worker 
179*e1997b9aSAndroid Build Coastguard Worker     if (!X509_set1_signature_value(x509.get(),
180*e1997b9aSAndroid Build Coastguard Worker                                    reinterpret_cast<const uint8_t*>(signed_data->data()),
181*e1997b9aSAndroid Build Coastguard Worker                                    signed_data->size())) {
182*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Unable to set x509 signature";
183*e1997b9aSAndroid Build Coastguard Worker     }
184*e1997b9aSAndroid Build Coastguard Worker 
185*e1997b9aSAndroid Build Coastguard Worker     auto f = fopen(path.c_str(), "wbe");
186*e1997b9aSAndroid Build Coastguard Worker     if (f == nullptr) {
187*e1997b9aSAndroid Build Coastguard Worker         return ErrnoError() << "Failed to open " << path;
188*e1997b9aSAndroid Build Coastguard Worker     }
189*e1997b9aSAndroid Build Coastguard Worker     i2d_X509_fp(f, x509.get());
190*e1997b9aSAndroid Build Coastguard Worker     if (fclose(f) != 0) {
191*e1997b9aSAndroid Build Coastguard Worker         return ErrnoError() << "Failed to close " << path;
192*e1997b9aSAndroid Build Coastguard Worker     }
193*e1997b9aSAndroid Build Coastguard Worker 
194*e1997b9aSAndroid Build Coastguard Worker     return {};
195*e1997b9aSAndroid Build Coastguard Worker }
196*e1997b9aSAndroid Build Coastguard Worker 
extractPublicKey(EVP_PKEY * pkey)197*e1997b9aSAndroid Build Coastguard Worker static Result<std::vector<uint8_t>> extractPublicKey(EVP_PKEY* pkey) {
198*e1997b9aSAndroid Build Coastguard Worker     if (pkey == nullptr) {
199*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to extract public key from x509 cert";
200*e1997b9aSAndroid Build Coastguard Worker     }
201*e1997b9aSAndroid Build Coastguard Worker 
202*e1997b9aSAndroid Build Coastguard Worker     if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
203*e1997b9aSAndroid Build Coastguard Worker         return Error() << "The public key is not an RSA key";
204*e1997b9aSAndroid Build Coastguard Worker     }
205*e1997b9aSAndroid Build Coastguard Worker 
206*e1997b9aSAndroid Build Coastguard Worker     RSA* rsa = EVP_PKEY_get0_RSA(pkey);
207*e1997b9aSAndroid Build Coastguard Worker     auto num_bytes = BN_num_bytes(RSA_get0_n(rsa));
208*e1997b9aSAndroid Build Coastguard Worker     std::vector<uint8_t> pubKey(num_bytes);
209*e1997b9aSAndroid Build Coastguard Worker     int res = BN_bn2bin(RSA_get0_n(rsa), pubKey.data());
210*e1997b9aSAndroid Build Coastguard Worker 
211*e1997b9aSAndroid Build Coastguard Worker     if (!res) {
212*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to convert public key to bytes";
213*e1997b9aSAndroid Build Coastguard Worker     }
214*e1997b9aSAndroid Build Coastguard Worker 
215*e1997b9aSAndroid Build Coastguard Worker     return pubKey;
216*e1997b9aSAndroid Build Coastguard Worker }
217*e1997b9aSAndroid Build Coastguard Worker 
extractPublicKeyFromX509(const std::vector<uint8_t> & derCert)218*e1997b9aSAndroid Build Coastguard Worker Result<std::vector<uint8_t>> extractPublicKeyFromX509(const std::vector<uint8_t>& derCert) {
219*e1997b9aSAndroid Build Coastguard Worker     auto derCertBytes = derCert.data();
220*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<X509> decoded_cert(d2i_X509(nullptr, &derCertBytes, derCert.size()));
221*e1997b9aSAndroid Build Coastguard Worker     if (decoded_cert.get() == nullptr) {
222*e1997b9aSAndroid Build Coastguard Worker         return Error() << "Failed to decode X509 certificate.";
223*e1997b9aSAndroid Build Coastguard Worker     }
224*e1997b9aSAndroid Build Coastguard Worker     bssl::UniquePtr<EVP_PKEY> decoded_pkey(X509_get_pubkey(decoded_cert.get()));
225*e1997b9aSAndroid Build Coastguard Worker 
226*e1997b9aSAndroid Build Coastguard Worker     return extractPublicKey(decoded_pkey.get());
227*e1997b9aSAndroid Build Coastguard Worker }
228*e1997b9aSAndroid Build Coastguard Worker 
extractPublicKeyFromX509(const std::string & path)229*e1997b9aSAndroid Build Coastguard Worker Result<std::vector<uint8_t>> extractPublicKeyFromX509(const std::string& path) {
230*e1997b9aSAndroid Build Coastguard Worker     auto cert = loadX509(path);
231*e1997b9aSAndroid Build Coastguard Worker     if (!cert.ok()) {
232*e1997b9aSAndroid Build Coastguard Worker         return cert.error();
233*e1997b9aSAndroid Build Coastguard Worker     }
234*e1997b9aSAndroid Build Coastguard Worker     return extractPublicKey(X509_get_pubkey(cert.value().get()));
235*e1997b9aSAndroid Build Coastguard Worker }
236