blob: 81280fde2c98472edc77fdf31ddc449b1fced306 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "compos_native.h"
#include <openssl/bn.h>
#include <openssl/mem.h>
#include <openssl/nid.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <algorithm>
#include <iterator>
#include <vector>
namespace {
KeyResult make_key_error(const char* message) {
return KeyResult{{}, {}, message};
}
SignResult make_sign_error(const char* message) {
return SignResult{{}, message};
}
} // namespace
constexpr int KEY_BITS = 2048;
KeyResult generate_key_pair() {
bssl::UniquePtr<RSA> key_pair(RSA_new());
// This function specifies that the public exponent is always 65537, which is good because
// that's what odsign is expecting.
if (!RSA_generate_key_fips(key_pair.get(), KEY_BITS, /*callback=*/nullptr)) {
return make_key_error("Failed to generate key pair");
}
KeyResult result;
uint8_t* out;
int size;
bssl::UniquePtr<uint8_t> out_owner;
// Extract public key as DER.
out = nullptr;
size = i2d_RSAPublicKey(key_pair.get(), &out);
if (size < 0 || !out) {
return make_key_error("Failed to get RSAPublicKey");
}
out_owner.reset(out);
result.public_key.reserve(size);
std::copy(out, out + size, std::back_inserter(result.public_key));
out_owner.reset();
// And ditto for the private key (which actually includes the public bits).
out = nullptr;
size = i2d_RSAPrivateKey(key_pair.get(), &out);
if (size < 0 || !out) {
return make_key_error("Failed to get RSAPrivateKey");
}
out_owner.reset(out);
result.private_key.reserve(size);
std::copy(out, out + size, std::back_inserter(result.private_key));
out_owner.reset();
return result;
}
SignResult sign(rust::Slice<const uint8_t> private_key, rust::Slice<const uint8_t> data) {
uint8_t digest[SHA256_DIGEST_LENGTH];
SHA256(data.data(), data.size(), digest);
const uint8_t* key_in = private_key.data();
bssl::UniquePtr<RSA> key(d2i_RSAPrivateKey(nullptr, &key_in, private_key.size()));
if (!key) {
return make_sign_error("Failed to load RSAPrivateKey");
}
// rust::Vec doesn't support resize, so we need our own buffer.
// The signature is always less than the modulus (public key), so
// will fit in KEY_BITS.
uint8_t signature[KEY_BITS / 8];
if (sizeof(signature) < RSA_size(key.get())) {
return make_sign_error("Signing key is too large");
}
unsigned signature_len = 0;
if (!RSA_sign(NID_sha256, digest, sizeof(digest), signature, &signature_len, key.get())) {
return make_sign_error("Failed to sign");
}
SignResult result;
result.signature.reserve(signature_len);
std::copy(signature, signature + signature_len, std::back_inserter(result.signature));
return result;
}