Skip to content

Commit 12d43a8

Browse files
authored
Merge pull request #18 from flatcar/wrl/openssl-3.0
upgrade OpenSSL API to version 3
2 parents 5721cad + ca71b53 commit 12d43a8

11 files changed

+58
-108
lines changed

.github/workflows/c-cpp.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ on:
99
jobs:
1010
build:
1111

12-
runs-on: ubuntu-latest
12+
runs-on: ubuntu-22.04
1313

1414
steps:
1515
- uses: actions/checkout@v2
1616
- name: install deps
1717
run: |
18-
sudo apt update && sudo apt install -y libblkid-dev libext2fs-dev libmount-dev curl unzip libdbus-glib-1-dev protobuf-compiler libbz2-dev libgflags-dev libssl-dev libgoogle-glog-dev libcurl4-openssl-dev libxml2-dev libprotobuf-dev cmake wget libtool autoconf libgtest-dev libgmock-dev libbrotli-dev libdivsufsort-dev
18+
sudo apt update && sudo apt install -y libunwind-dev && sudo apt install -y libblkid-dev libext2fs-dev libmount-dev curl unzip libdbus-glib-1-dev protobuf-compiler libbz2-dev libgflags-dev libssl-dev libgoogle-glog-dev libcurl4-openssl-dev libxml2-dev libprotobuf-dev cmake wget libtool autoconf libgtest-dev libgmock-dev libbrotli-dev libdivsufsort-dev libsodium-dev
1919
- name: prep rootdev
2020
run: |
2121
curl -sSL -o /tmp/seismograph.zip https://github.com/kinvolk/seismograph/archive/flatcar-master.zip

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ PKG_CHECK_MODULES([DEPS],
8181
libcrypto
8282
libcurl
8383
libglog
84+
libsodium
8485
libssl
8586
libxml-2.0
8687
protobuf])

src/update_engine/main.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <gflags/gflags.h>
66
#include <glib.h>
77
#include <glog/logging.h>
8+
#include <sodium.h>
89

910
#include "update_engine/certificate_checker.h"
1011
#include "update_engine/dbus_constants.h"
@@ -74,6 +75,8 @@ void SetupDbusService(UpdateEngineService* service) {
7475
} // namespace chromeos_update_engine
7576

7677
int main(int argc, char** argv) {
78+
PLOG_IF(FATAL, sodium_init() < 0 ) << "the cryptographic lib couldn't be initialized; it is not safe to use";
79+
7780
// Disable glog's default behavior of logging to files.
7881
FLAGS_logtostderr = true;
7982
GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);

src/update_engine/omaha_hash_calculator.cc

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,20 @@ class ScopedBioHandle {
5252
};
5353

5454
OmahaHashCalculator::OmahaHashCalculator() : valid_(false) {
55-
valid_ = (SHA256_Init(&ctx_) == 1);
56-
LOG_IF(ERROR, !valid_) << "SHA256_Init failed";
55+
valid_ = !crypto_hash_sha256_init(&hash_state_);
56+
LOG_IF(ERROR, !valid_) << "crypto_hash_sha256_init() failed";
5757
}
5858

5959
// Update is called with all of the data that should be hashed in order.
6060
// Mostly just passes the data through to OpenSSL's SHA256_Update()
6161
bool OmahaHashCalculator::Update(const char* data, size_t length) {
6262
TEST_AND_RETURN_FALSE(valid_);
6363
TEST_AND_RETURN_FALSE(hash_.empty());
64-
static_assert(sizeof(size_t) <= sizeof(unsigned long),
65-
"length param may be truncated in SHA256_Update");
66-
TEST_AND_RETURN_FALSE(SHA256_Update(&ctx_, data, length) == 1);
64+
static_assert(sizeof(size_t) <= sizeof(unsigned long long),
65+
"length param may be truncated in crypto_hash_sha256_update");
66+
67+
TEST_AND_RETURN_FALSE(crypto_hash_sha256_update(&hash_state_,
68+
reinterpret_cast<const unsigned char *>(data), length) == 0);
6769
return true;
6870
}
6971

