Restore OpenSSL Compatibility
(This is a merge of http://go/wvgerrit/96226.) This patch does a number of different things in order to re-enable the CDM to use OpenSSL 1.1.0+ out of the box, instead of just BoringSSL: * To support https://cryptography.io/, BoringSSL has reimplemented just enough of the OpenSSL PKCS7 API that we can fulfill our purposes with code that works on either library. This patch replaces code in privacy_crypto_boringssl.cpp and oec_session_util.cpp that was only compatible with BoringSSL with code that also works in OpenSSL. * Replaces code in oec_session_util.cpp that used the deprecated OpenSSL 1.0.0 API with OpenSSL 1.1.0-compatible code. This code previously worked on BoringSSL because they have not yet removed the OpenSSL 1.0.0 functions, even though they also implemented the 1.1.0 API. * Replaces openssl/mem.h (which does not work in OpenSSL 1.1.0 and higher) with openssl/crypto.h. (which works in all OpenSSL and BoringSSL releases) This does not require any function code changes. * The OID-comparison code in privacy_crypto_boringssl.cpp was using BoringSSL-exclusive functions to convert OBJ-format OIDs to text. Conversion functions that work on either library exist. However, the new code uses a different technique instead, pre-converting the passed-in OID to OBJ format. This allows it to be compared to the certificate directly, avoiding converting every certificate extension OID to text. * Allows the selection of "openssl" as the privacy_crypto_impl and adds a variable to configure OpenSSL. More will follow in future patches as more configurations of OpenSSL are supported. Bug: 140053043 Test: CE CDM Unit Tests Test: CE CDM Unit Tests w/ the x86-64 Platform Reconfigured to OpenSSL Test: Android Unit Tests Change-Id: I57cebbbfb59e0bcab85b589b98fb9ffd18885415
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/md5.h>
|
#include <openssl/md5.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/pkcs7.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
@@ -69,22 +70,6 @@ class boringssl_ptr {
|
|||||||
CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr);
|
CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
void DeleteX509Stack(STACK_OF(X509) * stack) {
|
|
||||||
sk_X509_pop_free(stack, X509_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetExtensionOid(X509_EXTENSION* extension) {
|
|
||||||
ASN1_OBJECT* const extension_object = X509_EXTENSION_get_object(extension);
|
|
||||||
if (!extension_object) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const int size = OBJ_obj2txt(nullptr, 0, extension_object, 1);
|
|
||||||
std::string ret(size, '\0');
|
|
||||||
OBJ_obj2txt(&ret[0], ret.size() + 1, extension_object, 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
@@ -324,27 +309,34 @@ bool RsaPublicKey::VerifySignature(const std::string& message,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ExtractExtensionValueFromCertificate(const std::string& cert,
|
bool ExtractExtensionValueFromCertificate(const std::string& cert,
|
||||||
const std::string& extension_oid,
|
const std::string& expected_oid,
|
||||||
size_t cert_index, uint32_t* value) {
|
size_t cert_index, uint32_t* value) {
|
||||||
// Load the certificate chain into a BoringSSL X509 Stack
|
// Convert the OID to OBJ form
|
||||||
const boringssl_ptr<STACK_OF(X509), DeleteX509Stack> x509_stack(
|
boringssl_ptr<ASN1_OBJECT, ASN1_OBJECT_free> expected_obj(
|
||||||
sk_X509_new_null());
|
OBJ_txt2obj(expected_oid.c_str(), true));
|
||||||
if (!x509_stack) {
|
|
||||||
LOGE("Unable to allocate X509 stack");
|
// The cert is a PKCS7 signed data type. First, parse it into an OpenSSL
|
||||||
|
// structure and find the certificate list.
|
||||||
|
//
|
||||||
|
// We must make defensive copies of cert's properties because of how
|
||||||
|
// d2i_PKCS7() works.
|
||||||
|
const unsigned char* cert_data =
|
||||||
|
reinterpret_cast<const unsigned char*>(cert.data());
|
||||||
|
long cert_size = static_cast<long>(cert.size());
|
||||||
|
boringssl_ptr<PKCS7, PKCS7_free> pkcs7(
|
||||||
|
d2i_PKCS7(NULL, &cert_data, cert_size));
|
||||||
|
if (!pkcs7) {
|
||||||
|
LOGE("Error parsing PKCS7 message");
|
||||||
|
return false;
|
||||||
|
} else if (!PKCS7_type_is_signed(pkcs7.get())) {
|
||||||
|
LOGE("Unexpected PKCS7 message type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CBS pkcs7;
|
STACK_OF(X509)* certs = pkcs7->d.sign->cert;
|
||||||
CBS_init(&pkcs7, reinterpret_cast<const uint8_t*>(cert.data()), cert.size());
|
|
||||||
if (!PKCS7_get_certificates(x509_stack.get(), &pkcs7)) {
|
|
||||||
LOGE("Error getting certificate chain");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
STACK_OF(X509)* certs = x509_stack.get();
|
|
||||||
|
|
||||||
// Find the desired certificate from the stack.
|
// Find the desired certificate from the stack.
|
||||||
if (sk_X509_num(certs) <= cert_index) {
|
if (cert_index >= static_cast<size_t>(sk_X509_num(certs))) {
|
||||||
LOGE(
|
LOGE(
|
||||||
"Unexpected number of certificates in chain: "
|
"Unexpected number of certificates in chain: "
|
||||||
"count = %zu, minimum = %zu",
|
"count = %zu, minimum = %zu",
|
||||||
@@ -367,7 +359,13 @@ bool ExtractExtensionValueFromCertificate(const std::string& cert,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetExtensionOid(extension) != extension_oid) {
|
ASN1_OBJECT* const extension_obj = X509_EXTENSION_get_object(extension);
|
||||||
|
if (extension_obj == nullptr) {
|
||||||
|
LOGE("Unable to get cert extension OID: cert_index = %d", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OBJ_cmp(extension_obj, expected_obj.get()) != 0) {
|
||||||
// This extension is not the Widevine System ID, so we should move on to
|
// This extension is not the Widevine System ID, so we should move on to
|
||||||
// the next one.
|
// the next one.
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <openssl/cmac.h>
|
#include <openssl/cmac.h>
|
||||||
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
#include <openssl/mem.h>
|
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/cmac.h>
|
#include <openssl/cmac.h>
|
||||||
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
#include <openssl/mem.h>
|
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
#include <openssl/mem.h>
|
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
|||||||
@@ -49,12 +49,7 @@ void PrintTo(const vector<uint8_t>& value, ostream* os) {
|
|||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void DeleteX509Stack(STACK_OF(X509)* stack) {
|
|
||||||
sk_X509_pop_free(stack, X509_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr size_t kTestSubsampleSectionSize = 256;
|
constexpr size_t kTestSubsampleSectionSize = 256;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
@@ -1161,22 +1156,25 @@ void Session::LoadOEMCert(bool verify_cert) {
|
|||||||
public_cert.data(), &public_cert_length));
|
public_cert.data(), &public_cert_length));
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadOEMPrivateKey(session_id()));
|
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadOEMPrivateKey(session_id()));
|
||||||
|
|
||||||
// Load the certificate chain into a BoringSSL X509 Stack
|
// The cert is a PKCS7 signed data type. First, parse it into an OpenSSL
|
||||||
const boringssl_ptr<STACK_OF(X509), DeleteX509Stack> x509_stack(
|
// structure and find the certificate list.
|
||||||
sk_X509_new_null());
|
//
|
||||||
ASSERT_TRUE(x509_stack.NotNull()) << "Unable to allocate X509 stack.";
|
// We must make defensive copies of public_cert's properties because of how
|
||||||
|
// d2i_PKCS7() works.
|
||||||
|
const unsigned char* cert_data =
|
||||||
|
reinterpret_cast<const unsigned char*>(public_cert.data());
|
||||||
|
long cert_size = static_cast<long>(public_cert.size());
|
||||||
|
boringssl_ptr<PKCS7, PKCS7_free> pkcs7(
|
||||||
|
d2i_PKCS7(NULL, &cert_data, cert_size));
|
||||||
|
ASSERT_TRUE(pkcs7.NotNull()) << "Error parsing PKCS7 message";
|
||||||
|
ASSERT_TRUE(PKCS7_type_is_signed(pkcs7.get()))
|
||||||
|
<< "Unexpected PKCS7 message type";
|
||||||
|
|
||||||
CBS pkcs7;
|
STACK_OF(X509)* certs = pkcs7->d.sign->cert;
|
||||||
CBS_init(&pkcs7, public_cert.data(), public_cert.size());
|
|
||||||
if (!PKCS7_get_certificates(x509_stack.get(), &pkcs7)) {
|
|
||||||
dump_boringssl_error();
|
|
||||||
FAIL() << "Unable to deserialize certificate chain.";
|
|
||||||
}
|
|
||||||
|
|
||||||
STACK_OF(X509)* certs = x509_stack.get();
|
|
||||||
|
|
||||||
// Load the public cert's key into public_rsa_ and verify, if requested
|
// Load the public cert's key into public_rsa_ and verify, if requested
|
||||||
for (size_t i = 0; certs && i < sk_X509_num(certs); i++) {
|
for (size_t i = 0; certs && i < static_cast<size_t>(sk_X509_num(certs));
|
||||||
|
++i) {
|
||||||
X509* x509_cert = sk_X509_value(certs, i);
|
X509* x509_cert = sk_X509_value(certs, i);
|
||||||
boringssl_ptr<EVP_PKEY, EVP_PKEY_free> pubkey(X509_get_pubkey(x509_cert));
|
boringssl_ptr<EVP_PKEY, EVP_PKEY_free> pubkey(X509_get_pubkey(x509_cert));
|
||||||
ASSERT_TRUE(pubkey.NotNull());
|
ASSERT_TRUE(pubkey.NotNull());
|
||||||
@@ -1253,12 +1251,10 @@ bool Session::VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
|
|||||||
size_t message_length,
|
size_t message_length,
|
||||||
const uint8_t* signature,
|
const uint8_t* signature,
|
||||||
size_t signature_length) {
|
size_t signature_length) {
|
||||||
EVP_MD_CTX md_ctx_struct;
|
boringssl_ptr<EVP_MD_CTX, EVP_MD_CTX_free> md_ctx(EVP_MD_CTX_new());
|
||||||
EVP_MD_CTX* md_ctx = &md_ctx_struct;
|
|
||||||
EVP_MD_CTX_init(md_ctx);
|
|
||||||
EVP_PKEY_CTX* pkey_ctx = nullptr;
|
EVP_PKEY_CTX* pkey_ctx = nullptr;
|
||||||
|
|
||||||
if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, EVP_sha1(),
|
if (EVP_DigestVerifyInit(md_ctx.get(), &pkey_ctx, EVP_sha1(),
|
||||||
nullptr /* no ENGINE */, pkey) != 1) {
|
nullptr /* no ENGINE */, pkey) != 1) {
|
||||||
LOGE("EVP_DigestVerifyInit failed in VerifyPSSSignature");
|
LOGE("EVP_DigestVerifyInit failed in VerifyPSSSignature");
|
||||||
goto err;
|
goto err;
|
||||||
@@ -1280,12 +1276,12 @@ bool Session::VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EVP_DigestVerifyUpdate(md_ctx, message, message_length) != 1) {
|
if (EVP_DigestVerifyUpdate(md_ctx.get(), message, message_length) != 1) {
|
||||||
LOGE("EVP_DigestVerifyUpdate failed in VerifyPSSSignature");
|
LOGE("EVP_DigestVerifyUpdate failed in VerifyPSSSignature");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EVP_DigestVerifyFinal(md_ctx, const_cast<uint8_t*>(signature),
|
if (EVP_DigestVerifyFinal(md_ctx.get(), const_cast<uint8_t*>(signature),
|
||||||
signature_length) != 1) {
|
signature_length) != 1) {
|
||||||
LOGE(
|
LOGE(
|
||||||
"EVP_DigestVerifyFinal failed in VerifyPSSSignature. (Probably a bad "
|
"EVP_DigestVerifyFinal failed in VerifyPSSSignature. (Probably a bad "
|
||||||
@@ -1293,12 +1289,10 @@ bool Session::VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
EVP_MD_CTX_cleanup(md_ctx);
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
dump_boringssl_error();
|
dump_boringssl_error();
|
||||||
EVP_MD_CTX_cleanup(md_ctx);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user