Files
oemcrypto/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.c
Fred Gylys-Colwell 0a16cb2594 Version 17 plus test updates and OPK v17
This is the first public release of OPK v17.
See the file CHANGELOG.md for details.
2022-04-13 19:36:27 -07:00

136 lines
4.0 KiB
C

/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
source code may only be used and distributed under the Widevine
License Agreement. */
#include "rsa_util.h"
#include "oemcrypto_key_types.h"
#include "openssl/bio.h"
#include "openssl/err.h"
#include "openssl/rsa.h"
#include "openssl/sha.h"
#include "openssl/x509.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
void dump_ssl_error(void) {
int count = 0;
unsigned long err;
while ((err = ERR_get_error())) {
count++;
char buffer[120];
ERR_error_string_n((int)err, buffer, sizeof(buffer));
LOGE("SSL Error %d -- %lu -- %s", count, err, buffer);
}
}
bool CheckRSAKey(const RSA* rsa) {
ABORT_IF(rsa == NULL, "rsa is NULL");
switch (RSA_check_key(rsa)) {
case 1: /* valid. */
return true;
case 0: /* not valid. */
LOGE("RSA key not valid");
dump_ssl_error();
return false;
default: /* -1 == check failed. */
LOGE("Error checking RSA key");
dump_ssl_error();
return false;
}
}
bool DeserializePKCS8PrivateKey(const uint8_t* serialized_bytes, size_t size,
RSA** rsa) {
ABORT_IF(serialized_bytes == NULL || size <= 0 || rsa == NULL,
"Parameters are NULL or 0");
BIO* bio = BIO_new_mem_buf(serialized_bytes, (int)size);
if (bio == NULL) {
LOGE("Could not allocate bio buffer");
return false;
}
bool success = false;
EVP_PKEY* evp = NULL;
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
if (pkcs8_pki == NULL) {
LOGE("d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL");
dump_ssl_error();
goto cleanup;
}
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == NULL) {
LOGE("EVP_PKCS82PKEY returned NULL");
dump_ssl_error();
goto cleanup;
}
*rsa = EVP_PKEY_get1_RSA(evp);
if (*rsa == NULL) {
LOGE("PrivateKeyInfo did not contain an RSA key");
goto cleanup;
}
success = true;
cleanup:
if (evp != NULL) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != NULL) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
return success;
}
bool RSASignSSAPSSSHA1(RSA* rsa, const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length) {
ABORT_IF(rsa == NULL || message == NULL || message_length <= 0 ||
signature == NULL || signature_length == NULL,
"Parameters are NULL or 0");
size_t private_key_size = RSA_size(rsa);
ABORT_IF(*signature_length < private_key_size,
"signature_length is not long enough");
/* Hash the message using SHA1. */
uint8_t hash[SHA_DIGEST_LENGTH];
if (!SHA1(message, message_length, hash)) {
dump_ssl_error();
return false;
}
/* Add PSS padding. */
ABORT_IF(private_key_size > KEY_SIZE_3072, "rsa size is too large");
uint8_t padding[KEY_SIZE_3072];
const int kPssSaltLength = 20;
int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa, padding, hash, EVP_sha1(),
NULL, kPssSaltLength);
if (status == 0) {
dump_ssl_error();
return false;
}
/* Encrypt PSS padded digest. */
int bytes_written = RSA_private_encrypt(private_key_size, padding, signature,
rsa, RSA_NO_PADDING);
if (bytes_written == -1) {
dump_ssl_error();
return false;
}
*signature_length = bytes_written;
return true;
}
bool RSAPrivateDecrypt(RSA* rsa, const uint8_t* in, size_t in_length,
uint8_t* out, size_t* out_length) {
ABORT_IF(rsa == NULL || in == NULL || in_length <= 0 || out == NULL ||
out_length == NULL,
"Parameters are NULL or 0");
size_t private_key_size = RSA_size(rsa);
ABORT_IF(*out_length < private_key_size, "out_length is not long enough");
int decrypted_size =
RSA_private_decrypt(in_length, in, out, rsa, RSA_PKCS1_OAEP_PADDING);
if (decrypted_size == -1) {
dump_ssl_error();
return false;
}
*out_length = decrypted_size;
return true;
}