@@ -170,13 +172,14 @@ bool OmahaHashCalculator::Base64Decode(const string& raw_in,
170172
bool OmahaHashCalculator::Finalize() {
171173
TEST_AND_RETURN_FALSE(hash_.empty());
172174
TEST_AND_RETURN_FALSE(raw_hash_.empty());
173-
raw_hash_.resize(SHA256_DIGEST_LENGTH);
175+
raw_hash_.resize(crypto_hash_sha256_BYTES);
176+
174177
TEST_AND_RETURN_FALSE(
175-
SHA256_Final(reinterpret_cast<unsigned char*>(&raw_hash_[0]),
176-
&ctx_) == 1);
178+
crypto_hash_sha256_final(&hash_state_,
179+
reinterpret_cast<unsigned char*>(raw_hash_.data())) == 0);
177180

178181
// Convert raw_hash_ to base64 encoding and store it in hash_.
179-
return Base64Encode(&raw_hash_[0], raw_hash_.size(), &hash_);
182+
return Base64Encode(raw_hash_.data(), raw_hash_.size(), &hash_);
180183
}
181184

182185
bool OmahaHashCalculator::RawHashOfBytes(const char* data,
@@ -221,16 +224,16 @@ string OmahaHashCalculator::OmahaHashOfString(const string& str) {
221224
}
222225

223226
string OmahaHashCalculator::OmahaHashOfData(const vector<char>& data) {
224-
return OmahaHashOfBytes(&data[0], data.size());
227+
return OmahaHashOfBytes(data.data(), data.size());
225228
}
226229

227230
string OmahaHashCalculator::GetContext() const {
228-
return string(reinterpret_cast<const char*>(&ctx_), sizeof(ctx_));
231+
return string(reinterpret_cast<const char*>(&hash_state_), sizeof(hash_state_));
229232
}
230233

231234
bool OmahaHashCalculator::SetContext(const std::string& context) {
232-
TEST_AND_RETURN_FALSE(context.size() == sizeof(ctx_));
233-
memcpy(&ctx_, context.data(), sizeof(ctx_));
235+
TEST_AND_RETURN_FALSE(context.size() == sizeof(hash_state_));
236+
memcpy(&hash_state_, context.data(), sizeof(hash_state_));
234237
return true;
235238
}
236239

src/update_engine/omaha_hash_calculator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <vector>
1111

1212
#include <glog/logging.h>
13-
#include <openssl/sha.h>
13+
#include <sodium.h>
1414

1515
#include "macros.h"
1616

@@ -94,7 +94,7 @@ class OmahaHashCalculator {
9494
bool valid_;
9595

9696
// The hash state used by OpenSSL
97-
SHA256_CTX ctx_;
97+
struct crypto_hash_sha256_state hash_state_;
9898
DISALLOW_COPY_AND_ASSIGN(OmahaHashCalculator);
9999
};
100100

src/update_engine/payload_processor.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,6 @@ ActionExitCode PayloadProcessor::VerifyPayload() {
361361
TEST_AND_RETURN_VAL(kActionCodeDownloadPayloadPubKeyVerificationError,
362362
signed_hasher.Finalize());
363363
vector<char> hash_data = signed_hasher.raw_hash();
364-
PayloadSigner::PadRSA2048SHA256Hash(&hash_data);
365364
TEST_AND_RETURN_VAL(kActionCodeDownloadPayloadPubKeyVerificationError,
366365
!hash_data.empty());
367366
if (hash_data != signed_hash_data) {

src/update_engine/payload_processor_unittest.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,15 +204,14 @@ static void SignGeneratedShellPayload(SignatureTest signature_test,
204204
// Pad the hash
205205
vector<char> hash;
206206
ASSERT_TRUE(utils::ReadFile(hash_file, &hash));
207-
ASSERT_TRUE(PayloadSigner::PadRSA2048SHA256Hash(&hash));
208207
ASSERT_TRUE(WriteFileVector(hash_file, hash));
209208

210209
string sig_file;
211210
ASSERT_TRUE(utils::MakeTempFile("/tmp/signature.XXXXXX", &sig_file, NULL));
212211
ScopedPathUnlinker sig_unlinker(sig_file);
213212
ASSERT_EQ(0,
214213
System(StringPrintf(
215-
"openssl rsautl -raw -sign -inkey %s -in %s -out %s",
214+
"openssl pkeyutl -sign -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pkcs1 -inkey %s -in %s -out %s",
216215
private_key_path.c_str(),
217216
hash_file.c_str(),
218217
sig_file.c_str())));
@@ -223,7 +222,7 @@ static void SignGeneratedShellPayload(SignatureTest signature_test,
223222
signature_test == kSignatureGeneratedShellRotateCl2) {
224223
ASSERT_EQ(0,
225224
System(StringPrintf(
226-
"openssl rsautl -raw -sign -inkey %s -in %s -out %s",
225+
"openssl pkeyutl -sign -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pkcs1 -inkey %s -in %s -out %s",
227226
kUnittestPrivateKey2Path,
228227
hash_file.c_str(),
229228
sig_file2.c_str())));

src/update_engine/payload_signer.cc

Lines changed: 31 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <glog/logging.h>
88
#include <openssl/pem.h>
9+
#include <openssl/evp.h>
910

1011
#include "update_engine/delta_diff_generator.h"
1112
#include "update_engine/delta_metadata.h"
@@ -23,59 +24,6 @@ const uint32_t kSignatureMessageCurrentVersion = 2;
2324

2425
namespace {
2526

26-
// The following is a standard PKCS1-v1_5 padding for SHA256 signatures, as
27-
// defined in RFC3447. It is prepended to the actual signature (32 bytes) to
28-
// form a sequence of 256 bytes (2048 bits) that is amenable to RSA signing. The
29-
// padded hash will look as follows:
30-
//
31-
// 0x00 0x01 0xff ... 0xff 0x00 ASN1HEADER SHA256HASH
32-
// |--------------205-----------||----19----||----32----|
33-
//
34-
// where ASN1HEADER is the ASN.1 description of the signed data. The complete 51
35-
// bytes of actual data (i.e. the ASN.1 header complete with the hash) are
36-
// packed as follows:
37-
//
38-
// SEQUENCE(2+49) {
39-
// SEQUENCE(2+13) {
40-
// OBJECT(2+9) id-sha256
41-
// NULL(2+0)
42-
// }
43-
// OCTET STRING(2+32) <actual signature bytes...>
44-
// }
45-
const unsigned char kRSA2048SHA256Padding[] = {
46-
// PKCS1-v1_5 padding
47-
0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
48-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
49-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
50-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
61-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
62-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
63-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
64-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
68-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
69-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
70-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
71-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
72-
0xff, 0xff, 0xff, 0xff, 0x00,
73-
// ASN.1 header
74-
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
75-
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
76-
0x00, 0x04, 0x20,
77-
};
78-
7927
// Given raw |signatures|, packs them into a protobuf and serializes it into a
8028
// binary blob. Returns true on success, false otherwise.
8129
bool ConvertSignatureToProtobufBlob(const vector<vector<char> >& signatures,
@@ -178,14 +126,13 @@ bool PayloadSigner::SignHash(const vector<char>& hash,
178126
// We expect unpadded SHA256 hash coming in
179127
TEST_AND_RETURN_FALSE(hash.size() == 32);
180128
vector<char> padded_hash(hash);
181-
PadRSA2048SHA256Hash(&padded_hash);
182129
TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
183130
padded_hash.data(),
184131
padded_hash.size()));
185132

186133
// This runs on the server, so it's okay to cop out and call openssl
187134
// executable rather than properly use the library
188-
vector<string> cmd = {"openssl", "rsautl", "-raw", "-sign",
135+
vector<string> cmd = {"openssl", "pkeyutl", "-sign", "-pkeyopt", "digest:sha256", "-pkeyopt", "rsa_padding_mode:pkcs1",
189136
"-inkey", private_key_path,
190137
"-in", hash_path,
191138
"-out", sig_path};
@@ -292,27 +239,44 @@ bool PayloadSigner::GetRawHashFromSignature(
292239
}
293240

294241
char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
295-
RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
242+
EVP_PKEY* pkey = PEM_read_PUBKEY(fpubkey, NULL, NULL, dummy_password);
296243
fclose(fpubkey);
297-
TEST_AND_RETURN_FALSE(rsa != NULL);
298-
unsigned int keysize = RSA_size(rsa);
244+
TEST_AND_RETURN_FALSE(pkey != NULL);
245+
size_t keysize = EVP_PKEY_get_size(pkey);
299246
if (sig_data.size() > 2 * keysize) {
300247
LOG(ERROR) << "Signature size is too big for public key size.";
301-
RSA_free(rsa);
248+
EVP_PKEY_free(pkey);
302249
return false;
303250
}
304251

305-
// Decrypts the signature.
306252
vector<char> hash_data(keysize);
307-
int decrypt_size = RSA_public_decrypt(
308-
sig_data.size(),
309-
reinterpret_cast<const unsigned char*>(sig_data.data()),
253+
254+
// Decrypts the signature.
255+
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
256+
if (!ctx
257+
|| EVP_PKEY_verify_recover_init(ctx) <= 0
258+
|| EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0
259+
|| EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {
260+
LOG(ERROR) << "Couldn't initialise EVP_PKEY_CTX";
261+
EVP_PKEY_free(pkey);
262+
return false;
263+
}
264+
265+
size_t decrypt_size = keysize;
266+
267+
if (EVP_PKEY_verify_recover(ctx,
310268
reinterpret_cast<unsigned char*>(hash_data.data()),
311-
rsa,
312-
RSA_NO_PADDING);
313-
RSA_free(rsa);
269+
&decrypt_size,
270+
reinterpret_cast<const unsigned char*>(sig_data.data()),
271+
sig_data.size()) <= 0 ) {
272+
decrypt_size = 0;
273+
}
274+
275+
EVP_PKEY_CTX_free(ctx);
276+
EVP_PKEY_free(pkey);
277+
314278
TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
315-
decrypt_size <= static_cast<int>(hash_data.size()));
279+
(ssize_t) decrypt_size <= static_cast<int>(hash_data.size()));
316280
hash_data.resize(decrypt_size);
317281
out_hash_data->swap(hash_data);
318282
return true;
@@ -341,7 +305,6 @@ bool PayloadSigner::VerifySignedPayload(const std::string& payload_path,
341305
vector<char> hash;
342306
TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
343307
payload.data(), metadata_size + manifest.signatures_offset(), &hash));
344-
PadRSA2048SHA256Hash(&hash);
345308
TEST_AND_RETURN_FALSE(hash == signed_hash);
346309
return true;
347310
}
@@ -414,14 +377,4 @@ bool PayloadSigner::AddSignatureToPayload(
414377
return true;
415378
}
416379

417-
bool PayloadSigner::PadRSA2048SHA256Hash(std::vector<char>* hash) {
418-
TEST_AND_RETURN_FALSE(hash->size() == 32);
419-
hash->insert(hash->begin(),
420-
reinterpret_cast<const char*>(kRSA2048SHA256Padding),
421-
reinterpret_cast<const char*>(kRSA2048SHA256Padding +
422-
sizeof(kRSA2048SHA256Padding)));
423-
TEST_AND_RETURN_FALSE(hash->size() == 256);
424-
return true;
425-
}
426-
427380
} // namespace chromeos_update_engine

src/update_engine/payload_signer.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,6 @@ class PayloadSigner {
113113
const std::string& public_key_path,
114114
uint32_t client_key_check_version);
115115

116-
// Pads a SHA256 hash so that it may be encrypted/signed with RSA2048
117-
// using the PKCS#1 v1.5 scheme.
118-
// hash should be a pointer to vector of exactly 256 bits. The vector
119-
// will be modified in place and will result in having a length of
120-
// 2048 bits. Returns true on success, false otherwise.
121-
static bool PadRSA2048SHA256Hash(std::vector<char>* hash);
122-
123116
// Reads the payload from the given |payload_path| into the |out_payload|
124117
// vector. It also parses the manifest protobuf in the payload and returns it
125118
// in |out_manifest| along with the size of the entire metadata in

src/update_engine/payload_signer_unittest.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ TEST(PayloadSignerTest, VerifySignatureTest) {
130130
vector<char> padded_hash_data(reinterpret_cast<const char *>(kDataHash),
131131
reinterpret_cast<const char *>(kDataHash +
132132
sizeof(kDataHash)));
133-
PayloadSigner::PadRSA2048SHA256Hash(&padded_hash_data);
134133
ASSERT_EQ(padded_hash_data.size(), hash_data.size());
135134
for (size_t i = 0; i < padded_hash_data.size(); i++) {
136135
EXPECT_EQ(padded_hash_data[i], hash_data[i]);

0 commit comments

Comments
 (0)