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:
John W. Bruce
2020-03-26 13:20:15 -07:00
parent c0d7f16b78
commit d21d70f533
5 changed files with 53 additions and 61 deletions

View File

@@ -16,6 +16,7 @@
#include <openssl/evp.h>
#include <openssl/md5.h>
#include <openssl/pem.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <openssl/x509v3.h>
@@ -69,22 +70,6 @@ class 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 wvcdm {
@@ -324,27 +309,34 @@ bool RsaPublicKey::VerifySignature(const std::string& message,
}
bool ExtractExtensionValueFromCertificate(const std::string& cert,
const std::string& extension_oid,
const std::string& expected_oid,
size_t cert_index, uint32_t* value) {
// Load the certificate chain into a BoringSSL X509 Stack
const boringssl_ptr<STACK_OF(X509), DeleteX509Stack> x509_stack(
sk_X509_new_null());
if (!x509_stack) {
LOGE("Unable to allocate X509 stack");
// Convert the OID to OBJ form
boringssl_ptr<ASN1_OBJECT, ASN1_OBJECT_free> expected_obj(
OBJ_txt2obj(expected_oid.c_str(), true));
// 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;
}
CBS pkcs7;
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();
STACK_OF(X509)* certs = pkcs7->d.sign->cert;
// 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(
"Unexpected number of certificates in chain: "
"count = %zu, minimum = %zu",
@@ -367,7 +359,13 @@ bool ExtractExtensionValueFromCertificate(const std::string& cert,
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
// the next one.
continue;