blob: bb2da5a193966f996581a49f4b1e1fb0ccaf31a6 [file] [log] [blame]
Martijn Coenen95194842020-09-24 16:56:46 +02001/*
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
Alan Stokesb1821782021-06-07 14:57:15 +010017#include "CertUtils.h"
18
Martijn Coenen95194842020-09-24 16:56:46 +020019#include <android-base/logging.h>
20#include <android-base/result.h>
21
22#include <openssl/bn.h>
23#include <openssl/crypto.h>
Martijn Coenen95194842020-09-24 16:56:46 +020024#include <openssl/rsa.h>
David Benjamin891b9542021-05-06 13:36:46 -040025#include <openssl/x509.h>
Martijn Coenen95194842020-09-24 16:56:46 +020026#include <openssl/x509v3.h>
27
Martijn Coenen95194842020-09-24 16:56:46 +020028#include <vector>
Martijn Coenenba1c9dc2021-02-04 13:18:29 +010029
30#include "KeyConstants.h"
31
Alan Stokes35049b62021-06-25 12:16:13 +010032// Common properties for all of our certificates.
Martijn Coenen95194842020-09-24 16:56:46 +020033constexpr int kCertLifetimeSeconds = 10 * 365 * 24 * 60 * 60;
Alan Stokes35049b62021-06-25 12:16:13 +010034const char* const kIssuerCountry = "US";
35const char* const kIssuerOrg = "Android";
Martijn Coenen95194842020-09-24 16:56:46 +020036
Alan Stokesbfd2ec02021-06-09 18:00:54 +010037using android::base::ErrnoError;
Martijn Coenen95194842020-09-24 16:56:46 +020038using android::base::Error;
Alan Stokesbfd2ec02021-06-09 18:00:54 +010039using android::base::Result;
Martijn Coenen95194842020-09-24 16:56:46 +020040
Alan Stokesbfd2ec02021-06-09 18:00:54 +010041static Result<bssl::UniquePtr<X509>> loadX509(const std::string& path) {
42 X509* rawCert;
43 auto f = fopen(path.c_str(), "re");
44 if (f == nullptr) {
45 return Error() << "Failed to open " << path;
46 }
47 if (!d2i_X509_fp(f, &rawCert)) {
48 fclose(f);
49 return Error() << "Unable to decode x509 cert at " << path;
50 }
51 bssl::UniquePtr<X509> cert(rawCert);
Martijn Coenen95194842020-09-24 16:56:46 +020052
Alan Stokesbfd2ec02021-06-09 18:00:54 +010053 fclose(f);
54 return cert;
55}
Martijn Coenen95194842020-09-24 16:56:46 +020056
Alan Stokesbfd2ec02021-06-09 18:00:54 +010057static bool add_ext(X509V3_CTX* context, X509* cert, int nid, const char* value) {
58 bssl::UniquePtr<X509_EXTENSION> ex(X509V3_EXT_nconf_nid(nullptr, context, nid, value));
Martijn Coenen95194842020-09-24 16:56:46 +020059 if (!ex) {
60 return false;
61 }
62
Alan Stokesbfd2ec02021-06-09 18:00:54 +010063 X509_add_ext(cert, ex.get(), -1);
Martijn Coenen95194842020-09-24 16:56:46 +020064 return true;
65}
66
Alan Stokesbfd2ec02021-06-09 18:00:54 +010067static void addNameEntry(X509_NAME* name, const char* field, const char* value) {
68 X509_NAME_add_entry_by_txt(name, field, MBSTRING_ASC,
69 reinterpret_cast<const unsigned char*>(value), -1, -1, 0);
70}
71
Alan Stokes8b4cb962021-07-06 17:45:39 +010072static Result<bssl::UniquePtr<RSA>> getRsaFromModulus(const std::vector<uint8_t>& publicKey) {
David Benjamin891b9542021-05-06 13:36:46 -040073 bssl::UniquePtr<BIGNUM> n(BN_new());
74 bssl::UniquePtr<BIGNUM> e(BN_new());
Martijn Coenendc05bb32021-03-08 10:52:48 +010075 bssl::UniquePtr<RSA> rsaPubkey(RSA_new());
David Benjamin891b9542021-05-06 13:36:46 -040076 if (!n || !e || !rsaPubkey || !BN_bin2bn(publicKey.data(), publicKey.size(), n.get()) ||
77 !BN_set_word(e.get(), kRsaKeyExponent) ||
78 !RSA_set0_key(rsaPubkey.get(), n.get(), e.get(), /*d=*/nullptr)) {
79 return Error() << "Failed to create RSA key";
80 }
81 // RSA_set0_key takes ownership of |n| and |e| on success.
82 (void)n.release();
83 (void)e.release();
Martijn Coenendc05bb32021-03-08 10:52:48 +010084
85 return rsaPubkey;
86}
87
Alan Stokes8b4cb962021-07-06 17:45:39 +010088static Result<bssl::UniquePtr<EVP_PKEY>> modulusToRsaPkey(const std::vector<uint8_t>& publicKey) {
89 // "publicKey" corresponds to the raw public key bytes - need to create
90 // a new RSA key with the correct exponent.
91 auto rsaPubkey = getRsaFromModulus(publicKey);
92 if (!rsaPubkey.ok()) {
93 return rsaPubkey.error();
94 }
95
96 bssl::UniquePtr<EVP_PKEY> public_key(EVP_PKEY_new());
97 if (!EVP_PKEY_assign_RSA(public_key.get(), rsaPubkey->release())) {
98 return Error() << "Failed to assign key";
99 }
100 return public_key;
101}
102
Martijn Coenendc05bb32021-03-08 10:52:48 +0100103Result<void> verifySignature(const std::string& message, const std::string& signature,
104 const std::vector<uint8_t>& publicKey) {
Alan Stokes8b4cb962021-07-06 17:45:39 +0100105 auto rsaKey = getRsaFromModulus(publicKey);
David Benjamin891b9542021-05-06 13:36:46 -0400106 if (!rsaKey.ok()) {
107 return rsaKey.error();
108 }
Martijn Coenendc05bb32021-03-08 10:52:48 +0100109 uint8_t hashBuf[SHA256_DIGEST_LENGTH];
110 SHA256(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(message.c_str())),
111 message.length(), hashBuf);
112
113 bool success = RSA_verify(NID_sha256, hashBuf, sizeof(hashBuf),
114 (const uint8_t*)signature.c_str(), signature.length(), rsaKey->get());
115
116 if (!success) {
Alan Stokes35049b62021-06-25 12:16:13 +0100117 return Error() << "Failed to verify signature";
Martijn Coenendc05bb32021-03-08 10:52:48 +0100118 }
119 return {};
120}
121
Eric Biggers1ee88c72023-07-05 22:13:52 +0000122Result<void> createSelfSignedCertificate(
123 const std::vector<uint8_t>& publicKey,
124 const std::function<Result<std::string>(const std::string&)>& signFunction,
125 const std::string& path) {
126 auto rsa_pkey = modulusToRsaPkey(publicKey);
127 if (!rsa_pkey.ok()) {
128 return rsa_pkey.error();
129 }
Martijn Coenen95194842020-09-24 16:56:46 +0200130 bssl::UniquePtr<X509> x509(X509_new());
131 if (!x509) {
132 return Error() << "Unable to allocate x509 container";
133 }
134 X509_set_version(x509.get(), 2);
Martijn Coenen95194842020-09-24 16:56:46 +0200135 X509_gmtime_adj(X509_get_notBefore(x509.get()), 0);
136 X509_gmtime_adj(X509_get_notAfter(x509.get()), kCertLifetimeSeconds);
Eric Biggers1ee88c72023-07-05 22:13:52 +0000137 ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), kRootSubject.serialNumber);
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100138
139 bssl::UniquePtr<X509_ALGOR> algor(X509_ALGOR_new());
140 if (!algor ||
141 !X509_ALGOR_set0(algor.get(), OBJ_nid2obj(NID_sha256WithRSAEncryption), V_ASN1_NULL,
142 NULL) ||
143 !X509_set1_signature_algo(x509.get(), algor.get())) {
144 return Error() << "Unable to set x509 signature algorithm";
145 }
Martijn Coenen95194842020-09-24 16:56:46 +0200146
Eric Biggers1ee88c72023-07-05 22:13:52 +0000147 if (!X509_set_pubkey(x509.get(), rsa_pkey.value().get())) {
Martijn Coenen95194842020-09-24 16:56:46 +0200148 return Error() << "Unable to set x509 public key";
149 }
150
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100151 X509_NAME* subjectName = X509_get_subject_name(x509.get());
152 if (!subjectName) {
Martijn Coenen95194842020-09-24 16:56:46 +0200153 return Error() << "Unable to get x509 subject name";
154 }
Alan Stokes35049b62021-06-25 12:16:13 +0100155 addNameEntry(subjectName, "C", kIssuerCountry);
156 addNameEntry(subjectName, "O", kIssuerOrg);
Eric Biggers1ee88c72023-07-05 22:13:52 +0000157 addNameEntry(subjectName, "CN", kRootSubject.commonName);
158 if (!X509_set_issuer_name(x509.get(), subjectName)) {
159 return Error() << "Unable to set x509 issuer name";
Martijn Coenen95194842020-09-24 16:56:46 +0200160 }
161
Eric Biggers1ee88c72023-07-05 22:13:52 +0000162 X509V3_CTX context = {};
163 X509V3_set_ctx(&context, x509.get(), x509.get(), nullptr, nullptr, 0);
164 add_ext(&context, x509.get(), NID_basic_constraints, "CA:TRUE");
165 add_ext(&context, x509.get(), NID_key_usage, "critical,keyCertSign,cRLSign,digitalSignature");
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100166 add_ext(&context, x509.get(), NID_subject_key_identifier, "hash");
167 add_ext(&context, x509.get(), NID_authority_key_identifier, "keyid:always");
168
Martijn Coenen95194842020-09-24 16:56:46 +0200169 // Get the data to be signed
David Benjamin891b9542021-05-06 13:36:46 -0400170 unsigned char* to_be_signed_buf(nullptr);
171 size_t to_be_signed_length = i2d_re_X509_tbs(x509.get(), &to_be_signed_buf);
Martijn Coenen95194842020-09-24 16:56:46 +0200172
David Benjamin891b9542021-05-06 13:36:46 -0400173 auto signed_data = signFunction(
174 std::string(reinterpret_cast<const char*>(to_be_signed_buf), to_be_signed_length));
Martijn Coenen95194842020-09-24 16:56:46 +0200175 if (!signed_data.ok()) {
176 return signed_data.error();
177 }
178
David Benjamin891b9542021-05-06 13:36:46 -0400179 if (!X509_set1_signature_value(x509.get(),
180 reinterpret_cast<const uint8_t*>(signed_data->data()),
181 signed_data->size())) {
182 return Error() << "Unable to set x509 signature";
183 }
Martijn Coenen95194842020-09-24 16:56:46 +0200184
Martijn Coenenc101b132021-03-18 11:23:55 +0100185 auto f = fopen(path.c_str(), "wbe");
186 if (f == nullptr) {
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100187 return ErrnoError() << "Failed to open " << path;
Martijn Coenenc101b132021-03-18 11:23:55 +0100188 }
Martijn Coenen95194842020-09-24 16:56:46 +0200189 i2d_X509_fp(f, x509.get());
Alan Stokesbfd2ec02021-06-09 18:00:54 +0100190 if (fclose(f) != 0) {
191 return ErrnoError() << "Failed to close " << path;
192 }
Martijn Coenen95194842020-09-24 16:56:46 +0200193
194 return {};
195}
196
Eric Biggers17d4ec32023-07-05 17:53:00 +0000197static Result<std::vector<uint8_t>> extractPublicKey(EVP_PKEY* pkey) {
Martijn Coenen95194842020-09-24 16:56:46 +0200198 if (pkey == nullptr) {
199 return Error() << "Failed to extract public key from x509 cert";
200 }
201
David Benjamin891b9542021-05-06 13:36:46 -0400202 if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
Martijn Coenen95194842020-09-24 16:56:46 +0200203 return Error() << "The public key is not an RSA key";
204 }
205
David Benjamin891b9542021-05-06 13:36:46 -0400206 RSA* rsa = EVP_PKEY_get0_RSA(pkey);
207 auto num_bytes = BN_num_bytes(RSA_get0_n(rsa));
Martijn Coenen95194842020-09-24 16:56:46 +0200208 std::vector<uint8_t> pubKey(num_bytes);
David Benjamin891b9542021-05-06 13:36:46 -0400209 int res = BN_bn2bin(RSA_get0_n(rsa), pubKey.data());
Martijn Coenen95194842020-09-24 16:56:46 +0200210
211 if (!res) {
212 return Error() << "Failed to convert public key to bytes";
213 }
214
215 return pubKey;
216}
217
Alan Stokesb1821782021-06-07 14:57:15 +0100218Result<std::vector<uint8_t>> extractPublicKeyFromX509(const std::vector<uint8_t>& derCert) {
219 auto derCertBytes = derCert.data();
220 bssl::UniquePtr<X509> decoded_cert(d2i_X509(nullptr, &derCertBytes, derCert.size()));
Martijn Coenenba1c9dc2021-02-04 13:18:29 +0100221 if (decoded_cert.get() == nullptr) {
222 return Error() << "Failed to decode X509 certificate.";
223 }
224 bssl::UniquePtr<EVP_PKEY> decoded_pkey(X509_get_pubkey(decoded_cert.get()));
225
226 return extractPublicKey(decoded_pkey.get());
227}
228
Alan Stokesb1821782021-06-07 14:57:15 +0100229Result<std::vector<uint8_t>> extractPublicKeyFromX509(const std::string& path) {
230 auto cert = loadX509(path);
231 if (!cert.ok()) {
232 return cert.error();
233 }
234 return extractPublicKey(X509_get_pubkey(cert.value().get()));
235}