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