Merge "Remove OEMCrypto reference"

This commit is contained in:
TreeHugger Robot
2021-06-29 18:10:29 +00:00
committed by Android (Google) Code Review
40 changed files with 0 additions and 11448 deletions

View File

@@ -1,5 +0,0 @@
# Reference OEMCrypto
This directory contains a testing-only implementation of OEMCrypto. **This
implementation is *NOT* suitable for production use and must *NOT* be released
on devices.**

View File

@@ -1,10 +0,0 @@
// If you are using a baked-in certificate instead of supporting keyboxes,
// you should have received a keys.cpp from Widevine that replaces this file.
//
// If you are not using a baked-in certificate, then you may ignore this file,
// as it intentionally defines an empty key.
#include "keys.h"
const uint8_t kPrivateKey[] = { 0, };
const size_t kPrivateKeySize = 0;

View File

@@ -1,11 +0,0 @@
// This header is used to access the baked-in certificate if one is in use.
#ifndef KEYS_H_
#define KEYS_H_
#include <stddef.h>
#include <stdint.h>
extern const uint8_t kPrivateKey[];
extern const size_t kPrivateKeySize;
#endif // KEYS_H_

View File

@@ -1,334 +0,0 @@
// This file contains the test OEM cert.
#include "oem_cert.h"
namespace wvoec_ref {
const uint32_t kOEMSystemId_Prod = 7913;
// From file test_rsa_key_2_carmichael.pk8 in team shared drive.
// Size is 1216.
const uint8_t kOEMPrivateKey_Prod[] = {
0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a,
0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde,
0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e,
0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4,
0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3,
0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce,
0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb,
0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e,
0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4,
0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b,
0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda,
0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54,
0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03,
0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51,
0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b,
0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12,
0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01,
0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a,
0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed,
0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb,
0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb,
0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
0x82, 0x01, 0x00, 0x0a, 0xf9, 0x4a, 0x19, 0x72, 0x88, 0x1b, 0x4e, 0xd8,
0x2f, 0xef, 0x99, 0x93, 0x32, 0xda, 0x51, 0x21, 0x2e, 0x14, 0x06, 0xf4,
0xe9, 0x65, 0x1c, 0xf9, 0xd4, 0xcf, 0x1a, 0x51, 0x53, 0xcd, 0x48, 0x33,
0x8c, 0x30, 0xed, 0xdd, 0x53, 0x6f, 0x29, 0x82, 0xf9, 0xe0, 0x74, 0xde,
0xb1, 0x13, 0x01, 0x88, 0x8f, 0xce, 0x14, 0xc1, 0x3b, 0x90, 0xb7, 0xcc,
0x6c, 0xdf, 0x35, 0xa1, 0xf2, 0x1a, 0x3d, 0xbe, 0x19, 0xd7, 0x0a, 0xe4,
0x67, 0x75, 0xbb, 0xfa, 0x87, 0xf4, 0x03, 0xb5, 0x7f, 0x69, 0xe4, 0x0b,
0x6a, 0xdc, 0x92, 0x82, 0x54, 0x64, 0x1a, 0x94, 0x2d, 0xe4, 0x63, 0x40,
0xb2, 0xb4, 0x85, 0x6b, 0xc8, 0x34, 0xba, 0xa2, 0x14, 0x30, 0x47, 0x1a,
0xeb, 0x90, 0x62, 0x30, 0x43, 0x44, 0x02, 0xc7, 0x0c, 0x30, 0xc0, 0x7f,
0xa9, 0x47, 0xae, 0xde, 0x68, 0x27, 0x92, 0xaa, 0x11, 0x95, 0xf5, 0x6f,
0xfc, 0x19, 0x8b, 0x49, 0xa0, 0x77, 0x9d, 0xc6, 0x13, 0x5d, 0x73, 0xff,
0x45, 0xa2, 0x4c, 0x3b, 0xf3, 0xe1, 0x2d, 0xd7, 0xc4, 0x70, 0xe2, 0x6c,
0x37, 0x99, 0x4c, 0x7a, 0xa9, 0x27, 0xf8, 0x3a, 0xd6, 0xfd, 0xc5, 0xd8,
0xfa, 0x2d, 0x0e, 0x71, 0x4b, 0x85, 0x7e, 0xce, 0xcb, 0x1c, 0x79, 0x71,
0xbd, 0xff, 0x63, 0x03, 0x6b, 0x58, 0x68, 0xe0, 0x14, 0xca, 0x5e, 0x85,
0xfd, 0xd0, 0xb7, 0xe0, 0x68, 0x14, 0xff, 0x2c, 0x82, 0x22, 0x26, 0x8a,
0x3f, 0xbf, 0xb0, 0x2a, 0x90, 0xff, 0xc7, 0x72, 0xfc, 0x66, 0x51, 0x3e,
0x51, 0x9f, 0x82, 0x68, 0x0e, 0xf3, 0x65, 0x74, 0x88, 0xab, 0xb7, 0xe5,
0x97, 0x5f, 0x0f, 0x3e, 0xe5, 0x3a, 0xbc, 0xa4, 0xa1, 0x50, 0xdd, 0x5c,
0x94, 0x4b, 0x0c, 0x70, 0x71, 0x48, 0x4e, 0xd0, 0xec, 0x46, 0x8f, 0xdf,
0xa2, 0x9a, 0xfe, 0xd8, 0x35, 0x1a, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcf,
0x73, 0x8c, 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75,
0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43,
0xeb, 0x85, 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda,
0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6,
0x51, 0x86, 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f,
0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27,
0x80, 0xb7, 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8,
0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16,
0x22, 0x6a, 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44,
0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60,
0x48, 0x16, 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce,
0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97,
0xb1, 0x49, 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28,
0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11,
0x9d, 0x17, 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3,
0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91,
0x32, 0x2d, 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41,
0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2,
0x74, 0x1d, 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd,
0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83,
0x51, 0x67, 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17,
0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c,
0x32, 0x83, 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0,
0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab,
0x9b, 0x0b, 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c,
0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1,
0x6c, 0x25, 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f,
0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48,
0x2c, 0x2d, 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41,
0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e,
0x08, 0x71, 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5,
0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29,
0x40, 0x19, 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b,
0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94,
0x49, 0x4c, 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8,
0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f,
0xce, 0xec, 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a,
0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06,
0x59, 0x22, 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a,
0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9,
0x83, 0x5a, 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a,
0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b,
0xc8, 0x96, 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8,
0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e,
0x75, 0xf6, 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65,
0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c,
0x52, 0xf9, 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33,
0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86,
0x4b, 0xb6, 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35,
0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02,
0x60, 0xf7, 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4,
0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95,
0x00, 0xae, 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde,
0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28,
0x33, 0xe0, 0xdb, 0x03
};
const size_t kOEMPrivateKeySize_Prod = sizeof(kOEMPrivateKey_Prod);
// From the team shared drive file
// oem-7913-leaf-and-intermediate-certs-test-key-2-carmichael.p7b, size 2353.
const uint8_t kOEMPublicCert_Prod[] = {
0x30, 0x82, 0x09, 0x2d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x1e, 0x30, 0x82, 0x09, 0x1a, 0x02,
0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x08,
0xfe, 0x30, 0x82, 0x03, 0x71, 0x30, 0x82, 0x02, 0x59, 0xa0, 0x03, 0x02,
0x01, 0x02, 0x02, 0x11, 0x00, 0xc2, 0x8d, 0x20, 0x22, 0x82, 0x8b, 0x9e,
0x63, 0x9d, 0x15, 0x89, 0x2c, 0xa9, 0x8f, 0xd9, 0x5d, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79,
0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31,
0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x31, 0x31, 0x31, 0x31,
0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31,
0x30, 0x36, 0x31, 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x30, 0x65, 0x31,
0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x39,
0x31, 0x33, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06,
0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09,
0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b,
0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04,
0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65,
0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40,
0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7,
0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56,
0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e,
0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34,
0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31,
0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e,
0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39,
0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2,
0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54,
0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3,
0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71,
0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96,
0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a,
0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c,
0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f,
0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca,
0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77,
0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27,
0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c,
0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c,
0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x16,
0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6,
0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x88, 0x95, 0xec, 0xcd, 0x8b, 0xa7,
0x51, 0xda, 0x74, 0x81, 0xa5, 0x39, 0x62, 0x1a, 0x0e, 0x2e, 0xde, 0x3c,
0x37, 0xea, 0xad, 0x7c, 0xee, 0x9b, 0x26, 0x8e, 0xe2, 0xd6, 0x34, 0xcd,
0xb7, 0x70, 0xba, 0xbf, 0xa0, 0xa3, 0xfe, 0xb3, 0x4b, 0xbc, 0xf4, 0x1c,
0x72, 0x66, 0x81, 0xd5, 0x09, 0x33, 0x78, 0x0c, 0x61, 0x21, 0xa8, 0xf1,
0xe2, 0xc9, 0xe2, 0x83, 0xc2, 0x19, 0x02, 0xf2, 0xe8, 0xab, 0x17, 0x36,
0x3a, 0x0b, 0x20, 0xaf, 0x0f, 0xae, 0x2e, 0x73, 0x68, 0xac, 0x15, 0xee,
0x9c, 0xc0, 0x92, 0x03, 0x7e, 0x95, 0x63, 0xaa, 0xad, 0x15, 0x96, 0x43,
0x20, 0x3b, 0xe5, 0x9b, 0x1f, 0xca, 0x02, 0xba, 0xf0, 0x07, 0x76, 0x80,
0xd7, 0xa3, 0x1a, 0xeb, 0xc8, 0xdb, 0x03, 0x7b, 0x43, 0x56, 0xe5, 0x96,
0x6b, 0x86, 0xfe, 0x08, 0x58, 0x8a, 0x84, 0xbd, 0xe9, 0x47, 0x18, 0xee,
0xb2, 0xa8, 0x05, 0x7b, 0xf0, 0xfd, 0xaa, 0xb9, 0x85, 0xcd, 0x7a, 0x0e,
0x6b, 0x6c, 0x9f, 0xc6, 0x75, 0xd2, 0x2a, 0xfe, 0x5b, 0xf3, 0xb7, 0x31,
0x6c, 0xac, 0xe3, 0x00, 0x9f, 0xe7, 0xdd, 0xe3, 0x81, 0xc1, 0x36, 0xc3,
0x1c, 0x5f, 0xdf, 0xf2, 0xc3, 0x5e, 0xfa, 0x55, 0x32, 0xd8, 0x5c, 0xa8,
0xe5, 0xcc, 0xb6, 0x4a, 0xe9, 0xe2, 0xcc, 0x38, 0x44, 0x07, 0x46, 0x59,
0x34, 0x84, 0x79, 0xf9, 0xee, 0x3c, 0x4b, 0x48, 0x90, 0xab, 0x73, 0xb0,
0xa1, 0x92, 0xc3, 0xd6, 0x83, 0x87, 0x81, 0xca, 0x12, 0x81, 0xd6, 0x5d,
0xf7, 0x6f, 0x7a, 0x35, 0x5e, 0x4f, 0x02, 0x66, 0x8a, 0x47, 0x88, 0x82,
0xab, 0xf0, 0x12, 0x1d, 0xb9, 0x75, 0x3b, 0x7b, 0xa8, 0x36, 0x15, 0xef,
0xa8, 0x12, 0x0e, 0x53, 0xb4, 0x83, 0x78, 0x53, 0xc0, 0x52, 0xae, 0xa6,
0x0a, 0xa0, 0x53, 0xdc, 0x1c, 0x15, 0x22, 0xdd, 0x17, 0x98, 0x30, 0x82,
0x05, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
0x10, 0x03, 0xb1, 0xf7, 0x58, 0xdf, 0x1d, 0xe3, 0x25, 0x00, 0x0b, 0x10,
0x3d, 0xd5, 0xe6, 0xe4, 0x64, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61,
0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f,
0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c,
0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a,
0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f,
0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76,
0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d,
0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x31,
0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x33, 0x35, 0x5a, 0x17, 0x0d, 0x32,
0x37, 0x31, 0x31, 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x31, 0x33, 0x5a,
0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79,
0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31,
0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc8,
0x71, 0xae, 0x08, 0x0c, 0x06, 0x06, 0x2d, 0x81, 0x7c, 0xa9, 0x8b, 0xb3,
0xd6, 0x66, 0xe4, 0xf6, 0x08, 0x5e, 0x5a, 0x75, 0xe8, 0x74, 0x61, 0x7a,
0x88, 0xca, 0x85, 0x14, 0x0d, 0x58, 0xa4, 0x09, 0x19, 0x6c, 0x60, 0xc9,
0xad, 0x91, 0x1c, 0xbf, 0x04, 0xb3, 0x47, 0x10, 0x63, 0x7f, 0x02, 0x58,
0xc2, 0x1e, 0xbd, 0xcc, 0x07, 0x77, 0xaa, 0x7e, 0x14, 0xa8, 0xc2, 0x01,
0xcd, 0xe8, 0x46, 0x60, 0x53, 0x6f, 0x2f, 0xda, 0x17, 0x2d, 0x4d, 0x9d,
0x0e, 0x5d, 0xb5, 0x50, 0x95, 0xae, 0xab, 0x6e, 0x43, 0xe3, 0xb0, 0x00,
0x12, 0xb4, 0x05, 0x82, 0x4a, 0x2b, 0x14, 0x63, 0x0d, 0x1f, 0x06, 0x12,
0xaa, 0xe1, 0x9d, 0xe7, 0xba, 0xda, 0xe3, 0xfc, 0x7c, 0x6c, 0x73, 0xae,
0x56, 0xf8, 0xab, 0xf7, 0x51, 0x93, 0x31, 0xef, 0x8f, 0xe4, 0xb6, 0x01,
0x2c, 0xeb, 0x7b, 0xe4, 0xd8, 0xb3, 0xea, 0x70, 0x37, 0x89, 0x05, 0xa9,
0x51, 0x57, 0x72, 0x98, 0x9e, 0xa8, 0x46, 0xdb, 0xeb, 0x7a, 0x38, 0x2b,
0x2f, 0xc0, 0x27, 0xb7, 0xc2, 0xe1, 0x9a, 0x17, 0xdf, 0xf5, 0xd6, 0x9c,
0xd5, 0x8c, 0xb8, 0x66, 0x42, 0xd5, 0x04, 0x1e, 0x7c, 0x36, 0x4c, 0x1e,
0x3e, 0x45, 0x51, 0x4d, 0x41, 0x72, 0x22, 0x53, 0x3d, 0xf4, 0x57, 0x7c,
0x6c, 0x33, 0x34, 0x24, 0x45, 0xdf, 0x84, 0x87, 0x4a, 0xa6, 0xcb, 0x7c,
0x03, 0xa3, 0xaa, 0x8e, 0x2d, 0x82, 0x01, 0x27, 0x87, 0x74, 0x82, 0x1a,
0xbc, 0x0f, 0x76, 0x69, 0xab, 0xe0, 0x4e, 0x70, 0xbe, 0x37, 0xfc, 0xc8,
0x2c, 0x91, 0x17, 0x4f, 0xd5, 0x26, 0x3b, 0x7b, 0x90, 0xb5, 0x2d, 0x64,
0xba, 0xf7, 0xd2, 0x8a, 0xb4, 0x8f, 0x38, 0x9d, 0x8e, 0xba, 0xe7, 0x5c,
0x52, 0xf1, 0x0a, 0xb8, 0xc0, 0x1b, 0xb6, 0xb1, 0x70, 0x7e, 0x47, 0x59,
0x94, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30,
0x82, 0x01, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30,
0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
0x02, 0x02, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
0x04, 0x14, 0x4b, 0xcb, 0xdf, 0xaa, 0x02, 0xde, 0x8d, 0xc3, 0xe7, 0xe5,
0x85, 0xdb, 0x2e, 0x8a, 0xbe, 0x75, 0x6b, 0x8a, 0x67, 0x58, 0x30, 0x81,
0xb2, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7,
0x80, 0x14, 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5,
0xf7, 0x13, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81,
0x83, 0xa4, 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69,
0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f,
0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64,
0x82, 0x09, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30,
0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01,
0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82,
0x02, 0x01, 0x00, 0x61, 0x3f, 0x2f, 0x43, 0xe4, 0xbe, 0x66, 0x34, 0xef,
0x92, 0x06, 0xe9, 0x88, 0xba, 0x6a, 0x1d, 0x4f, 0x54, 0x5a, 0x97, 0xb1,
0x75, 0xd7, 0x93, 0xf8, 0x45, 0xc6, 0x83, 0x92, 0x36, 0xfd, 0x55, 0xa9,
0x21, 0x0b, 0xdc, 0xf6, 0xae, 0x11, 0xdc, 0x62, 0x21, 0x44, 0xbd, 0x04,
0x1d, 0x58, 0x2c, 0x03, 0xf8, 0xe4, 0xe2, 0x1e, 0xba, 0xe6, 0xdd, 0x19,
0xdd, 0x56, 0xfd, 0xce, 0x06, 0x73, 0x5f, 0x94, 0x1e, 0xb6, 0x03, 0xdb,
0x3d, 0x7b, 0xab, 0xab, 0x72, 0x64, 0x7b, 0xde, 0x7d, 0x4d, 0xcf, 0x7e,
0xf0, 0x91, 0x29, 0xc1, 0x77, 0x13, 0xc2, 0x6f, 0x80, 0xab, 0x7a, 0xa8,
0xce, 0xb0, 0x1c, 0x2a, 0xc5, 0x9c, 0xfb, 0x0b, 0xe5, 0x9f, 0x9c, 0x1b,
0xc9, 0x4b, 0x58, 0xdf, 0x96, 0x18, 0xf7, 0x67, 0x67, 0x89, 0xa4, 0xe9,
0x14, 0x48, 0xac, 0xfa, 0x9d, 0x86, 0x2a, 0xeb, 0x75, 0x2c, 0x2b, 0xbf,
0x63, 0x7d, 0xc7, 0x4e, 0x7e, 0xad, 0x39, 0x2d, 0xb4, 0x7c, 0x07, 0xa5,
0x5a, 0xe8, 0x3a, 0xd4, 0xf5, 0x0c, 0x4f, 0xf3, 0xa2, 0x9c, 0x3c, 0x32,
0xed, 0x9d, 0x4b, 0x49, 0x05, 0xbc, 0x1f, 0xa0, 0x13, 0xe6, 0xdd, 0x82,
0x79, 0x06, 0x31, 0x3b, 0xc6, 0x97, 0xec, 0x8d, 0xaa, 0x4f, 0xef, 0x14,
0x3c, 0x21, 0xf6, 0x72, 0xb2, 0x09, 0x42, 0xc7, 0x74, 0xfe, 0xef, 0x70,
0xbd, 0xe9, 0x85, 0x41, 0x30, 0x0b, 0xb3, 0x6b, 0x59, 0x0c, 0x0f, 0x11,
0x75, 0xd4, 0xbb, 0xb1, 0xdf, 0xb1, 0xdf, 0xb3, 0xfa, 0xb3, 0x3a, 0x43,
0x17, 0x7d, 0x8a, 0x82, 0xae, 0xa2, 0x07, 0xf8, 0x83, 0x51, 0xfb, 0x16,
0xfb, 0x64, 0xb6, 0x46, 0xda, 0xbe, 0x32, 0x2b, 0xc0, 0xee, 0x78, 0x2a,
0x84, 0xa9, 0x54, 0x0a, 0xf9, 0x2d, 0x61, 0x65, 0xde, 0xa5, 0x97, 0x66,
0x79, 0x02, 0xf8, 0x97, 0x17, 0xe2, 0xd4, 0x9f, 0x9e, 0xac, 0xcc, 0xae,
0x99, 0x9a, 0x03, 0x04, 0xbb, 0x45, 0xfe, 0xb2, 0xf5, 0x80, 0xba, 0xbf,
0xdd, 0x24, 0xe5, 0xe6, 0x1e, 0x5d, 0x36, 0xa5, 0x87, 0x0c, 0xdf, 0x60,
0x81, 0x6f, 0xb7, 0x5f, 0xb9, 0x1f, 0xca, 0x75, 0x3c, 0x1a, 0x63, 0xb0,
0xeb, 0xe6, 0x95, 0x86, 0x0d, 0xae, 0xa6, 0xc9, 0x2a, 0x94, 0xf1, 0xd0,
0xbe, 0x75, 0xc8, 0xf8, 0x07, 0xd7, 0x88, 0xff, 0xec, 0xf9, 0xcd, 0x49,
0xc6, 0xfe, 0x4d, 0x7f, 0x44, 0x1e, 0xd8, 0xaf, 0xa9, 0x72, 0x27, 0x98,
0xe2, 0x5a, 0x08, 0xea, 0x55, 0xd3, 0xb3, 0xea, 0xdc, 0x76, 0x69, 0x51,
0x10, 0x01, 0x46, 0x7d, 0x33, 0x94, 0x9c, 0x94, 0xef, 0xfe, 0x76, 0x1c,
0xc6, 0xd7, 0x15, 0x53, 0x3e, 0x8d, 0x3d, 0x29, 0x9a, 0x58, 0x6a, 0xf1,
0x75, 0x9e, 0xea, 0x1b, 0x4c, 0xf0, 0x47, 0x76, 0xac, 0xc6, 0xa2, 0x32,
0x44, 0x40, 0xdf, 0xfe, 0xff, 0x9d, 0xf4, 0xe2, 0xc2, 0xfa, 0xa1, 0x5f,
0x2e, 0x66, 0xe9, 0x97, 0xcb, 0x27, 0x26, 0x6e, 0x53, 0xe4, 0xe8, 0x86,
0x2c, 0xea, 0xd3, 0x69, 0x6c, 0x61, 0x4f, 0xfe, 0xc1, 0xc9, 0x8b, 0x05,
0x92, 0x6f, 0x47, 0x96, 0xce, 0xf0, 0x33, 0xfa, 0x7c, 0x78, 0x24, 0x9b,
0xd7, 0x8d, 0x36, 0x56, 0x37, 0x86, 0xbc, 0x72, 0x5a, 0xf9, 0xb9, 0xb0,
0x93, 0xf0, 0x81, 0x78, 0x10, 0xf2, 0xb0, 0xc2, 0x79, 0x91, 0x5e, 0xcf,
0xbc, 0x8c, 0xf2, 0x32, 0x0f, 0xf7, 0x2d, 0x30, 0xd8, 0x13, 0x77, 0x4f,
0x78, 0x9e, 0x40, 0x8d, 0xe6, 0x3a, 0x98, 0xb2, 0xaa, 0x13, 0x4d, 0x25,
0x49, 0x34, 0x6c, 0x80, 0x9e, 0x19, 0x03, 0xdb, 0xcd, 0xf5, 0xb1, 0x54,
0x74, 0x1b, 0x67, 0x3c, 0x46, 0xac, 0x3e, 0x5d, 0xa2, 0xd9, 0x13, 0x83,
0x30, 0xeb, 0x82, 0x3b, 0x06, 0xab, 0x3c, 0x39, 0x7d, 0xd0, 0x68, 0x31,
0x00
};
const size_t kOEMPublicCertSize_Prod = sizeof(kOEMPublicCert_Prod);
// Refer to the following in main modules.
// This level of indirection is present so new OEM Certificates can be
// added and then selected for use at compile time or run time.
const uint32_t kOEMSystemId = kOEMSystemId_Prod;
const uint8_t* kOEMPrivateKey = kOEMPrivateKey_Prod;
const uint8_t* kOEMPublicCert = kOEMPublicCert_Prod;
const size_t kOEMPrivateKeySize = kOEMPrivateKeySize_Prod;
const size_t kOEMPublicCertSize = kOEMPublicCertSize_Prod;
} // namespace wvoec_ref

View File

@@ -1,21 +0,0 @@
// This header is used to access the OEM certificate if one is in use.
#ifndef OEM_CERT_H_
#define OEM_CERT_H_
#include <stddef.h>
#include <stdint.h>
namespace wvoec_ref {
// Refer to the following in main modules
extern const uint32_t kOEMSystemId;
extern const uint8_t* kOEMPrivateKey;
extern const uint8_t* kOEMPublicCert;
extern const size_t kOEMPrivateKeySize;
extern const size_t kOEMPublicCertSize;
} // namespace wvoec_ref
#endif // OEM_CERT_H_

View File

@@ -1,447 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_auth_ref.h"
#include <string.h>
#include <string>
#include <vector>
#include "keys.h"
#include "log.h"
namespace wvoec_ref {
namespace {
// Fake device ID which is to be returned inplace of a real ID.
const std::string kFakeDeviceId = "device_with_no_keybox";
// A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format
// This is the RSA Test Key. This key is not derived
// from any Widevine authentication root.
static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = {
0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01,
0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00,
0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a,
0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f,
0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c,
0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e,
0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a,
0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a,
0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3,
0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f,
0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06,
0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb,
0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3,
0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f,
0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4,
0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04,
0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25,
0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda,
0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67,
0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f,
0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03,
0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53,
0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13,
0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b,
0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e,
0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb,
0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01,
0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87,
0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72,
0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed,
0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44,
0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b,
0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb,
0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03,
0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x5e,
0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05,
0x45, 0x0f, 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29,
0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8, 0xac, 0x97,
0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7,
0x3b, 0x5c, 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d,
0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a, 0x7e, 0xdc,
0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c,
0x5e, 0x79, 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1,
0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e, 0x79, 0xf9,
0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3,
0x68, 0x7b, 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba,
0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1, 0x71, 0xe7,
0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75,
0xbe, 0x09, 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22,
0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1, 0xe8, 0x88,
0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78,
0x25, 0x0b, 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21,
0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0, 0x37, 0x14,
0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47,
0xde, 0x00, 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa,
0x68, 0x71, 0x17, 0x66, 0x12, 0x1a, 0x87, 0x27,
0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d,
0x6f, 0x35, 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51,
0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7, 0xb6, 0x64,
0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53,
0x1f, 0x51, 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77,
0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96, 0x07, 0x5f,
0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29,
0xf6, 0x06, 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0,
0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e, 0xc9, 0x21,
0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81,
0xb2, 0x51, 0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02,
0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c, 0xbe, 0x6d,
0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75,
0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9,
0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85, 0xab, 0x04,
0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda,
0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4,
0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86, 0x7b, 0xd0,
0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f,
0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13,
0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7, 0x1e, 0x64,
0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8,
0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96,
0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a, 0xcc, 0x48,
0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44,
0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27,
0x33, 0x85, 0x26, 0x60, 0x48, 0x16, 0xcb, 0xef,
0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce,
0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87,
0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49, 0xc2, 0x19,
0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28,
0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb,
0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17, 0x68, 0x78,
0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3,
0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54,
0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d, 0xeb, 0x3f,
0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41,
0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42,
0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d, 0x8e, 0x87,
0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd,
0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53,
0xda, 0xfb, 0xed, 0x83, 0x51, 0x67, 0xa9, 0x55,
0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17,
0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02,
0x81, 0x80, 0x67, 0x9c, 0x32, 0x83, 0x39, 0x57,
0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0,
0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97,
0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b, 0x1b, 0x43,
0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c,
0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80,
0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25, 0x92, 0xe4,
0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f,
0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81,
0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d, 0x45, 0xdc,
0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41,
0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54,
0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71, 0x16, 0xd8,
0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5,
0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf,
0x35, 0x95, 0x41, 0x29, 0x40, 0x19, 0x83, 0x35,
0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b,
0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae,
0x50, 0x76, 0x63, 0x94, 0x49, 0x4c, 0xad, 0x10,
0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8,
0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b,
0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec, 0x5e, 0x61,
0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a,
0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69,
0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22, 0xfa, 0x34,
0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a,
0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26,
0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a, 0x2d, 0x0c,
0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a,
0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3,
0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96, 0x76, 0xe8,
0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8,
0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80,
0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6, 0x69, 0x1d,
0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65,
0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57,
0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9, 0xe4, 0xc7,
0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33,
0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50,
0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6, 0x2b, 0xad,
0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35,
0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a,
0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7, 0xab, 0x30,
0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4,
0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18,
0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae, 0x84, 0x6b,
0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde,
0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18,
0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03
};
} // namespace
bool AuthenticationRoot::Initialize(OEMCrypto_ProvisioningMethod method) {
if (prov_method_ != OEMCrypto_ProvisioningError) {
// If provisioning method is something other than ProvisioningError
// indicates it has already been initialized before. Must
// existing data.
drm_cert_key_.reset();
test_drm_cert_key_.reset();
keybox_.reset();
test_keybox_.reset();
oem_cert_.reset();
oem_cert_key_.reset();
}
prov_method_ = method;
switch (method) {
case OEMCrypto_DrmCertificate: {
std::unique_ptr<RsaPrivateKey> key =
RsaPrivateKey::Load(kPrivateKey, kPrivateKeySize);
if (key) {
drm_cert_key_ = std::move(key);
} else {
// This error message is OK in unit tests which use test certificate.
LOGE(
"FATAL ERROR: Platform uses a baked-in certificate instead of a "
"keybox, but the certificate could not be loaded.");
}
return true;
}
case OEMCrypto_Keybox:
case OEMCrypto_OEMCertificate:
// Nothing to do yet.
return true;
case OEMCrypto_ProvisioningError:
default: {
LOGE("Invalid provisioning method: method = %d",
static_cast<int>(method));
prov_method_ = OEMCrypto_ProvisioningError;
return false;
}
}
}
bool AuthenticationRoot::IsValid() const {
switch (prov_method_) {
case OEMCrypto_DrmCertificate: {
return HasDrmCertKey() && HasDeviceKey();
}
case OEMCrypto_Keybox: {
return HasDeviceKey();
}
case OEMCrypto_OEMCertificate: {
return HasOemCertKey() && HasDeviceKey();
}
default: {
LOGE("Root of trust is not properly initialized");
return false;
}
}
}
OEMCryptoResult AuthenticationRoot::IsKeyboxOrOemCertValid() const {
switch (prov_method_) {
case OEMCrypto_Keybox: {
WvKeybox* kb = keybox();
if (kb == nullptr) {
LOGW("Null keybox cannot be validated");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
return kb->IsKeyboxValid();
}
case OEMCrypto_OEMCertificate: {
if (!oem_cert_) {
LOGW("OEM cert is not installed");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return oem_cert_->IsCertificateValid();
}
case OEMCrypto_DrmCertificate: {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
default:
LOGE("Root of trust is not properly initialized");
return OEMCrypto_ERROR_SYSTEM_INVALIDATED;
}
}
OEMCryptoResult AuthenticationRoot::GetDeviceId(
uint8_t* device_id, size_t* device_id_length) const {
WvKeybox* kb = keybox();
if (kb != nullptr) {
return kb->GetDeviceId(device_id, device_id_length);
}
if (prov_method_ == OEMCrypto_Keybox) {
// Keybox devices must have keybox for the source of the device
// ID.
LOGE("Expected keybox to be set for a device ID");
return OEMCrypto_ERROR_NO_DEVICEID;
}
// For non-Keybox devices use fake device ID.
if (device_id_length == nullptr) {
LOGE("Output device ID length is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (device_id == nullptr && *device_id_length > 0) {
LOGE("Output device ID buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (*device_id_length < kFakeDeviceId.size()) {
*device_id_length = kFakeDeviceId.size();
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*device_id_length = kFakeDeviceId.size();
memcpy(device_id, kFakeDeviceId.data(), kFakeDeviceId.size());
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> AuthenticationRoot::DeviceId() const {
WvKeybox* kb = keybox();
if (kb != nullptr) {
return kb->DeviceId();
}
if (prov_method_ == OEMCrypto_Keybox) {
LOGE("Expected keybox to be set for a device ID");
return std::vector<uint8_t>();
}
return std::vector<uint8_t>(kFakeDeviceId.begin(), kFakeDeviceId.end());
}
std::vector<uint8_t> AuthenticationRoot::DeviceKey() const {
WvKeybox* kb = keybox();
if (kb != nullptr) {
return kb->DeviceKey();
}
LOGE("No device key has been set");
return std::vector<uint8_t>();
}
bool AuthenticationRoot::HasDeviceKey() const { return keybox() != nullptr; }
void AuthenticationRoot::Clear() {
RemoveTestRsaKey();
RemoveTestKeybox();
}
OEMCryptoResult AuthenticationRoot::LoadTestRsaKey() {
if (prov_method_ != OEMCrypto_DrmCertificate) {
LOGE("System does not support DRM certificates");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (test_drm_cert_key_) {
LOGE("Test RSA key is already loaded");
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
std::unique_ptr<RsaPrivateKey> key =
RsaPrivateKey::Load(kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
if (!key) {
LOGE("Failed to load test RSA key");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
test_drm_cert_key_ = std::move(key);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult AuthenticationRoot::IsKeyboxValid() const {
WvKeybox* kb = keybox();
if (kb == nullptr) {
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
return kb->IsKeyboxValid();
}
OEMCryptoResult AuthenticationRoot::InstallKeybox(const uint8_t* keybox_data,
size_t keybox_length) {
if (keybox_) {
LOGE("Keybox already installed");
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
const OEMCryptoResult result =
WvKeybox::ValidateData(keybox_data, keybox_length);
if (result != OEMCrypto_SUCCESS) {
LOGE("Cannot install an invalid keybox");
return result;
}
keybox_ = WvKeybox::Create(keybox_data, keybox_length);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult AuthenticationRoot::InstallTestKeybox(
const uint8_t* keybox_data, size_t keybox_length) {
if (prov_method_ != OEMCrypto_Keybox) {
LOGE("System does not support keybox");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (test_keybox_) {
LOGE("Test keybox already installed");
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
const OEMCryptoResult result =
WvKeybox::ValidateData(keybox_data, keybox_length);
if (result != OEMCrypto_SUCCESS) {
LOGE("Cannot install an invalid test keybox");
return result;
}
test_keybox_ = WvKeybox::Create(keybox_data, keybox_length);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult AuthenticationRoot::GetKeyData(uint8_t* key_data,
size_t* key_data_length) const {
if (prov_method_ != OEMCrypto_Keybox) {
LOGE("System does not support keybox");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
WvKeybox* kb = keybox();
if (kb == nullptr) {
LOGE("No keybox to be set for source of key data");
return OEMCrypto_ERROR_NO_KEYDATA;
}
return kb->GetKeyData(key_data, key_data_length);
}
OEMCryptoResult AuthenticationRoot::InstallOemCertificate(
const uint8_t* private_key, size_t private_key_size,
const uint8_t* public_cert, size_t public_cert_size) {
if (prov_method_ != OEMCrypto_OEMCertificate) {
LOGE("System does not support OEM certificates");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (oem_cert_ || oem_cert_key_) {
LOGE("OEM certificate is already installed");
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
std::unique_ptr<OemCertificate> oem_cert = OemCertificate::Create(
private_key, private_key_size, public_cert, public_cert_size);
if (!oem_cert) {
LOGE("Failed to install OEM certificate as root of trust");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (oem_cert->key_type() != OemCertificate::kRsa) {
LOGE("Only RSA-based OEM certificates supported");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
std::unique_ptr<RsaPrivateKey> oem_cert_key =
RsaPrivateKey::Load(oem_cert->GetPrivateKey());
if (!oem_cert_key) {
LOGE("Failed to parse OEM certificate private key");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
oem_cert_ = std::move(oem_cert);
oem_cert_key_ = std::move(oem_cert_key);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult AuthenticationRoot::GetOemPublicCertificate(
uint8_t* public_cert, size_t* public_cert_length) const {
if (prov_method_ != OEMCrypto_OEMCertificate) {
LOGE("System does not support OEM certificates");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (!oem_cert_) {
LOGE("OEM certificate is not installed");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return oem_cert_->GetPublicCertificate(public_cert, public_cert_length);
}
} // namespace wvoec_ref

View File

@@ -1,172 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_AUTH_REF_H_
#define OEMCRYPTO_AUTH_REF_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include "OEMCryptoCENC.h" // Needed for enums only.
#include "disallow_copy_and_assign.h"
#include "oemcrypto_keybox_ref.h"
#include "oemcrypto_oem_cert.h"
#include "oemcrypto_rsa_key.h"
namespace wvoec_ref {
// The AuthenticationRoot class contains the OEMCrypto information
// which makes up the "root of trust" of a device.
class AuthenticationRoot {
public:
AuthenticationRoot() {}
~AuthenticationRoot() {}
// Initializes the root of authentication for the provided
// |method|. This will clear any previously initialied data.
bool Initialize(OEMCrypto_ProvisioningMethod method);
// General root of trust API.
// Checks that the auth root has been properly initialized and can
// be used by the rest of OEMCrypto for the current provisioning
// method.
bool IsValid() const;
// Checks the validity of the underlying Keybox or OEM Certificate
// depending on the provisioning method.
// Similar to the expected behavior of OEMCrypto_IsKeyboxOrOEMCertValid().
OEMCryptoResult IsKeyboxOrOemCertValid() const;
// Gets the device ID from the root of trust.
// Similar to the expected behavior of OEMCrypto_GetDeviceID().
OEMCryptoResult GetDeviceId(uint8_t* device_id,
size_t* device_id_length) const;
// Returns the device ID from the root of trust. Intended to be used
// for core message generation.
std::vector<uint8_t> DeviceId() const;
// Returns the device key from the root of trust. For keybox-based
// devices, this is the device key from the keybox (or test keybox
// if installed). For devices that use a non-keybox provisioning
// method, this will be a device specific key.
std::vector<uint8_t> DeviceKey() const;
// Check for the existence of a device key.
bool HasDeviceKey() const;
// Clears any test data inside this root of trust.
void Clear();
// DRM Certificate-based root of trust API.
// Returns the shared RSA private key from the built-in DRM
// Certificate.
std::shared_ptr<RsaPrivateKey> ShareDrmCertKey() {
return test_drm_cert_key_ ? test_drm_cert_key_ : drm_cert_key_;
}
RsaPrivateKey* DrmCertKey() const {
return test_drm_cert_key_ ? test_drm_cert_key_.get() : drm_cert_key_.get();
}
bool HasDrmCertKey() const { return test_drm_cert_key_ || drm_cert_key_; }
// Loads the system's built-in RSA key. Only implemented for
// devices that are that pre-provisioned with a built-in DRM
// Certificate,
// This method implements the expected behavior of
// OEMCrypto_LoadTestRSAKey().
OEMCryptoResult LoadTestRsaKey();
// Removes any installed test RSA key.
void RemoveTestRsaKey() { test_drm_cert_key_.reset(); }
// Keybox-based root of trust API.
// Returns the currently installed keybox (or test keybox) if any
// present. The test keybox takes priority over the standard.
WvKeybox* keybox() const {
return test_keybox_ ? test_keybox_.get() : keybox_.get();
}
// Checks the validity of the keybox regardless of the provisioning
// method.
OEMCryptoResult IsKeyboxValid() const;
// Installs a clear WV keybox as the root of trust.
// A keybox can only be installed once, however, the provisioning
// method stated at initialization remains the same.
//
// This method is similar to the expected behavior of
// OEMCrypto_InstallKeyboxOrOEMCert() for keybox devices except
// that the keybox provided here must be decrypted before installing.
OEMCryptoResult InstallKeybox(const uint8_t* keybox_data,
size_t keybox_length);
// Installs a clear test WV keybox. Only settable for devices that
// uses a keybox for provisioning.
//
// This method is similar to the expected behavior of
// OEMCrypto_LoadTestKeybox() for keybox devices except that
// the keybox provided here must be decrypted before installing.
OEMCryptoResult InstallTestKeybox(const uint8_t* keybox_data,
size_t keybox_length);
// Removes any installed test keybox.
void RemoveTestKeybox() { test_keybox_.reset(); }
// Gets the keybox key data.
// Implements the expected behavior of OEMCrypto_GetKeyData().
OEMCryptoResult GetKeyData(uint8_t* key_data, size_t* key_data_length) const;
// OEM Certificate-base root of trust API.
// Installs an OEM certificate as the root of trust. The provided
// private key and public cert are parsed, but not validated. The
// private key will be made available for sessions to load.
OEMCryptoResult InstallOemCertificate(const uint8_t* private_key,
size_t private_key_size,
const uint8_t* public_cert,
size_t public_cert_size);
// For OEM Cert-based devices, returns the OEM Public Certificate
// component of the OEM Certificate.
// This method implements the expected behavior of
// OEMCrypto_GetOEMPublicCertificate().
OEMCryptoResult GetOemPublicCertificate(uint8_t* public_cert,
size_t* public_cert_length) const;
// Returns the OEM private key. Intended to be used when loading
// the OEM private key into a session.
// Should only be called for devices that use OEM Certificates
// for provisioning.
std::shared_ptr<RsaPrivateKey> ShareOemCertKey() { return oem_cert_key_; }
RsaPrivateKey* OemCertKey() const { return oem_cert_key_.get(); }
bool HasOemCertKey() const { return static_cast<bool>(oem_cert_key_); }
private:
OEMCrypto_ProvisioningMethod prov_method_ = OEMCrypto_ProvisioningError;
// DRM certificate.
// If no keybox, this is the private key of the baked-in DRM
// Certificate.
std::shared_ptr<RsaPrivateKey> drm_cert_key_;
std::shared_ptr<RsaPrivateKey> test_drm_cert_key_;
// Keybox data.
std::unique_ptr<WvKeybox> keybox_;
std::unique_ptr<WvKeybox> test_keybox_;
// OEM certificate.
std::unique_ptr<OemCertificate> oem_cert_;
std::shared_ptr<RsaPrivateKey> oem_cert_key_;
CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot);
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_AUTH_REF_H_

View File

@@ -1,782 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_ecc_key.h"
#include <assert.h>
#include <string.h>
#include <mutex>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
#include "log.h"
#include "scoped_object.h"
namespace wvoec_ref {
namespace {
// Estimated max size (in bytes) of a serialized ECC key (public or
// private). These values are based on rough calculations for
// secp521r1 (largest of the supported curves) and should be slightly
// larger needed.
constexpr size_t kPrivateKeySize = 230;
constexpr size_t kPublicKeySize = 164;
// 256 bit key, intended to be used with CMAC-AES-256.
constexpr size_t kEccSessionKeySize = 32;
using ScopedBigNum = ScopedObject<BIGNUM, BN_free>;
using ScopedBigNumCtx = ScopedObject<BN_CTX, BN_CTX_free>;
using ScopedEcKey = ScopedObject<EC_KEY, EC_KEY_free>;
using ScopedSigPoint = ScopedObject<ECDSA_SIG, ECDSA_SIG_free>;
using ScopedEvpMdCtx = ScopedObject<EVP_MD_CTX, EVP_MD_CTX_free>;
const EC_GROUP* GetEcGroup(EccCurve curve) {
// Creating a named EC_GROUP is an expensive operation, and they
// are always used in a manner which does not transfer ownership.
// Maintaining a process-wide set of supported EC groups reduces
// the overhead of group operations.
static std::mutex group_mutex;
static EC_GROUP* group_256 = nullptr;
static EC_GROUP* group_384 = nullptr;
static EC_GROUP* group_521 = nullptr;
std::lock_guard<std::mutex> group_lock(group_mutex);
switch (curve) {
case kEccSecp256r1: {
if (group_256 == nullptr) {
LOGD("Creating secp256r1 group");
// The curve secp256r1 was originally named prime256v1
// in the X9.62 specification.
group_256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
assert(group_256 != nullptr);
}
return group_256;
}
case kEccSecp384r1: {
if (group_384 == nullptr) {
LOGD("Creating secp384r1 group");
group_384 = EC_GROUP_new_by_curve_name(NID_secp384r1);
assert(group_384 != nullptr);
}
return group_384;
}
case kEccSecp521r1: {
if (group_521 == nullptr) {
LOGD("Creating secp521r1 group");
group_521 = EC_GROUP_new_by_curve_name(NID_secp521r1);
assert(group_521 != nullptr);
}
return group_521;
}
default:
LOGE("Cannot get EC group for unknown curve: curve = %d",
static_cast<int>(curve));
return nullptr;
}
}
// Determines which of the supported ECC curves the provided |key|
// belongs to.
//
// This is intended to be used on keys that have been deserialized
// from an ASN.1 structure which may have contained a key which is
// supported by OpenSSL/BoringSSL but not necessarily by OEMCrypto.
//
// If the key group is unknown to OEMCrypto or if an error occurs,
// kEccCurveUnknown is returned.
EccCurve GetCurveFromKeyGroup(const EC_KEY* key) {
ScopedBigNumCtx ctx(BN_CTX_new());
if (!ctx) {
LOGE("Failed to allocate BN ctx");
return kEccCurveUnknown;
}
const EC_GROUP* group = EC_KEY_get0_group(key);
if (group == nullptr) {
LOGE("Provided key does not have a group");
return kEccCurveUnknown;
}
int rc = EC_GROUP_cmp(group, GetEcGroup(kEccSecp256r1), ctx.get());
if (rc == 0) {
return kEccSecp256r1;
}
if (rc == -1) {
LOGE("Error occurred while checking against secp256r1");
return kEccCurveUnknown;
}
rc = EC_GROUP_cmp(group, GetEcGroup(kEccSecp384r1), ctx.get());
if (rc == 0) {
return kEccSecp384r1;
}
if (rc == -1) {
LOGE("Error occurred while checking against secp384r1");
return kEccCurveUnknown;
}
rc = EC_GROUP_cmp(group, GetEcGroup(kEccSecp521r1), ctx.get());
if (rc == 0) {
return kEccSecp521r1;
}
if (rc == -1) {
LOGE("Error occurred while checking against secp521r1");
return kEccCurveUnknown;
}
LOGW("Unsupported curve group");
return kEccCurveUnknown;
}
// Compares the public EC points of both keys to see if they are the
// equal.
// Both |public_key| and |private_key| must be of the same group.
bool IsMatchingKeyPair(const EC_KEY* public_key, const EC_KEY* private_key) {
ScopedBigNumCtx ctx(BN_CTX_new());
if (!ctx) {
LOGE("Failed to allocate BN ctx");
return false;
}
// Returns: 1 if not equal, 0 if equal, -1 if error.
const int res = EC_POINT_cmp(EC_KEY_get0_group(public_key),
EC_KEY_get0_public_key(public_key),
EC_KEY_get0_public_key(private_key), ctx.get());
if (res == -1) {
LOGE("Error occurred comparing keys");
}
return res == 0;
}
// Performs a SHA2 digest on the provided |message| and outputs the
// computed hash to |digest|.
// The digest algorithm used depends on which curve is used.
// - secp256r1 -> SHA-256
// - secp384r1 -> SHA-384
// - secp521r1 -> SHA-512
// This function assumes that all parameters are valid.
// Returns true on success, false otherwise.
bool DigestMessage(EccCurve curve, const uint8_t* message, size_t message_size,
std::vector<uint8_t>* digest) {
const EVP_MD* md_engine = nullptr;
switch (curve) {
case kEccSecp256r1: {
md_engine = EVP_sha256();
break;
}
case kEccSecp384r1: {
md_engine = EVP_sha384();
break;
}
case kEccSecp521r1: {
md_engine = EVP_sha512();
break;
}
case kEccCurveUnknown:
// This case is to suppress compiler warnings. It will never
// occur.
break;
}
if (md_engine == nullptr) {
LOGE("Failed to get MD engine: curve = %d", static_cast<int>(curve));
return false;
}
ScopedEvpMdCtx md_ctx(EVP_MD_CTX_new());
if (!md_ctx) {
LOGE("Failed to create MD CTX");
return false;
}
if (!EVP_DigestInit_ex(md_ctx.get(), md_engine, nullptr)) {
LOGE("Failed to init MD CTX");
return false;
}
if (message_size > 0 &&
!EVP_DigestUpdate(md_ctx.get(), message, message_size)) {
LOGE("Failed to update");
return false;
}
digest->resize(EVP_MD_CTX_size(md_ctx.get()), 0);
const int res = EVP_DigestFinal_ex(md_ctx.get(), digest->data(), nullptr);
if (!res) {
LOGE("Failed to finalize");
return false;
}
return true;
}
// This KDF function is defined by OEMCrypto ECC specification.
// Function signature is based on the |kdf| parameter of
// ECDH_compute_key(). This function assumes that all pointer
// parameters are not null.
extern "C" void* WidevineEccKdf(const void* secret, size_t secret_length,
void* key, size_t* key_size) {
if (*key_size < kEccSessionKeySize) {
LOGE("Output buffer is too small: required = %zu, size = %zu",
kEccSessionKeySize, *key_size);
return nullptr;
}
std::vector<uint8_t> digest;
if (!DigestMessage(kEccSecp256r1 /* SHA-256 */,
reinterpret_cast<const uint8_t*>(secret), secret_length,
&digest)) {
LOGE("Cannot derive key: Failed to hash secret");
return nullptr;
}
if (digest.size() != kEccSessionKeySize) {
LOGE("Unexpected hash size: actual = %zu, expected = %zu", digest.size(),
kEccSessionKeySize);
return nullptr;
}
*key_size = kEccSessionKeySize;
memcpy(key, digest.data(), *key_size);
return key;
}
} // namespace
std::string EccCurveToString(EccCurve curve) {
switch (curve) {
case kEccSecp256r1:
return "secp256r1";
case kEccSecp384r1:
return "secp384r1";
case kEccSecp521r1:
return "secp521r1";
case kEccCurveUnknown:
return "Unknown";
}
return "Unknown(" + std::to_string(static_cast<int>(curve)) + ")";
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::New(
const EccPrivateKey& private_key) {
std::unique_ptr<EccPublicKey> key(new EccPublicKey());
if (!key->InitFromPrivateKey(private_key)) {
LOGE("Failed to initialize public key from private key");
key.reset();
}
return key;
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::Load(const uint8_t* buffer,
size_t length) {
std::unique_ptr<EccPublicKey> key;
if (buffer == nullptr) {
LOGE("Provided public key buffer is null");
return key;
}
if (length == 0) {
LOGE("Provided public key buffer is zero length");
return key;
}
key.reset(new EccPublicKey());
if (!key->InitFromBuffer(buffer, length)) {
LOGE("Failed to initialize public key from buffer");
key.reset();
}
return key;
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::Load(const std::string& buffer) {
if (buffer.empty()) {
LOGE("Provided public key buffer is empty");
return std::unique_ptr<EccPublicKey>();
}
return Load(reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size());
}
// static
std::unique_ptr<EccPublicKey> EccPublicKey::Load(
const std::vector<uint8_t>& buffer) {
if (buffer.empty()) {
LOGE("Provided public key buffer is empty");
return std::unique_ptr<EccPublicKey>();
}
return Load(buffer.data(), buffer.size());
}
bool EccPublicKey::IsMatchingPrivateKey(
const EccPrivateKey& private_key) const {
if (private_key.curve() != curve_) {
return false;
}
return IsMatchingKeyPair(GetEcKey(), private_key.GetEcKey());
}
OEMCryptoResult EccPublicKey::Serialize(uint8_t* buffer,
size_t* buffer_size) const {
if (buffer_size == nullptr) {
LOGE("Output buffer size is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (buffer == nullptr && *buffer_size > 0) {
LOGE("Output buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t* der_key = nullptr;
const int der_res = i2d_EC_PUBKEY(key_, &der_key);
if (der_res < 0) {
LOGE("Public key serialization failed");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (der_key == nullptr) {
LOGE("Encoded key is unexpectedly null");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (der_res == 0) {
LOGE("Unexpected DER encoded size");
OPENSSL_free(der_key);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t required_size = static_cast<size_t>(der_res);
if (buffer == nullptr || *buffer_size < required_size) {
*buffer_size = required_size;
OPENSSL_free(der_key);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(buffer, der_key, required_size);
*buffer_size = required_size;
OPENSSL_free(der_key);
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> EccPublicKey::Serialize() const {
size_t key_size = kPublicKeySize;
std::vector<uint8_t> key_data(key_size, 0);
const OEMCryptoResult res = Serialize(key_data.data(), &key_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to serialize public key: result = %d", static_cast<int>(res));
key_data.clear();
} else {
key_data.resize(key_size);
}
return key_data;
}
OEMCryptoResult EccPublicKey::VerifySignature(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length) const {
if (signature == nullptr || signature_length == 0) {
LOGE("Signature is missing");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (message == nullptr && message_length > 0) {
LOGE("Bad message data");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Step 1: Parse signature.
const uint8_t* tp = signature;
ScopedSigPoint sig_point(d2i_ECDSA_SIG(nullptr, &tp, signature_length));
if (!sig_point) {
LOGE("Failed to parse signature");
// Most likely an invalid signature than an OpenSSL error.
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Step 2: Hash message
std::vector<uint8_t> digest;
if (!DigestMessage(curve_, message, message_length, &digest)) {
LOGE("Failed to digest message");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 3: Verify signature
const int res =
ECDSA_do_verify(digest.data(), digest.size(), sig_point.get(), key_);
if (res == -1) {
LOGE("Error occurred checking signature");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (res == 0) {
LOGD("Signature did not match");
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult EccPublicKey::VerifySignature(
const std::string& message, const std::string& signature) const {
if (signature.empty()) {
LOGE("Signature should not be empty");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return VerifySignature(
reinterpret_cast<const uint8_t*>(message.data()), message.size(),
reinterpret_cast<const uint8_t*>(signature.data()), signature.size());
}
OEMCryptoResult EccPublicKey::VerifySignature(
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature) const {
if (signature.empty()) {
LOGE("Signature should not be empty");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return VerifySignature(message.data(), message.size(), signature.data(),
signature.size());
}
EccPublicKey::~EccPublicKey() {
if (key_ != nullptr) {
EC_KEY_free(key_);
key_ = nullptr;
}
curve_ = kEccCurveUnknown;
}
bool EccPublicKey::InitFromBuffer(const uint8_t* buffer, size_t length) {
// Deserialize SubjectPublicKeyInfo
const uint8_t* tp = buffer;
ScopedEcKey key(d2i_EC_PUBKEY(nullptr, &tp, length));
if (!key) {
LOGE("Failed to parse key");
return false;
}
curve_ = GetCurveFromKeyGroup(key.get());
if (curve_ == kEccCurveUnknown) {
LOGE("Failed to determine key group");
return false;
}
// Required flags for IETF compliance.
EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED);
key_ = key.release();
return true;
}
bool EccPublicKey::InitFromPrivateKey(const EccPrivateKey& private_key) {
ScopedEcKey key(EC_KEY_new());
if (!key) {
LOGE("Failed to allocate key");
return false;
}
if (!EC_KEY_set_group(key.get(), EC_KEY_get0_group(private_key.GetEcKey()))) {
LOGE("Failed to set group");
return false;
}
if (!EC_KEY_set_public_key(key.get(),
EC_KEY_get0_public_key(private_key.GetEcKey()))) {
LOGE("Failed to set public point");
return false;
}
curve_ = private_key.curve();
// Required flags for IETF compliance.
EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED);
key_ = key.release();
return true;
}
// static
std::unique_ptr<EccPrivateKey> EccPrivateKey::New(EccCurve curve) {
std::unique_ptr<EccPrivateKey> key(new EccPrivateKey());
if (!key->InitFromCurve(curve)) {
LOGE("Failed to initialize private key from curve");
key.reset();
}
return key;
}
// static
std::unique_ptr<EccPrivateKey> EccPrivateKey::Load(const uint8_t* buffer,
size_t length) {
std::unique_ptr<EccPrivateKey> key;
if (buffer == nullptr) {
LOGE("Provided private key buffer is null");
return key;
}
if (length == 0) {
LOGE("Provided private key buffer is zero length");
return key;
}
key.reset(new EccPrivateKey());
if (!key->InitFromBuffer(buffer, length)) {
LOGE("Failed to initialize private key from buffer");
key.reset();
}
return key;
}
// static
std::unique_ptr<EccPrivateKey> EccPrivateKey::Load(const std::string& buffer) {
if (buffer.empty()) {
LOGE("Provided private key buffer is empty");
return std::unique_ptr<EccPrivateKey>();
}
return Load(reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size());
}
// static
std::unique_ptr<EccPrivateKey> EccPrivateKey::Load(
const std::vector<uint8_t>& buffer) {
if (buffer.empty()) {
LOGE("Provided private key buffer is empty");
return std::unique_ptr<EccPrivateKey>();
}
return Load(buffer.data(), buffer.size());
}
std::unique_ptr<EccPublicKey> EccPrivateKey::MakePublicKey() const {
return EccPublicKey::New(*this);
}
bool EccPrivateKey::IsMatchingPublicKey(const EccPublicKey& public_key) const {
if (public_key.curve() != curve_) {
return false;
}
return IsMatchingKeyPair(public_key.GetEcKey(), GetEcKey());
}
OEMCryptoResult EccPrivateKey::Serialize(uint8_t* buffer,
size_t* buffer_size) const {
if (buffer_size == nullptr) {
LOGE("Output buffer size is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (buffer == nullptr && *buffer_size > 0) {
LOGE("Output buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t* der_key = nullptr;
const int der_res = i2d_ECPrivateKey(key_, &der_key);
if (der_res < 0) {
LOGE("Private key serialization failed");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (der_key == nullptr) {
LOGE("Encoded key is unexpectedly null");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (der_res == 0) {
LOGE("Unexpected DER encoded size");
OPENSSL_free(der_key);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t required_size = static_cast<size_t>(der_res);
if (*buffer_size < required_size || buffer == nullptr) {
*buffer_size = required_size;
OPENSSL_free(der_key);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(buffer, der_key, required_size);
*buffer_size = required_size;
OPENSSL_free(der_key);
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> EccPrivateKey::Serialize() const {
size_t key_size = kPrivateKeySize;
std::vector<uint8_t> key_data(key_size, 0);
const OEMCryptoResult res = Serialize(key_data.data(), &key_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to serialize private key: result = %d", static_cast<int>(res));
key_data.clear();
} else {
key_data.resize(key_size);
}
return key_data;
}
OEMCryptoResult EccPrivateKey::GenerateSignature(
const uint8_t* message, size_t message_length, uint8_t* signature,
size_t* signature_length) const {
if (signature_length == nullptr) {
LOGE("Output signature size is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (signature == nullptr && *signature_length > 0) {
LOGE("Output signature is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (message == nullptr && message_length > 0) {
LOGE("Invalid message data");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const size_t expected_signature_length = ECDSA_size(key_);
if (*signature_length < expected_signature_length) {
*signature_length = expected_signature_length;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
// Step 1: Hash message.
std::vector<uint8_t> digest;
if (!DigestMessage(curve_, message, message_length, &digest)) {
LOGE("Failed to digest message");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 2: Generate signature point.
ScopedSigPoint sig_point(ECDSA_do_sign(digest.data(), digest.size(), key_));
if (!sig_point) {
LOGE("Failed to perform ECDSA");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Step 3: Serialize
std::vector<uint8_t> temp(expected_signature_length);
uint8_t* sig_ptr = temp.data();
const int res = i2d_ECDSA_SIG(sig_point.get(), &sig_ptr);
if (res <= 0) {
LOGE("Failed to serialize signature");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t required_size = static_cast<size_t>(res);
if (signature == nullptr || *signature_length < required_size) {
*signature_length = required_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(signature, temp.data(), required_size);
*signature_length = required_size;
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> EccPrivateKey::GenerateSignature(
const std::string& message) const {
size_t signature_size = SignatureSize();
std::vector<uint8_t> signature(signature_size, 0);
const OEMCryptoResult res =
GenerateSignature(reinterpret_cast<const uint8_t*>(message.data()),
message.size(), signature.data(), &signature_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to generate signature: result = %d", static_cast<int>(res));
signature.clear();
} else {
signature.resize(signature_size);
}
return signature;
}
std::vector<uint8_t> EccPrivateKey::GenerateSignature(
const std::vector<uint8_t>& message) const {
size_t signature_size = SignatureSize();
std::vector<uint8_t> signature(signature_size, 0);
const OEMCryptoResult res = GenerateSignature(
message.data(), message.size(), signature.data(), &signature_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to generate signature: result = %d", static_cast<int>(res));
signature.clear();
} else {
signature.resize(signature_size);
}
return signature;
}
size_t EccPrivateKey::SignatureSize() const { return ECDSA_size(key_); }
OEMCryptoResult EccPrivateKey::DeriveSessionKey(
const EccPublicKey& public_key, uint8_t* session_key,
size_t* session_key_size) const {
if (public_key.curve() != curve_) {
LOGE("Incompatible ECC keys: public = %s, private = %s",
EccCurveToString(public_key.curve()).c_str(),
EccCurveToString(curve_).c_str());
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (session_key_size == nullptr) {
LOGE("Output session key size buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (session_key == nullptr && *session_key_size > 0) {
LOGE("Output session key buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (*session_key_size < kEccSessionKeySize) {
*session_key_size = kEccSessionKeySize;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
const int res = ECDH_compute_key(
session_key, kEccSessionKeySize,
EC_KEY_get0_public_key(public_key.GetEcKey()), key_, WidevineEccKdf);
if (res < 0) {
LOGE("ECDH error occurred");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (static_cast<size_t>(res) != kEccSessionKeySize) {
LOGE("Unexpected key size: size = %d", res);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
*session_key_size = kEccSessionKeySize;
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> EccPrivateKey::DeriveSessionKey(
const EccPublicKey& public_key) const {
size_t session_key_size = kEccSessionKeySize;
std::vector<uint8_t> session_key(session_key_size, 0);
const OEMCryptoResult res =
DeriveSessionKey(public_key, session_key.data(), &session_key_size);
if (res != OEMCrypto_SUCCESS) {
LOGE("Failed to derive session key: result = %d", static_cast<int>(res));
session_key.clear();
} else {
session_key.resize(session_key_size);
}
return session_key;
}
size_t EccPrivateKey::SessionKeyLength() const { return kEccSessionKeySize; }
EccPrivateKey::~EccPrivateKey() {
if (key_ != nullptr) {
EC_KEY_free(key_);
key_ = nullptr;
}
curve_ = kEccCurveUnknown;
}
bool EccPrivateKey::InitFromBuffer(const uint8_t* buffer, size_t length) {
// Deserialize ECPrivateKey
const uint8_t* tp = buffer;
ScopedEcKey key(d2i_ECPrivateKey(nullptr, &tp, length));
if (!key) {
LOGE("Failed to parse key");
return false;
}
curve_ = GetCurveFromKeyGroup(key.get());
if (curve_ == kEccCurveUnknown) {
LOGE("Failed to determine key group");
return false;
}
// Required flags for IETF compliance.
EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED);
key_ = key.release();
return true;
}
bool EccPrivateKey::InitFromCurve(EccCurve curve) {
const EC_GROUP* group = GetEcGroup(curve);
if (group == nullptr) {
LOGE("Failed to get ECC group");
return false;
}
ScopedEcKey key(EC_KEY_new());
if (!key) {
LOGE("Failed to allocate key");
return false;
}
if (!EC_KEY_set_group(key.get(), group)) {
LOGE("Failed to set group");
return false;
}
// Generate random key.
if (!EC_KEY_generate_key(key.get())) {
LOGE("Failed to generate random key");
return false;
}
curve_ = curve;
// Required flags for IETF compliance.
EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED);
key_ = key.release();
return true;
}
} // namespace wvoec_ref

View File

@@ -1,245 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_ECC_KEY_H_
#define OEMCRYPTO_ECC_KEY_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include <openssl/ec.h>
#include "OEMCryptoCENCCommon.h"
namespace wvoec_ref {
enum EccCurve {
kEccCurveUnknown = 0,
kEccSecp256r1 = 256,
kEccSecp384r1 = 384,
kEccSecp521r1 = 521
};
// Returns the string representation of the provided curve.
// Intended for logging purposes.
std::string EccCurveToString(EccCurve curve);
class EccPrivateKey;
class EccPublicKey {
public:
// Creates a new public key equivalent of the provided private key.
static std::unique_ptr<EccPublicKey> New(const EccPrivateKey& private_key);
// Loads a serialized EC public key.
// The provided |buffer| must contain a valid ASN.1 DER encoded
// SubjectPublicKey. Only supported curves by this API are those
// enumerated by EccCurve.
//
// buffer: SubjectPublicKeyInfo = {
// algorithm: AlgorithmIdentifier = {
// algorithm: OID = id-ecPublicKey,
// parameters: ECParameters = {
// namedCurve: OID = secp256r1 | secp384r1 | secp521r1
// }
// },
// subjectPublicKey: BIT STRING = ... -- SEC1 encoded ECPoint
// }
//
// Failure will occur if the provided |buffer| does not contain a
// valid SubjectPublicKey, or if the specified curve is not
// supported.
static std::unique_ptr<EccPublicKey> Load(const uint8_t* buffer,
size_t length);
static std::unique_ptr<EccPublicKey> Load(const std::string& buffer);
static std::unique_ptr<EccPublicKey> Load(const std::vector<uint8_t>& buffer);
EccCurve curve() const { return curve_; }
const EC_KEY* GetEcKey() const { return key_; }
// Checks if the provided |private_key| is the EC private key of this
// public key.
bool IsMatchingPrivateKey(const EccPrivateKey& private_key) const;
// Serializes the public key into an ASN.1 DER encoded SubjectPublicKey
// representation.
// On success, |buffer_size| is populated with the number of bytes
// written to |buffer|, and OEMCrypto_SUCCESS is returned.
// If the provided |buffer_size| is too small, ERROR_SHORT_BUFFER
// is returned and |buffer_size| is set to the required buffer size.
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
// Same as above, except directly returns the serialized key.
// Returns an empty vector on error.
std::vector<uint8_t> Serialize() const;
// Verifies the |signature| matches the provided |message| by the
// private equivalent of this public key.
// The |signature| should be a valid ASN.1 DER encoded
// ECDSA-Sig-Value.
// This implementation uses ECDSA with the following digest
// algorithms for the supported curve types.
// - SHA-256 / secp256r1
// - SHA-384 / secp384r1 (optional support)
// - SHA-512 / secp521r1 (optional support)
// Returns:
// OEMCrypto_SUCCESS if signature is valid
// OEMCrypto_ERROR_SIGNATURE_FAILURE if the signature is invalid
// Any other result indicates an unexpected error
OEMCryptoResult VerifySignature(const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length) const;
OEMCryptoResult VerifySignature(const std::string& message,
const std::string& signature) const;
OEMCryptoResult VerifySignature(const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature) const;
~EccPublicKey();
EccPublicKey(const EccPublicKey&) = delete;
EccPublicKey(EccPublicKey&&) = delete;
const EccPublicKey& operator=(const EccPublicKey&) = delete;
EccPublicKey& operator=(EccPublicKey&&) = delete;
private:
EccPublicKey() {}
// Initializes the public key object using the provided |buffer|.
// In case of any failure, false is return and the key should be
// discarded.
bool InitFromBuffer(const uint8_t* buffer, size_t length);
// Initializes the public key object from a private.
bool InitFromPrivateKey(const EccPrivateKey& private_key);
// OpenSSL/BoringSSL implementation of an ECC key.
// As a public key, this will only have key point initialized.
EC_KEY* key_ = nullptr;
EccCurve curve_ = kEccCurveUnknown;
};
class EccPrivateKey {
public:
// Creates a new, pseudorandom ECC private key belonging to the
// curve specified.
static std::unique_ptr<EccPrivateKey> New(EccCurve curve);
// Loads a serialized ECC private key.
// The provided |buffer| must contain a valid ASN.1 DER encoded
// ECPrivateKey. Only supported curves by this API are those
// enumerated by EccCurve.
//
// buffer: ECPrivateKey = {
// version: INTEGER = ecPrivateKeyVer1,
// privateKey: OCTET STRING = ..., -- I2OSP of private key point
// parameters: ECParameters = {
// namedCurve: OID = secp256r1 | secp384r1 | secp521r1
// },
// publicKey: BIT STRING OPTIONAL = ... -- SEC1 encoded ECPoint
// }
// Note: If the public key is not included, then it is computed from
// the private key.
//
// Failure will occur if the provided |buffer| does not contain a
// valid ECPrivateKey, or if the specified curve is not supported.
static std::unique_ptr<EccPrivateKey> Load(const uint8_t* buffer,
size_t length);
static std::unique_ptr<EccPrivateKey> Load(const std::string& buffer);
static std::unique_ptr<EccPrivateKey> Load(
const std::vector<uint8_t>& buffer);
// Creates a new ECC public key of this private key.
// Equivalent to calling EccPublicKey::New with this private
// key.
std::unique_ptr<EccPublicKey> MakePublicKey() const;
EccCurve curve() const { return curve_; }
const EC_KEY* GetEcKey() const { return key_; }
// Checks if the provided |public_key| is the EC public key of this
// private key.
bool IsMatchingPublicKey(const EccPublicKey& public_key) const;
// Serializes the private key into an ASN.1 DER encoded ECPrivateKey
// representation.
// On success, |buffer_size| is populated with the number of bytes
// written to |buffer|, and SUCCESS is returned.
// If the provided |buffer_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is
// set to the required buffer size.
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
// Same as above, except directly returns the serialized key.
// Returns an empty vector on error.
std::vector<uint8_t> Serialize() const;
// Signs the provided |message| and serializes the signature
// point to |signature| as a ASN.1 DER encoded ECDSA-Sig-Value.
// This implementation uses ECDSA with the following digest
// algorithms for the supported curve types.
// - SHA-256 / secp256r1
// - SHA-384 / secp384r1 (optional support)
// - SHA-512 / secp521r1 (optional support)
// On success, |signature_length| is populated with the number of
// bytes written to |signature|, and SUCCESS is returned.
// If the provided |signature_length| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |signature_length|
// is set to the required signature size.
OEMCryptoResult GenerateSignature(const uint8_t* message,
size_t message_length, uint8_t* signature,
size_t* signature_length) const;
// Same as above, except directly returns the serialized signature.
// Returns an empty vector on error.
std::vector<uint8_t> GenerateSignature(
const std::vector<uint8_t>& message) const;
std::vector<uint8_t> GenerateSignature(const std::string& message) const;
// Returns an upper bound for the signature size. May be larger than
// the actual signature generated by GenerateSignature().
size_t SignatureSize() const;
// Derives the OEMCrypto session key used for deriving other keys.
// The provided public key must be of the same curve.
// On success, |session_key_size| is populated with the number of
// bytes written to |session_key|, and OEMCrypto_SUCCESS is returned.
// If the provided |session_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |session_key_size|
// is set to the required buffer size.
OEMCryptoResult DeriveSessionKey(const EccPublicKey& public_key,
uint8_t* session_key,
size_t* session_key_size) const;
// Same as above, except directly returns the derived key.
std::vector<uint8_t> DeriveSessionKey(const EccPublicKey& public_key) const;
// Returns the byte length of the symmetric key that would be derived
// by DeriveSymmetricKey().
size_t SessionKeyLength() const;
~EccPrivateKey();
EccPrivateKey(const EccPrivateKey&) = delete;
EccPrivateKey(EccPrivateKey&&) = delete;
const EccPrivateKey& operator=(const EccPrivateKey&) = delete;
EccPrivateKey& operator=(EccPrivateKey&&) = delete;
private:
EccPrivateKey() {}
// Initializes the public key object using the provided |buffer|.
// In case of any failure, false is return and the key should be
// discarded.
bool InitFromBuffer(const uint8_t* buffer, size_t length);
// Generates a new key based on the provided curve.
bool InitFromCurve(EccCurve curve);
// OpenSSL/BoringSSL implementation of an ECC key.
// The public point of the key will always be present.
EC_KEY* key_ = nullptr;
EccCurve curve_ = kEccCurveUnknown;
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_EC_KEY_H_

View File

@@ -1,19 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_engine_ref.h"
#include <utility>
namespace wvoec_ref {
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::unique_ptr<wvcdm::FileSystem>&& file_system) {
return new CryptoEngine(std::move(file_system));
}
} // namespace wvoec_ref

View File

@@ -1,40 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
// This file contains oemcrypto engine properties that would be for a
// level 1 device.
#include "oemcrypto_engine_ref.h"
#include <utility>
namespace wvoec_ref {
class L1CryptoEngine : public CryptoEngine {
public:
explicit L1CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system)
: CryptoEngine(std::move(file_system)) {}
bool config_local_display_only() { return true; }
OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() {
return HDCP_V2;
}
bool config_is_anti_rollback_hw_present() { return true; }
const char* config_security_level() { return "L1"; }
// This should start at 0, and be incremented only when a security patch has
// been applied to the device that fixes a security bug.
uint8_t config_security_patch_level() { return 3; }
};
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::unique_ptr<wvcdm::FileSystem>&& file_system) {
return new L1CryptoEngine(std::move(file_system));
}
} // namespace wvoec_ref

View File

@@ -1,37 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
// This file contains oemcrypto engine properties that would be for a device
// that does not have persistant storage or a keybox.
//
// Note: We also define it to be L2 for illustration only. Production devices
// are rarely level 2.
#include "oemcrypto_engine_ref.h"
namespace wvoec_ref {
class CertOnlyCryptoEngine : public CryptoEngine {
public:
explicit CertOnlyCryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system)
: CryptoEngine(std::move(file_system)) {}
bool config_local_display_only() { return true; }
bool config_supports_usage_table() { return false; }
OEMCrypto_ProvisioningMethod config_provisioning_method() {
return OEMCrypto_DrmCertificate;
}
const char* config_security_level() { return "L2"; }
};
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::unique_ptr<wvcdm::FileSystem>&& file_system) {
return new CertOnlyCryptoEngine(std::move(file_system));
}
} // namespace wvoec_ref

View File

@@ -1,70 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
// This file contains oemcrypto engine properties that would be for a
// level 2 device that does not have persistant storage or a keybox.
// Note: this is for illustration only. Production devices are rarely level 2.
#include "oemcrypto_engine_ref.h"
#include <string.h>
#include <utility>
#include "log.h"
#include "oem_cert.h"
namespace wvoec_ref {
class Prov30CryptoEngine : public CryptoEngine {
public:
explicit Prov30CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system)
: CryptoEngine(std::move(file_system)) {}
bool Initialize() override {
if (!CryptoEngine::Initialize()) {
return false;
}
const OEMCryptoResult result = InstallOemCertificate(
kOEMPrivateKey, kOEMPrivateKeySize, kOEMPublicCert, kOEMPublicCertSize);
return result == OEMCrypto_SUCCESS;
}
bool config_local_display_only() { return true; }
// Returns the max HDCP version supported.
OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() {
return HDCP_NO_DIGITAL_OUTPUT;
}
// Returns true if the client supports persistent storage of
// offline usage table information.
bool config_supports_usage_table() {
return false;
}
// Returns true if the client uses a keybox as the root of trust.
bool config_supports_keybox() {
return false;
}
// This version uses an OEM Certificate.
OEMCrypto_ProvisioningMethod config_provisioning_method() {
return OEMCrypto_OEMCertificate;
}
// Returns "L3" for a software only library. L1 is for hardware protected
// keys and data paths. L2 is for hardware protected keys but no data path
// protection.
const char* config_security_level() { return "L2"; }
};
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::unique_ptr<wvcdm::FileSystem>&& file_system) {
return new Prov30CryptoEngine(std::move(file_system));
}
} // namespace wvoec_ref

View File

@@ -1,279 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_engine_ref.h"
#include <assert.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
#include <openssl/aes.h>
#include <openssl/err.h>
#include "clock.h"
#include "keys.h"
#include "log.h"
#include "oemcrypto_key_ref.h"
#include "string_conversions.h"
namespace {
// Lower bits in SessionId are actual session id. The rest higher bits are
// session type.
const uint32_t kSessionIdTypeShift = 28;
const uint32_t kSessionIdMask = (1u << kSessionIdTypeShift) - 1u;
} // namespace
namespace wvoec_ref {
// Note: The class CryptoEngine is configured at compile time by compiling in
// different device property files. The methods in this file are generic to
// all configurations. See the files oemcrypto_engine_device_properties*.cpp
// for methods that are configured for specific configurations.
CryptoEngine::CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system)
: file_system_(std::move(file_system)), usage_table_() {
ERR_load_crypto_strings();
}
CryptoEngine::~CryptoEngine() {
ERR_free_strings();
}
bool CryptoEngine::Initialize() {
std::string file_path = GetUsageTimeFileFullPath();
LoadOfflineTimeInfo(file_path);
usage_table_.reset(MakeUsageTable());
return root_of_trust_.Initialize(config_provisioning_method());
}
void CryptoEngine::Terminate() {
std::string file_path = GetUsageTimeFileFullPath();
SaveOfflineTimeInfo(file_path);
std::unique_lock<std::mutex> lock(session_table_lock_);
ActiveSessions::iterator it;
for (it = sessions_.begin(); it != sessions_.end(); ++it) {
delete it->second;
}
sessions_.clear();
root_of_trust_.Clear();
}
SessionId CryptoEngine::OpenSession() {
std::unique_lock<std::mutex> lock(session_table_lock_);
static OEMCrypto_SESSION unique_id = 1;
SessionId id = ++unique_id;
// Check if too many sessions have been opened.
if (SessionTypeBits(id) != 0) {
return 0;
}
// Apply session type to higher bits.
id = (kSessionTypeOEMCrypto << kSessionIdTypeShift) | (id & kSessionIdMask);
sessions_[id] = MakeSession(id);
return id;
}
SessionContext* CryptoEngine::MakeSession(SessionId sid) {
if (root_of_trust_.HasDrmCertKey()) {
return new SessionContext(this, sid, root_of_trust_.ShareDrmCertKey());
}
return new SessionContext(this, sid);
}
UsageTable* CryptoEngine::MakeUsageTable() { return new UsageTable(this); }
bool CryptoEngine::DestroySession(SessionId sid) {
SessionContext* sctx = FindSession(sid);
std::unique_lock<std::mutex> lock(session_table_lock_);
if (sctx) {
sessions_.erase(sid);
delete sctx;
return true;
} else {
return false;
}
}
SessionContext* CryptoEngine::FindSession(SessionId sid) {
std::unique_lock<std::mutex> lock(session_table_lock_);
ActiveSessions::iterator it = sessions_.find(sid);
if (it != sessions_.end()) {
return it->second;
}
return nullptr;
}
int64_t CryptoEngine::MonotonicTime() {
// Use the monotonic clock for times that don't have to be stable across
// device boots.
int64_t now =
wvcdm::Clock().GetCurrentTime() + offline_time_info_.rollback_offset;
static int64_t then = now;
if (now < then) {
LOGW("Clock rollback detected: %ld seconds", then - now);
offline_time_info_.rollback_offset += then - now;
now = then;
}
then = now;
return now;
}
int64_t CryptoEngine::SystemTime() {
const int64_t current_time = MonotonicTime();
// Write time info to disk if kTimeInfoUpdateWindowInSeconds has elapsed since
// last write.
if (current_time - offline_time_info_.previous_time >
kTimeInfoUpdateWindowInSeconds) {
std::string file_path = GetUsageTimeFileFullPath();
SaveOfflineTimeInfo(file_path);
}
return current_time;
}
std::string CryptoEngine::GetUsageTimeFileFullPath() const {
std::string file_path;
// Note: file path is OK for a real implementation, but using security
// level 1 would be better.
// TODO(fredgc, jfore): Address how this property is presented to the ref.
// For now, the file path is empty.
/*if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
&file_path)) {
LOGE("Unable to get base path");
}*/
return file_path + kStoredUsageTimeFileName;
}
bool CryptoEngine::LoadOfflineTimeInfo(const std::string& file_path) {
memset(&offline_time_info_, 0, sizeof(TimeInfo));
wvcdm::FileSystem* file_system = file_system_.get();
if (file_system->Exists(file_path)) {
std::unique_ptr<wvcdm::File> file =
file_system->Open(file_path, wvcdm::FileSystem::kReadOnly);
if (!file) {
// This error is expected at first initialization.
LOGE("File open failed (this is expected on first initialization): %s",
file_path.c_str());
return false;
}
// Load time info from previous call.
file->Read(reinterpret_cast<char*>(&offline_time_info_), sizeof(TimeInfo));
// Detect offline time rollback after loading from disk.
// Add any time offsets in the past to the current time.
int64_t current_time = MonotonicTime();
if (offline_time_info_.previous_time > current_time) {
// Current time is earlier than the previously saved time. Time has been
// rolled back. Update the rollback offset.
offline_time_info_.rollback_offset +=
offline_time_info_.previous_time - current_time;
// Keep current time at previous recorded time.
current_time = offline_time_info_.previous_time;
}
// The new previous_time will either stay the same or move forward.
offline_time_info_.previous_time = current_time;
}
return true;
}
bool CryptoEngine::SaveOfflineTimeInfo(const std::string& file_path) {
// Add any time offsets in the past to the current time. If there was an
// earlier offline rollback, the rollback offset will be updated in
// LoadOfflineTimeInfo(). It guarantees that the current time to be saved
// will never go back.
const int64_t current_time = MonotonicTime();
// The new previous_time will either stay the same or move forward.
if (current_time > offline_time_info_.previous_time)
offline_time_info_.previous_time = current_time;
std::unique_ptr<wvcdm::File> file;
wvcdm::FileSystem* file_system = file_system_.get();
// Write the current time and offset to disk.
file = file_system->Open(
file_path, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
if (!file) {
LOGE("File open failed: %s", file_path.c_str());
return false;
}
file->Write(reinterpret_cast<char*>(&offline_time_info_), sizeof(TimeInfo));
return true;
}
bool CryptoEngine::NonceCollision(uint32_t nonce) {
for (const auto& session_pair : sessions_) {
const SessionContext* session = session_pair.second;
if (nonce == session->nonce()) return true;
}
return false;
}
OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() {
return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1;
}
OEMCrypto_HDCP_Capability CryptoEngine::config_maximum_hdcp_capability() {
return HDCP_NO_DIGITAL_OUTPUT;
}
OEMCryptoResult CryptoEngine::SetDestination(
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
uint8_t subsample_flags) {
size_t max_length = 0;
switch (out_description.type) {
case OEMCrypto_BufferType_Clear:
destination_ = out_description.buffer.clear.address;
max_length = out_description.buffer.clear.address_length;
break;
case OEMCrypto_BufferType_Secure:
if (out_description.buffer.secure.handle_length <
out_description.buffer.secure.offset) {
LOGE("Secure buffer offset too large: %zu < %zu",
out_description.buffer.secure.handle_length,
out_description.buffer.secure.offset);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
destination_ =
reinterpret_cast<uint8_t*>(out_description.buffer.secure.handle) +
out_description.buffer.secure.offset;
max_length = out_description.buffer.secure.handle_length -
out_description.buffer.secure.offset;
break;
case OEMCrypto_BufferType_Direct:
// Direct buffer type is only used on some specialized devices where
// oemcrypto has a direct connection to the screen buffer. It is not,
// for example, supported on Android.
destination_ = nullptr;
break;
default:
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const size_t max_allowed = max_sample_size();
if (max_allowed > 0 &&
(max_allowed < max_length || max_allowed < data_length)) {
LOGE("Output too large (or buffer too small).");
return OEMCrypto_ERROR_OUTPUT_TOO_LARGE;
}
if (out_description.type != OEMCrypto_BufferType_Direct &&
max_length < data_length) {
LOGE("[SetDestination(): OEMCrypto_ERROR_SHORT_BUFFER]");
return OEMCrypto_ERROR_SHORT_BUFFER;
}
adjust_destination(out_description, data_length, subsample_flags);
if ((out_description.type != OEMCrypto_BufferType_Direct) &&
(destination_ == nullptr)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return OEMCrypto_SUCCESS;
}
uint32_t CryptoEngine::SessionTypeBits(SessionId sid) {
return sid >> kSessionIdTypeShift;
}
} // namespace wvoec_ref

View File

@@ -1,271 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef REF_OEMCRYPTO_ENGINE_REF_H_
#define REF_OEMCRYPTO_ENGINE_REF_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <mutex>
#include <vector>
#include "OEMCryptoCENC.h"
#include "file_store.h"
#include "oemcrypto_auth_ref.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_session.h"
#include "oemcrypto_types.h"
#include "oemcrypto_usage_table_ref.h"
namespace wvoec_ref {
typedef std::map<SessionId, SessionContext*> ActiveSessions;
static const std::string kStoredUsageTimeFileName = "StoredUsageTime.dat";
typedef struct {
// The max time recorded
int64_t previous_time;
// If the wall time is rollbacked to before the previous_time, this member
// is updated to reflect the offset.
int64_t rollback_offset;
// Pad the struct so that TimeInfo is a multiple of 16.
uint8_t padding[16 - (2 * sizeof(time_t)) % 16];
} TimeInfo;
// Session types are higher (32 - kSessionIdTypeShift) bits in SessionId.
typedef enum SessionType {
kSessionTypeOEMCrypto = 0,
kSessionTypeEntitledKey = 1,
} SessionType;
class CryptoEngine {
public:
static const uint32_t kApiVersion = 16;
static const uint32_t kMinorApiVersion = 3;
static const int64_t kTimeInfoUpdateWindowInSeconds = 300;
// This is like a factory method, except we choose which version to use at
// compile time. It is defined in several source files. The build system
// should choose which one to use by only linking in the correct one.
// NOTE: The caller must instantiate a FileSystem object - ownership
// will be transferred to the new CryptoEngine object.
static CryptoEngine* MakeCryptoEngine(
std::unique_ptr<wvcdm::FileSystem>&& file_system);
virtual ~CryptoEngine();
virtual bool Initialize();
bool ValidRootOfTrust() const { return root_of_trust_.IsValid(); }
OEMCryptoResult InstallKeybox(const uint8_t* keybox, size_t keybox_length) {
return root_of_trust_.InstallKeybox(keybox, keybox_length);
}
OEMCryptoResult InstallTestKeybox(const uint8_t* keybox_data,
size_t keybox_length) {
return root_of_trust_.InstallTestKeybox(keybox_data, keybox_length);
}
OEMCryptoResult LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); }
OEMCryptoResult IsKeyboxOrOemCertValid() const {
return root_of_trust_.IsKeyboxOrOemCertValid();
}
std::vector<uint8_t> DeviceRootKey() const {
return root_of_trust_.DeviceKey();
}
OEMCryptoResult GetDeviceRootId(uint8_t* device_id,
size_t* device_id_length) const {
return root_of_trust_.GetDeviceId(device_id, device_id_length);
}
std::vector<uint8_t> DeviceRootId() const {
return root_of_trust_.DeviceId();
}
OEMCryptoResult GetRootKeyData(uint8_t* key_data,
size_t* key_data_length) const {
return root_of_trust_.GetKeyData(key_data, key_data_length);
}
OEMCryptoResult InstallOemCertificate(const uint8_t* private_key,
size_t private_key_size,
const uint8_t* public_cert,
size_t public_cert_size) {
return root_of_trust_.InstallOemCertificate(private_key, private_key_size,
public_cert, public_cert_size);
}
OEMCryptoResult GetOemPublicCertificate(uint8_t* public_cert,
size_t* public_cert_length) const {
return root_of_trust_.GetOemPublicCertificate(public_cert,
public_cert_length);
}
std::shared_ptr<RsaPrivateKey> ShareOemPrivateKey() {
return root_of_trust_.ShareOemCertKey();
}
bool HasOemPrivateKey() const { return root_of_trust_.HasOemCertKey(); }
virtual void Terminate();
virtual SessionId OpenSession();
virtual bool DestroySession(SessionId sid);
SessionContext* FindSession(SessionId sid);
size_t GetNumberOfOpenSessions() { return sessions_.size(); }
size_t GetMaxNumberOfSessions() {
// An arbitrary limit for ref implementation.
static const size_t kMaxSupportedOEMCryptoSessions = 64;
return kMaxSupportedOEMCryptoSessions;
}
// The OEMCrypto system time. Prevents time rollback.
int64_t SystemTime();
// Verify that this nonce does not collide with another nonce in any session.
virtual bool NonceCollision(uint32_t nonce);
// Returns the HDCP version currently in use.
virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability();
// Returns the max HDCP version supported.
virtual OEMCrypto_HDCP_Capability config_maximum_hdcp_capability();
// Return true if there might be analog video output enabled.
virtual bool analog_display_active() { return !config_local_display_only(); }
// Return true if there is an analog display, and CGMS A is turned on.
virtual bool cgms_a_active() { return false; }
// Return the analog output flags.
virtual uint32_t analog_output_flags() {
return config_local_display_only() ? OEMCrypto_No_Analog_Output
: OEMCrypto_Supports_Analog_Output;
}
UsageTable& usage_table() { return *(usage_table_.get()); }
wvcdm::FileSystem* file_system() { return file_system_.get(); }
// If config_local_display_only() returns true, we pretend we are using a
// built-in display, instead of HDMI or WiFi output.
virtual bool config_local_display_only() { return false; }
// A closed platform is permitted to use clear buffers.
virtual bool config_closed_platform() { return false; }
// Returns true if the client supports persistent storage of
// offline usage table information.
virtual bool config_supports_usage_table() { return true; }
virtual OEMCrypto_ProvisioningMethod config_provisioning_method() {
return OEMCrypto_Keybox;
}
// Used for OEMCrypto_IsAntiRollbackHwPresent.
virtual bool config_is_anti_rollback_hw_present() { return false; }
// Returns "L3" for a software only library. L1 is for hardware protected
// data paths.
virtual const char* config_security_level() { return "L3"; }
// This should start at 0, and be incremented only when a security patch has
// been applied to the device that fixes a security bug.
virtual uint8_t config_security_patch_level() { return 0; }
// If 0 no restriction, otherwise it's the max subsample size for
// DecryptCENC. This is not the same as the max sample or buffer size.
virtual size_t max_subsample_size() { return 4 * 1024 * 1024; } // 4 MiB
// If 0 no restriction, otherwise it's the max sample size for DecryptCENC.
// This is the same as the max input and output buffer size for DecryptCENC
// and CopyBuffer. It is not the same as the max subsample size.
virtual size_t max_sample_size() { return 16 * 1024 * 1024; } // 16 MiB
virtual bool srm_update_supported() { return false; }
virtual OEMCryptoResult current_srm_version(uint16_t* version) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
virtual OEMCryptoResult load_srm(const uint8_t* buffer,
size_t buffer_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
virtual OEMCryptoResult remove_srm() {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
virtual bool srm_forbidden_device_attached() { return false; }
// Rate limit for nonce generation. Default to 200 nonce/second.
virtual int nonce_flood_count() { return 200; }
// Limit for size of usage table. If this is zero, then the
// size is unlimited -- or limited only by memory size.
virtual size_t max_usage_table_size() { return 0; }
virtual uint32_t resource_rating() { return 1; }
// Set destination pointer based on the output destination description.
OEMCryptoResult SetDestination(
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
uint8_t subsample_flags);
// The current destination.
uint8_t* destination() { return destination_; }
// Subclasses can adjust the destination -- for use in testing.
virtual void adjust_destination(
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
uint8_t subsample_flags) {}
// Push destination buffer to output -- used by subclasses for testing.
virtual OEMCryptoResult PushDestination(
const OEMCrypto_DestBufferDesc& out_description,
uint8_t subsample_flags) {
return OEMCrypto_SUCCESS;
}
// Get the session type bits from |sid|.
static uint32_t SessionTypeBits(SessionId sid);
protected:
// System clock, measuring time in seconds, including anti-rollback offset.
int64_t MonotonicTime();
bool LoadOfflineTimeInfo(const std::string& file_path);
bool SaveOfflineTimeInfo(const std::string& file_path);
std::string GetUsageTimeFileFullPath() const;
explicit CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system);
virtual SessionContext* MakeSession(SessionId sid);
virtual UsageTable* MakeUsageTable();
uint8_t* destination_;
ActiveSessions sessions_;
AuthenticationRoot root_of_trust_;
std::mutex session_table_lock_;
std::unique_ptr<wvcdm::FileSystem> file_system_;
std::unique_ptr<UsageTable> usage_table_;
TimeInfo offline_time_info_;
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
};
} // namespace wvoec_ref
#endif // REF_OEMCRYPTO_ENGINE_REF_H_

View File

@@ -1,71 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_key_ref.h"
#include "oemcrypto_types.h"
#include <string.h>
#include <vector>
#include "log.h"
namespace wvoec_ref {
bool KeyControlBlock::Validate() {
if (memcmp(verification_, "kctl", 4) && // original verification
memcmp(verification_, "kc09", 4) && // add in version 9 api
memcmp(verification_, "kc10", 4) && // add in version 10 api
memcmp(verification_, "kc11", 4) && // add in version 11 api
memcmp(verification_, "kc12", 4) && // add in version 12 api
memcmp(verification_, "kc13", 4) && // add in version 13 api
memcmp(verification_, "kc14", 4) && // add in version 14 api
memcmp(verification_, "kc15", 4) && // add in version 15 api
memcmp(verification_, "kc16", 4)) { // add in version 16 api
LOGE("KCB: BAD verification string: %4.4s", verification_);
valid_ = false;
} else {
valid_ = true;
}
return valid_;
}
// This extracts 4 bytes in network byte order to a 32 bit integer in
// host byte order.
uint32_t KeyControlBlock::ExtractField(const std::vector<uint8_t>& str,
int idx) {
int bidx = idx * 4;
uint32_t t = static_cast<unsigned char>(str[bidx]) << 24;
t |= static_cast<unsigned char>(str[bidx + 1]) << 16;
t |= static_cast<unsigned char>(str[bidx + 2]) << 8;
t |= static_cast<unsigned char>(str[bidx + 3]);
return t;
}
KeyControlBlock::KeyControlBlock(
const std::vector<uint8_t>& key_control_string) {
if (key_control_string.size() < wvoec::KEY_CONTROL_SIZE) {
LOGE("KCB: BAD Size: %zu (not %zu)", key_control_string.size(),
wvoec::KEY_CONTROL_SIZE);
return;
}
memcpy(verification_, &key_control_string[0], 4);
duration_ = ExtractField(key_control_string, 1);
nonce_ = ExtractField(key_control_string, 2);
control_bits_ = ExtractField(key_control_string, 3);
Validate();
}
void Key::UpdateDuration(const KeyControlBlock& control) {
control_.set_duration(control.duration());
}
void KeyControlBlock::RequireLocalDisplay() {
// Set all bits to require HDCP Local Display Only.
control_bits_ |= wvoec::kControlHDCPVersionMask;
}
} // namespace wvoec_ref

View File

@@ -1,87 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_KEY_REF_H_
#define OEMCRYPTO_KEY_REF_H_
#include <stdint.h>
#include <string>
#include <vector>
namespace wvoec_ref {
class KeyControlBlock {
public:
KeyControlBlock(const std::vector<uint8_t>& key_control_string);
~KeyControlBlock() {}
bool Validate();
void Invalidate() { valid_ = false; }
bool valid() const { return valid_; }
uint32_t duration() const { return duration_; }
void set_duration(uint32_t duration) { duration_ = duration; }
uint32_t nonce() const { return nonce_; }
const char* verification() const { return verification_; }
uint32_t control_bits() const { return control_bits_; }
void RequireLocalDisplay();
private:
uint32_t ExtractField(const std::vector<uint8_t>& str, int idx);
bool valid_;
char verification_[4];
uint32_t duration_;
uint32_t nonce_;
uint32_t control_bits_;
};
// AES-128 crypto key, or HMAC signing key.
class Key {
public:
Key(const Key& key)
: value_(key.value_), control_(key.control_), ctr_mode_(key.ctr_mode_) {}
Key(const std::vector<uint8_t>& key_string, const KeyControlBlock& control)
: value_(key_string), control_(control), ctr_mode_(true){};
virtual ~Key() {};
void UpdateDuration(const KeyControlBlock& control);
virtual const std::vector<uint8_t>& value() const { return value_; }
const KeyControlBlock& control() const { return control_; }
bool ctr_mode() const { return ctr_mode_; }
void set_ctr_mode(bool ctr_mode) { ctr_mode_ = ctr_mode; }
private:
std::vector<uint8_t> value_;
KeyControlBlock control_;
bool ctr_mode_;
};
// AES-256 entitlement key. |Key| holds the entitlement key. |EntitlementKey|
// holds the content key.
class EntitlementKey : public Key {
public:
EntitlementKey(const Key& key) : Key(key) {}
~EntitlementKey() override {}
const std::vector<uint8_t>& value() const override { return content_key_; }
const std::vector<uint8_t>& content_key() { return content_key_; }
const std::vector<uint8_t>& content_key_id() { return content_key_id_; }
const std::vector<uint8_t>& entitlement_key() { return Key::value(); }
bool SetContentKey(const std::vector<uint8_t>& content_key_id,
const std::vector<uint8_t>& content_key) {
content_key_.assign(content_key.begin(), content_key.end());
content_key_id_.assign(content_key_id.begin(), content_key_id.end());
return true;
}
private:
std::vector<uint8_t> content_key_;
std::vector<uint8_t> content_key_id_;
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_KEY_REF_H_

View File

@@ -1,129 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_keybox_ref.h"
#include <string.h>
#include <cstdint>
#include <string>
#include "log.h"
#include "oemcrypto_types.h"
#include "platform.h"
#include "wvcrc32.h"
namespace wvoec_ref {
namespace {
constexpr size_t kKeyboxSize = 128;
constexpr size_t kDeviceIdSize = 32;
constexpr size_t kKeyDataSize = 72;
constexpr size_t kMagicOffset = 120;
const uint8_t kMagic[4] = {'k', 'b', 'o', 'x'};
constexpr size_t kCrcKeyboxSize = 124;
constexpr size_t kCrcOffset = 124;
static_assert(sizeof(wvoec::WidevineKeybox) == kKeyboxSize,
"Unexpected keybox size");
template <size_t N>
std::vector<uint8_t> ToVector(const uint8_t (&field)[N]) {
return std::vector<uint8_t>(field, &field[N]);
}
} // namespace
// static
OEMCryptoResult WvKeybox::ValidateData(const uint8_t* keybox,
size_t keybox_length) {
if (keybox == nullptr) {
LOGE("Keybox data buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (keybox_length != kKeyboxSize) {
LOGE("Invalid keybox length: length = %zu", keybox_length);
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
if (memcmp(&keybox[kMagicOffset], kMagic, sizeof(kMagic))) {
LOGE("Invalid keybox magic");
return OEMCrypto_ERROR_BAD_MAGIC;
}
uint32_t crc_provided;
memcpy(&crc_provided, &keybox[kCrcOffset], sizeof(crc_provided));
const uint32_t crc_computed = wvcrc32n(keybox, kCrcKeyboxSize);
if (crc_provided != crc_computed) {
LOGE("Invalid keybox CRC: provided = %08x, computed = %08x", crc_provided,
crc_computed);
return OEMCrypto_ERROR_BAD_CRC;
}
return OEMCrypto_SUCCESS;
}
// static
std::unique_ptr<WvKeybox> WvKeybox::Create(const uint8_t* keybox_data,
size_t keybox_length) {
std::unique_ptr<WvKeybox> keybox;
if (keybox_length != kKeyboxSize) {
LOGE("Invalid keybox length: length = %zu", keybox_length);
return keybox;
}
keybox.reset(new WvKeybox());
memcpy(reinterpret_cast<uint8_t*>(&keybox->raw_keybox_), keybox_data,
kKeyboxSize);
return keybox;
}
OEMCryptoResult WvKeybox::GetDeviceId(uint8_t* device_id,
size_t* device_id_length) const {
if (device_id_length == nullptr) {
LOGE("Output device ID length buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (device_id == nullptr && *device_id_length > 0) {
LOGE("Output device ID buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (*device_id_length < kDeviceIdSize) {
*device_id_length = kDeviceIdSize;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*device_id_length = kDeviceIdSize;
memcpy(device_id, raw_keybox_.device_id_, kDeviceIdSize);
return OEMCrypto_SUCCESS;
}
std::vector<uint8_t> WvKeybox::DeviceId() const {
return ToVector(raw_keybox_.device_id_);
}
std::vector<uint8_t> WvKeybox::DeviceKey() const {
return ToVector(raw_keybox_.device_key_);
}
OEMCryptoResult WvKeybox::GetKeyData(uint8_t* key_data,
size_t* key_data_length) const {
if (key_data_length == nullptr) {
LOGE("Output key data length buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (key_data == nullptr && *key_data_length > 0) {
LOGE("Output key data buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (*key_data_length < kKeyDataSize) {
*key_data_length = kKeyDataSize;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*key_data_length = kKeyDataSize;
memcpy(key_data, raw_keybox_.data_, kKeyDataSize);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WvKeybox::IsKeyboxValid() const {
return ValidateData(reinterpret_cast<const uint8_t*>(&raw_keybox_),
kKeyboxSize);
}
} // namespace wvoec_ref

View File

@@ -1,66 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_KEYBOX_REF_H_
#define OEMCRYPTO_KEYBOX_REF_H_
#include <memory>
#include <vector>
#include "OEMCryptoCENCCommon.h"
#include "oemcrypto_types.h"
namespace wvoec_ref {
// Widevine keybox
class WvKeybox {
public:
// Validates keybox data using the following rules:
// 1. Data is not null
// 2. Keybox size
// 3. Matching magic
// 4. CRC-32 check
static OEMCryptoResult ValidateData(const uint8_t* keybox_data,
size_t keybox_length);
// Creates a keybox from the provided keybox data.
// Provided keybox data must be the proper length, but does
// not need to be valid.
// Once created, keyboxes are immutable.
static std::unique_ptr<WvKeybox> Create(const uint8_t* keybox_data,
size_t keybox_length);
// Gets the device ID from the keybox.
// Similar to the expected behavior of OEMCrypto_GetDeviceID().
OEMCryptoResult GetDeviceId(uint8_t* device_id,
size_t* device_id_length) const;
// Returns the keybox device ID directly. Intended to be used
// for core message generation.
std::vector<uint8_t> DeviceId() const;
// Returns the keybox device key directly. Intended to be used
// for key derivation.
std::vector<uint8_t> DeviceKey() const;
// Gets the keybox data.
// Similar to the expected behavior of OEMCrypto_GetKeyData().
OEMCryptoResult GetKeyData(uint8_t* key_data, size_t* key_data_length) const;
// Checks the current keybox instantiation that it is valid.
// Similar to the expected behavior of OEMCrypto_IsKeyboxValid().
OEMCryptoResult IsKeyboxValid() const;
~WvKeybox() {}
private:
WvKeybox() {}
wvoec::WidevineKeybox raw_keybox_;
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_KEYBOX_REF_H_

View File

@@ -1,233 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_oem_cert.h"
#include <string.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include "log.h"
#include "oemcrypto_rsa_key.h"
#include "scoped_object.h"
namespace wvoec_ref {
namespace {
using ScopedCertificate = ScopedObject<X509, X509_free>;
using ScopedEvpKey = ScopedObject<EVP_PKEY, EVP_PKEY_free>;
using ScopedPkcs7 = ScopedObject<PKCS7, PKCS7_free>;
constexpr size_t kExpectedCertCount = 2; // Leaf and intermediate.
constexpr int kDeviceCertIndex = 0;
// Checks that the |public_key| from an X.509 certificate is the
// correct public key of the serialized |private_key_data|.
OEMCryptoResult VerifyRsaKey(const RSA* public_key,
const std::vector<uint8_t>& private_key_data) {
if (public_key == nullptr) {
LOGE("RSA key is null");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
std::unique_ptr<RsaPrivateKey> private_key =
RsaPrivateKey::Load(private_key_data);
if (!private_key) {
LOGE("Failed to parse provided RSA private key");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (!RsaKeysAreMatchingPair(public_key, private_key->GetRsaKey())) {
LOGE("OEM certificate keys do not match");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
return OEMCrypto_SUCCESS;
}
} // namespace
// This utility class encapsulates the minimum functionality of an
// OEM Public Certificate required to verify a device's OEM Public
// Certificate.
class OemPublicCertificate {
public:
// Loads a PKCS #7 signedData message with certificate chain.
// Minimum validation is performed. Only checks that the
// device's public key is of a known type (RSA).
static std::unique_ptr<OemPublicCertificate> Load(const uint8_t* public_cert,
size_t public_cert_size) {
std::unique_ptr<OemPublicCertificate> oem_public_cert;
if (public_cert == nullptr) {
LOGE("Public cert buffer is null");
return oem_public_cert;
}
if (public_cert_size == 0) {
LOGE("Public cert buffer is empty");
return oem_public_cert;
}
oem_public_cert.reset(new OemPublicCertificate());
if (!oem_public_cert->InitFromBuffer(public_cert, public_cert_size)) {
oem_public_cert.reset();
}
return oem_public_cert;
}
OemCertificate::KeyType key_type() const { return key_type_; }
const std::vector<uint8_t>& cert_data() const { return cert_data_; }
const RSA* GetPublicRsaKey() const {
return EVP_PKEY_get0_RSA(device_public_key_.get());
}
~OemPublicCertificate() = default;
OemPublicCertificate(const OemPublicCertificate&) = delete;
OemPublicCertificate(OemPublicCertificate&&) = delete;
const OemPublicCertificate& operator=(const OemPublicCertificate&) = delete;
OemPublicCertificate& operator=(OemPublicCertificate&&) = delete;
private:
OemPublicCertificate() {}
bool InitFromBuffer(const uint8_t* public_cert, size_t public_cert_size) {
// Step 1: Parse the PKCS7 certificate chain as signedData.
const uint8_t* public_cert_ptr = public_cert;
pkcs7_.reset(d2i_PKCS7(nullptr, &public_cert_ptr, public_cert_size));
if (!pkcs7_) {
LOGE("Failed to parse PKCS#7 certificate chain");
return false;
}
if (!PKCS7_type_is_signed(pkcs7_.get())) {
LOGE("OEM Public Certificate is not PKCS#7 signed data");
return false;
}
PKCS7_SIGNED* signed_data = pkcs7_->d.sign;
// Step 2: Get the leaf certificate.
const size_t cert_count =
static_cast<size_t>(sk_X509_num(signed_data->cert));
if (cert_count != kExpectedCertCount) {
LOGE("Unexpected number of certificates: expected = %zu, actual = %zu",
kExpectedCertCount, cert_count);
return false;
}
X509* leaf_cert = sk_X509_value(signed_data->cert, kDeviceCertIndex);
// Step 3a: Get the device's public key.
device_public_key_.reset(X509_get_pubkey(leaf_cert));
if (!device_public_key_) {
LOGE("Device X.509 certificate is missing a public key");
return false;
}
// Step 3b: Check key type.
if (EVP_PKEY_get0_RSA(device_public_key_.get()) == nullptr) {
LOGE("Device public key is not RSA");
return false;
}
key_type_ = OemCertificate::kRsa;
cert_data_.assign(public_cert, public_cert + public_cert_size);
return true;
}
OemCertificate::KeyType key_type_ = OemCertificate::kNone;
// OpenSSL/BoringSSL's implementation of PKCS7 objects.
ScopedPkcs7 pkcs7_;
ScopedEvpKey device_public_key_;
std::vector<uint8_t> cert_data_;
};
// ===== ===== ===== OEM Certificate ===== ===== =====
// static
std::unique_ptr<OemCertificate> OemCertificate::Create(
const uint8_t* private_key_data, size_t private_key_size,
const uint8_t* public_cert_data, size_t public_cert_size) {
std::unique_ptr<OemCertificate> oem_cert;
// Step 1: Verify public cert is well-formed.
std::unique_ptr<OemPublicCertificate> oem_public_cert =
OemPublicCertificate::Load(public_cert_data, public_cert_size);
if (!oem_public_cert) {
LOGE("Invalid OEM Public Certificate");
return oem_cert;
}
// Step 2: Verify private key is well-formed.
switch (oem_public_cert->key_type()) {
case kRsa: {
std::unique_ptr<RsaPrivateKey> oem_private_key =
RsaPrivateKey::Load(private_key_data, private_key_size);
if (!oem_private_key) {
LOGE("Invalid OEM Private Key");
return oem_cert;
}
} break;
case kNone: // Suppress compiler warnings.
return oem_cert;
}
// Step 3: Copy over data.
oem_cert.reset(new OemCertificate());
oem_cert->private_key_.assign(private_key_data,
private_key_data + private_key_size);
oem_cert->public_cert_ = std::move(oem_public_cert);
return oem_cert;
}
// static
std::unique_ptr<OemCertificate> OemCertificate::Create(
const std::vector<uint8_t>& private_key,
const std::vector<uint8_t>& public_cert) {
if (private_key.empty()) {
LOGE("Private key buffer is empty");
return std::unique_ptr<OemCertificate>();
}
if (public_cert.empty()) {
LOGE("Public cert buffer is empty");
return std::unique_ptr<OemCertificate>();
}
return Create(private_key.data(), private_key.size(), public_cert.data(),
public_cert.size());
}
OemCertificate::KeyType OemCertificate::key_type() const {
return public_cert_->key_type();
}
OEMCryptoResult OemCertificate::GetPublicCertificate(
uint8_t* public_cert, size_t* public_cert_length) const {
if (public_cert_length == nullptr) {
LOGE("Output |public_cert_length| is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (public_cert == nullptr && *public_cert_length > 0) {
LOGE("Output |public_cert| is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const std::vector<uint8_t>& cert_data = public_cert_->cert_data();
if (*public_cert_length < cert_data.size()) {
*public_cert_length = cert_data.size();
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*public_cert_length = cert_data.size();
memcpy(public_cert, cert_data.data(), cert_data.size());
return OEMCrypto_SUCCESS;
}
const std::vector<uint8_t>& OemCertificate::GetPublicCertificate() const {
return public_cert_->cert_data();
}
OEMCryptoResult OemCertificate::IsCertificateValid() const {
switch (key_type()) {
case kRsa:
return VerifyRsaKey(public_cert_->GetPublicRsaKey(), private_key_);
case kNone: // Suppress compiler warnings.
break;
}
LOGE("Unexpected error key type: type = %d", static_cast<int>(key_type()));
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Constructor and destructor do not perform anything special, but
// must be declared within a scope which defines OemPublicCertificate.
OemCertificate::OemCertificate() {}
OemCertificate::~OemCertificate() {}
} // namespace wvoec_ref

View File

@@ -1,104 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_OEM_CERT_H_
#define OEMCRYPTO_OEM_CERT_H_
#include <memory>
#include <vector>
#include "OEMCryptoCENCCommon.h"
namespace wvoec_ref {
class OemPublicCertificate;
// An OEM Certificate is a factory provisioned root of trust
// certificate which consists of a public certificate and its
// matching private key.
// The public certificate must be an ASN.1 DER encoded PKCS #7
// ContentInfo of type signedData (RFC2315). The device's X.509
// certificate must be the first certificate in the chain of
// SignedContent |certificates|.
// The certificates are X.509 Certificate as defined in RFC 5280
// signed by the device manufacturers certificate which is signed
// by Google.
// The OEM Public Cert should only contain the device's certificate
// and the OEM's intermediate certificate.
// The private key storage format is at the discretion of the OEM;
// the reference implementation uses PKCS8 PrivateKeyInfo.
class OemCertificate {
public:
enum KeyType {
kNone = 0,
// Private key is an ASN.1 DER encoded PrivateKeyInfo specifying
// an RSA encryption key.
kRsa = 1
};
// Creates a new OEM Certificate and performs basic validation
// to ensure that the private key and public cert are well-formed.
// The |public_cert| provided is parsed as an X.509 Certificate
// and the public key is verified against the private key.
// The |private_key| is parsed depending on the key type.
// If any error occurs or if the provided data is malformed, an
// empty pointer is returned.
static std::unique_ptr<OemCertificate> Create(const uint8_t* private_key,
size_t private_key_size,
const uint8_t* public_cert,
size_t public_cert_size);
static std::unique_ptr<OemCertificate> Create(
const std::vector<uint8_t>& private_key,
const std::vector<uint8_t>& public_cert);
// Returns the key type of the OEM Public key and private key.
// As of OEMCrypto v16, the only supported key type is RSA.
KeyType key_type() const;
// Returns the private key data. Intended to be used for calls
// to OEMCrypto_LoadOEMPrivateKey().
const std::vector<uint8_t>& GetPrivateKey() const { return private_key_; }
// Returns a copy of the ASN.1 DER encoded PKCS #7 certificate chain.
// If |*public_cert_length| is large enough, the complete
// certificate is copied to the buffer specified by |public_cert|,
// |*public_cert_length| is adjusted to the actual size of the
// certificate data, and SUCCESS is returned.
// If |*public_cert_length| is not large enough, then it is
// set to size of the certificate and ERROR_SHORT_BUFFER is
// returned.
OEMCryptoResult GetPublicCertificate(uint8_t* public_cert,
size_t* public_cert_length) const;
// Returns the certificate directly. Intended to be used for
// testing.
const std::vector<uint8_t>& GetPublicCertificate() const;
// Verifies that the RSA key included in the OEM Cert is valid.
// The existence of an OemCertificate already ensures that the
// OEM Public Certificate and private key data are well-formed.
// This takes the check another step further and ensures that
// the private key matches the public key in the public cert
// (ie, same modulos and public exponent).
OEMCryptoResult IsCertificateValid() const;
~OemCertificate();
OemCertificate(const OemCertificate&) = delete;
OemCertificate(OemCertificate&&) = delete;
const OemCertificate& operator=(const OemCertificate&) = delete;
OemCertificate& operator=(OemCertificate&&) = delete;
private:
OemCertificate();
// Serialized private key matching the OEM certificate.
std::vector<uint8_t> private_key_;
// Serialized OEM Certificate.
std::unique_ptr<OemPublicCertificate> public_cert_;
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_OEM_CERT_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,359 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_RSA_KEY_H_
#define OEMCRYPTO_RSA_KEY_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include <openssl/rsa.h>
#include "OEMCryptoCENCCommon.h"
namespace wvoec_ref {
enum RsaFieldSize {
kRsaFieldUnknown = 0,
kRsa2048Bit = 2048,
kRsa3072Bit = 3084
};
// Identifies the RSA signature algorithm to be used when signing
// messages or verifying message signatures.
// The two standard signing algorithms specified by PKCS1 RSA V2.1
// are RSASSA-PKCS1 and RSASSA-PSS. Each require agreement on a
// set of options. For OEMCrypto, only one set of options are agreed
// upon for each RSA signature scheme. CAST receivers specify a
// special implementation of PKCS1 where the message is already
// digested and encoded when provided.
enum RsaSignatureAlgorithm {
// RSASSA-PSS with default options:
// Hash algorithm: SHA-1
// MGF: MGF1 with SHA-1
// Salt length: 20 bytes
// Trailer field: 0xbc
kRsaPssDefault = 0,
// RSASSA-PKCS1 for CAST receivers.
// Assumes message is already digested & encoded. Max message length
// is 83 bytes.
kRsaPkcs1Cast = 1
};
// Returns the string representation of the provided RSA field size.
// Intended for logging purposes.
std::string RsaFieldSizeToString(RsaFieldSize field_size);
// Compares two OpenSSL/BoringSSL RSA keys to see if their public RSA
// components are matching.
// This function assumes both keys are valid.
// Returns true if they are matching, false otherwise.
bool RsaKeysAreMatchingPair(const RSA* public_key, const RSA* private_key);
class RsaPrivateKey;
class RsaPublicKey {
public:
// Creates a new public key equivalent of the provided private key.
static std::unique_ptr<RsaPublicKey> New(const RsaPrivateKey& private_key);
// Loads a serialized RSA public key.
// The provided |buffer| must contain a valid ASN.1 DER encoded
// SubjectPublicKey. This API will reject any RSA key that is not
// approximately to 2048bits or 3072bits.
//
// buffer: SubjectPublicKeyInfo = {
// algorithm: AlgorithmIdentifier = {
// algorithm: OID = rsaEncryption,
// parameters: NULL = null
// },
// subjectPublicKey: BIT STRING = ... -- ASN.1 DER encoded RSAPublicKey
// }
//
// Failure will occur if the provided |buffer| does not contain a
// valid SubjectPublicKey, or if the specified curve is not
// supported.
static std::unique_ptr<RsaPublicKey> Load(const uint8_t* buffer,
size_t length);
static std::unique_ptr<RsaPublicKey> Load(const std::string& buffer);
static std::unique_ptr<RsaPublicKey> Load(const std::vector<uint8_t>& buffer);
RsaFieldSize field_size() const { return field_size_; }
uint32_t allowed_schemes() const { return allowed_schemes_; }
const RSA* GetRsaKey() const { return key_; }
// Checks if the provided |private_key| is the RSA private key of this
// public key.
bool IsMatchingPrivateKey(const RsaPrivateKey& private_key) const;
// Serializes the public key into an ASN.1 DER encoded SubjectPublicKey
// representation.
// On success, |buffer_size| is populated with the number of bytes
// written to |buffer|, and OEMCrypto_SUCCESS is returned.
// If the provided |buffer_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is set
// to the required buffer size.
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
// Same as above, except directly returns the serialized key.
// Returns an empty vector on error.
std::vector<uint8_t> Serialize() const;
// Verifies the |signature| matches the provided |message| by the
// private equivalent of this public key.
// The signature algorithm can be specified via the |algorithm| field.
// See RsaSignatureAlgorithm for details on each algorithm.
//
// Returns:
// OEMCrypto_SUCCESS if signature is valid
// OEMCrypto_ERROR_SIGNATURE_FAILURE if the signature is invalid
// OEMCrypto_ERROR_UNKNOWN_FAILURE if any error occurs
OEMCryptoResult VerifySignature(
const uint8_t* message, size_t message_length, const uint8_t* signature,
size_t signature_length,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
OEMCryptoResult VerifySignature(
const std::string& message, const std::string& signature,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
OEMCryptoResult VerifySignature(
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
// Encrypts the OEMCrypto session key used for deriving other keys.
// On success, |enc_session_key_size| is populated with the number
// of bytes written to |enc_session_key|, and OEMCrypto_SUCCESS is
// returned. If the provided |enc_session_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and
// |enc_session_key_size| is set to the required buffer size.
OEMCryptoResult EncryptSessionKey(const uint8_t* session_key,
size_t session_key_size,
uint8_t* enc_session_key,
size_t* enc_session_key_size) const;
// Same as above, except directly returns the encrypted key.
std::vector<uint8_t> EncryptSessionKey(
const std::vector<uint8_t>& session_key) const;
std::vector<uint8_t> EncryptSessionKey(const std::string& session_key) const;
// Encrypts the OEMCrypto encryption key used for encrypting the
// DRM private key.
// On success, |enc_encryption_key_size| is populated with the
// number of bytes written to |enc_encryption_key|, and
// OEMCrypto_SUCCESS is returned.
// If the provided |enc_encryption_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and
// |enc_encryption_key_size| is set to the required buffer size.
OEMCryptoResult EncryptEncryptionKey(const uint8_t* encryption_key,
size_t encryption_key_size,
uint8_t* enc_encryption_key,
size_t* enc_encryption_key_size) const;
// Same as above, except directly returns the encrypted key.
std::vector<uint8_t> EncryptEncryptionKey(
const std::vector<uint8_t>& encryption_key) const;
std::vector<uint8_t> EncryptEncryptionKey(
const std::string& encryption_key) const;
~RsaPublicKey();
RsaPublicKey(const RsaPublicKey&) = delete;
RsaPublicKey(RsaPublicKey&&) = delete;
const RsaPublicKey& operator=(const RsaPublicKey&) = delete;
RsaPublicKey& operator=(RsaPublicKey&&) = delete;
private:
RsaPublicKey() {}
// Initializes the public key object using the provided |buffer|.
// In case of any failure, false is return and the key should be
// discarded.
bool InitFromBuffer(const uint8_t* buffer, size_t length);
// Initializes the public key object from a private.
bool InitFromPrivateKey(const RsaPrivateKey& private_key);
// Signature specialization functions.
OEMCryptoResult VerifySignaturePss(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length) const;
OEMCryptoResult VerifySignaturePkcs1Cast(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length) const;
// RSAES-OAEP encrypt.
OEMCryptoResult EncryptOaep(const uint8_t* message, size_t message_size,
uint8_t* enc_message,
size_t* enc_message_length) const;
// OpenSSL/BoringSSL implementation of an RSA key.
// Will only include components of an RSA public key.
RSA* key_ = nullptr;
uint32_t allowed_schemes_ = 0;
RsaFieldSize field_size_ = kRsaFieldUnknown;
};
class RsaPrivateKey {
public:
// Creates a new, pseudorandom RSA private key.
static std::unique_ptr<RsaPrivateKey> New(RsaFieldSize field_size);
// Loads a serialized RSA private key.
// The provided |buffer| must contain a valid ASN.1 DER encoded
// PrivateKeyInfo (RFC 5208).
//
// buffer: PrivateKeyInfo = {
// version: INTEGER = v1(0),
// privateKeyAlgorithm: OID = rsaEncryption,
// privateKey: OCTET STRING = ...,
// -- BER encoding of RSAPrivateKey (RFC 3447)
// attributes: Attributes = ... -- Optional, not used by OEMCrypto
// }
// Note: If the public key is not included, then it is computed from
// the private.
//
// Failure will occur if the provided |buffer| does not contain a
// valid ECPrivateKey, or if the specified curve is not supported.
static std::unique_ptr<RsaPrivateKey> Load(const uint8_t* buffer,
size_t length);
static std::unique_ptr<RsaPrivateKey> Load(const std::string& buffer);
static std::unique_ptr<RsaPrivateKey> Load(
const std::vector<uint8_t>& buffer);
// Creates a new RSA public key of this private key.
// Equivalent to calling RsaPublicKey::New with this private
// key.
std::unique_ptr<RsaPublicKey> MakePublicKey() const;
RsaFieldSize field_size() const { return field_size_; }
uint32_t allowed_schemes() const { return allowed_schemes_; }
const RSA* GetRsaKey() const { return key_; }
// Checks if the provided |public_key| is the RSA public key of this
// private key.
bool IsMatchingPublicKey(const RsaPublicKey& public_key) const;
// Serializes the private key into an ASN.1 DER encoded X
// representation.
// On success, |buffer_size| is populated with the number of bytes
// written to |buffer|, and OEMCrypto_SUCCESS is returned.
// If the provided |buffer_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is
// set to the required buffer size.
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
// Same as above, except directly returns the serialized key.
// Returns an empty vector on error.
std::vector<uint8_t> Serialize() const;
// Signs the provided |message| using the RSA signing algorithm
// specified by |algorithm|. See RsaSignatureAlgorithm for
// details on each algorithm.
//
// On success, |signature_length| is populated with the number of
// bytes written to |signature|, and OEMCrypto_SUCCESS is returned.
// If the provided |signature_length| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |signature_length|
// is set to the required signature size.
OEMCryptoResult GenerateSignature(const uint8_t* message,
size_t message_length,
RsaSignatureAlgorithm algorithm,
uint8_t* signature,
size_t* signature_length) const;
// Same as above, except directly returns the serialized signature.
// Returns an empty vector on error.
std::vector<uint8_t> GenerateSignature(
const std::vector<uint8_t>& message,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
std::vector<uint8_t> GenerateSignature(
const std::string& message,
RsaSignatureAlgorithm algorithm = kRsaPssDefault) const;
// Returns an upper bound for the signature size. May be larger than
// the actual signature generated by GenerateSignature().
size_t SignatureSize() const;
// Decrypts the OEMCrypto session key used for deriving other keys.
// On success, |session_key_size| is populated with the number of
// bytes written to |session_key|, and OEMCrypto_SUCCESS is returned.
// If the provided |session_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |session_key_size|
// is set to the required buffer size.
OEMCryptoResult DecryptSessionKey(const uint8_t* enc_session_key,
size_t enc_session_key_size,
uint8_t* session_key,
size_t* session_key_size) const;
// Same as above, except directly returns the decrypted key.
std::vector<uint8_t> DecryptSessionKey(
const std::vector<uint8_t>& enc_session_key) const;
std::vector<uint8_t> DecryptSessionKey(
const std::string& enc_session_key) const;
// Returns the byte length of the symmetric key that would be derived
// by DecryptSessionKey().
size_t SessionKeyLength() const;
// Decrypts the OEMCrypto encryption key used for decrypting DRM
// private key.
// On success, |encryption_key_size| is populated with the number of
// bytes written to |encryption_key|, and OEMCrypto_SUCCESS is
// returned.
// If the provided |encryption_key_size| is too small,
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |encryption_key_size|
// is set to the required buffer size.
OEMCryptoResult DecryptEncryptionKey(const uint8_t* enc_encryption_key,
size_t enc_encryption_key_size,
uint8_t* encryption_key,
size_t* encryption_key_size) const;
// Same as above, except directly returns the decrypted key.
std::vector<uint8_t> DecryptEncryptionKey(
const std::vector<uint8_t>& enc_encryption_key) const;
std::vector<uint8_t> DecryptEncryptionKey(
const std::string& enc_encryption_key) const;
~RsaPrivateKey();
RsaPrivateKey(const RsaPrivateKey&) = delete;
RsaPrivateKey(RsaPrivateKey&&) = delete;
const RsaPrivateKey& operator=(const RsaPrivateKey&) = delete;
RsaPrivateKey& operator=(RsaPrivateKey&&) = delete;
private:
RsaPrivateKey() {}
// Initializes the public key object using the provided |buffer|.
// In case of any failure, false is return and the key should be
// discarded.
bool InitFromBuffer(const uint8_t* buffer, size_t length);
// Generates a new key based on the provided field size.
bool InitFromFieldSize(RsaFieldSize field_size);
// Signature specialization functions.
OEMCryptoResult GenerateSignaturePss(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length) const;
OEMCryptoResult GenerateSignaturePkcs1Cast(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length) const;
// RSAES-OAEP decrypt.
OEMCryptoResult DecryptOaep(const uint8_t* enc_message,
size_t enc_message_size, uint8_t* message,
size_t expected_message_length) const;
// OpenSSL/BoringSSL implementation of an RSA key.
// Will include all components of an RSA private key.
RSA* key_ = nullptr;
uint32_t allowed_schemes_ = 0;
// Set true if the deserialized key contained an allowed schemes.
bool explicit_schemes_ = false;
RsaFieldSize field_size_ = kRsaFieldUnknown;
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_RSA_KEY_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,312 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef REF_OEMCRYPTO_SESSION_H_
#define REF_OEMCRYPTO_SESSION_H_
#include <stdint.h>
#include <time.h>
#include <map>
#include <vector>
#include <openssl/rsa.h>
#include "OEMCryptoCENC.h"
#include "odk_structs.h"
#include "oemcrypto_auth_ref.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key.h"
#include "oemcrypto_session_key_table.h"
#include "oemcrypto_types.h"
#include "oemcrypto_usage_table_ref.h"
namespace wvoec_ref {
class CryptoEngine;
typedef uint32_t SessionId;
enum SRMVersionStatus { NoSRMVersion, ValidSRMVersion, InvalidSRMVersion };
// TODO(jfore): Is there a better name?
class SessionContextKeys {
public:
virtual OEMCrypto_LicenseType type() = 0;
virtual size_t size() = 0;
virtual bool Insert(const KeyId& key_id, const Key& key_data) = 0;
virtual Key* Find(const KeyId& key_id) = 0;
virtual Key* FirstKey() = 0;
virtual void Remove(const KeyId& key_id) = 0;
virtual void UpdateDuration(const KeyControlBlock& control) = 0;
// Methods supported exclusively for entitlement keys. Returns false if
// entitlement keys are not found or not supported by the current key table.
// It is the caller's responsibility to check the context.
virtual bool SetContentKey(const KeyId& entitlement_id,
const KeyId& content_key_id,
const std::vector<uint8_t>& content_key) = 0;
virtual EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) = 0;
virtual ~SessionContextKeys() {}
protected:
SessionContextKeys() {}
private:
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContextKeys);
};
class SessionContext {
public:
SessionContext(CryptoEngine* ce, SessionId sid);
SessionContext(CryptoEngine* ce, SessionId sid,
std::shared_ptr<RsaPrivateKey>&& rsa_key);
SessionContext() = delete;
virtual ~SessionContext();
bool isValid() const { return valid_; }
virtual OEMCryptoResult DeriveKeys(const std::vector<uint8_t>& master_key,
const std::vector<uint8_t>& mac_context,
const std::vector<uint8_t>& enc_context);
virtual OEMCryptoResult RSADeriveKeys(
const std::vector<uint8_t>& enc_session_key,
const std::vector<uint8_t>& mac_context,
const std::vector<uint8_t>& enc_context);
virtual OEMCryptoResult LoadOemPrivateKey();
virtual OEMCryptoResult PrepAndSignLicenseRequest(uint8_t* message,
size_t message_length,
size_t* core_message_length,
uint8_t* signature,
size_t* signature_length);
virtual OEMCryptoResult PrepAndSignRenewalRequest(uint8_t* message,
size_t message_length,
size_t* core_message_length,
uint8_t* signature,
size_t* signature_length);
virtual OEMCryptoResult PrepAndSignProvisioningRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
uint8_t* signature, size_t* signature_length);
// Restricted to CAST receivers using PKCS1 block padding only.
virtual OEMCryptoResult GenerateRSASignature(
const uint8_t* message, size_t message_length, uint8_t* signature,
size_t* signature_length, RSA_Padding_Scheme padding_scheme);
virtual bool ValidateMessage(const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length);
OEMCryptoResult DecryptSamples(
const OEMCrypto_SampleDescription* samples, size_t samples_length,
const OEMCrypto_CENCEncryptPatternDesc* pattern);
OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer,
size_t buffer_length, const uint8_t* iv,
OEMCrypto_Algorithm algorithm,
uint8_t* out_buffer);
OEMCryptoResult Generic_Decrypt(const uint8_t* in_buffer,
size_t buffer_length, const uint8_t* iv,
OEMCrypto_Algorithm algorithm,
uint8_t* out_buffer);
OEMCryptoResult Generic_Sign(const uint8_t* in_buffer, size_t buffer_length,
OEMCrypto_Algorithm algorithm,
uint8_t* signature, size_t* signature_length);
OEMCryptoResult Generic_Verify(const uint8_t* in_buffer, size_t buffer_length,
OEMCrypto_Algorithm algorithm,
const uint8_t* signature,
size_t signature_length);
virtual OEMCryptoResult LoadLicense(const uint8_t* message,
size_t message_length,
size_t core_message_length,
const uint8_t* signature,
size_t signature_length);
virtual OEMCryptoResult LoadKeys(
const uint8_t* message, size_t message_length, const uint8_t* signature,
size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv,
OEMCrypto_Substring enc_mac_keys, size_t num_keys,
const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst,
OEMCrypto_Substring srm_restriction_data,
OEMCrypto_LicenseType license_type);
virtual OEMCryptoResult LoadKeysNoSignature(
const uint8_t* message, size_t message_length,
OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys,
size_t num_keys, const OEMCrypto_KeyObject* key_array,
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
OEMCrypto_LicenseType license_type);
virtual OEMCryptoResult LoadEntitledContentKeys(
const uint8_t* message, size_t message_length, size_t key_array_length,
const OEMCrypto_EntitledContentKeyObject* key_array);
virtual OEMCryptoResult InstallKey(
const KeyId& key_id, const std::vector<uint8_t>& key_data,
const std::vector<uint8_t>& key_data_iv,
const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv);
bool InstallRSAEncryptedKey(const std::vector<uint8_t>& enc_encryption_key);
bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length,
const uint8_t* wrapped_rsa_key_iv, uint8_t* pkcs8_rsa_key);
bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key);
bool LoadRsaDrmKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length);
virtual OEMCryptoResult LoadRenewal(const uint8_t* message,
size_t message_length,
size_t core_message_length,
const uint8_t* signature,
size_t signature_length);
virtual OEMCryptoResult RefreshKey(
const KeyId& key_id, const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv);
virtual bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
const std::vector<uint8_t>& iv);
virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
virtual OEMCryptoResult SelectContentKey(const KeyId& key_id,
OEMCryptoCipherMode cipher_mode);
virtual OEMCryptoResult SetDecryptHash(uint32_t frame_number,
const uint8_t* hash,
size_t hash_length);
virtual OEMCryptoResult GetHashErrorCode(uint32_t* failed_frame_number);
const Key* current_content_key(void) { return current_content_key_; }
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
mac_key_server_ = mac_key_server;
}
const std::vector<uint8_t>& mac_key_server() { return mac_key_server_; }
void set_mac_key_client(const std::vector<uint8_t>& mac_key_client) {
mac_key_client_ = mac_key_client;
}
const std::vector<uint8_t>& mac_key_client() { return mac_key_client_; }
void set_encryption_key(const std::vector<uint8_t>& enc_key) {
encryption_key_ = enc_key;
}
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
// Return true if nonce was set.
bool set_nonce(uint32_t nonce);
uint32_t nonce() const { return nonce_values_.nonce; }
ODK_NonceValues& nonce_values() { return nonce_values_; }
bool CheckNonce(uint32_t nonce) const {
return nonce != 0 && nonce == nonce_values_.nonce;
};
virtual OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number);
virtual OEMCryptoResult LoadUsageEntry(uint32_t index,
const std::vector<uint8_t>& buffer);
virtual OEMCryptoResult UpdateUsageEntry(uint8_t* header_buffer,
size_t* header_buffer_length,
uint8_t* entry_buffer,
size_t* entry_buffer_length);
virtual OEMCryptoResult DeactivateUsageEntry(const std::vector<uint8_t>& pst);
virtual OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst,
uint8_t* buffer, size_t* buffer_length);
OEMCryptoResult MoveEntry(uint32_t new_index);
bool usage_entry_present() const { return usage_entry_ != nullptr; }
protected:
// Signature size of the currently loaded private key.
size_t CertSignatureSize() const;
// Signature size when using a keybox or OEM Cert's private key.
size_t ROTSignatureSize() const;
virtual OEMCryptoResult GenerateCertSignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
virtual OEMCryptoResult GenerateSignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
bool DeriveKey(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& context, int counter,
std::vector<uint8_t>* out);
bool DecryptMessage(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& message,
std::vector<uint8_t>* decrypted,
uint32_t key_size); // AES key size, in bits.
// Either verify the nonce or usage entry, as required by the key control
// block.
OEMCryptoResult CheckNonceOrEntry(const KeyControlBlock& key_control_block);
// If there is a usage entry, check that it is not inactive.
// It also updates the status of the entry if needed.
bool CheckUsageEntry();
// Check that the usage entry status is valid for online use.
OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control);
// Check that the usage entry status is valid for offline use.
OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control);
OEMCryptoResult DecryptSubsample(
const OEMCrypto_SubSampleDescription& subsample,
const uint8_t* cipher_data, uint8_t* clear_data,
OEMCryptoBufferType buffer_type, const uint8_t (&iv)[wvoec::KEY_IV_SIZE],
const OEMCrypto_CENCEncryptPatternDesc* pattern);
OEMCryptoResult ChooseDecrypt(const uint8_t* iv, size_t block_offset,
const OEMCrypto_CENCEncryptPatternDesc* pattern,
const uint8_t* cipher_data,
size_t cipher_data_length, uint8_t* clear_data,
OEMCryptoBufferType buffer_type);
OEMCryptoResult PatternDecryptCBC(
const uint8_t* key, const uint8_t* iv,
const OEMCrypto_CENCEncryptPatternDesc* pattern,
const uint8_t* cipher_data, size_t cipher_data_length,
uint8_t* clear_data);
OEMCryptoResult DecryptCTR(const uint8_t* key_u8, const uint8_t* iv,
size_t block_offset, const uint8_t* cipher_data,
size_t cipher_data_length, uint8_t* clear_data);
// Checks if the key is allowed for the specified type. If there is a usage
// entry, it also checks the usage entry.
OEMCryptoResult CheckKeyUse(const std::string& log_string, uint32_t use_type,
OEMCryptoBufferType buffer_type);
bool valid_ = false;
CryptoEngine* ce_ = nullptr;
SessionId id_;
// Message keys.
std::shared_ptr<RsaPrivateKey> rsa_key_;
std::vector<uint8_t> mac_key_server_;
std::vector<uint8_t> mac_key_client_;
std::vector<uint8_t> encryption_key_;
std::vector<uint8_t> session_key_;
ODK_NonceValues nonce_values_;
uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE];
// Content/entitlement keys.
const Key* current_content_key_ = nullptr;
std::unique_ptr<SessionContextKeys> session_keys_;
bool decrypt_started_ =
false; // If the license has been used in this session.
ODK_TimerLimits timer_limits_;
ODK_ClockValues clock_values_;
std::unique_ptr<UsageTableEntry> usage_entry_;
SRMVersionStatus srm_requirements_status_ = NoSRMVersion;
enum UsageEntryStatus {
kNoUsageEntry, // No entry loaded for this session.
kUsageEntryNew, // After entry was created.
kUsageEntryLoaded, // After loading entry or loading keys.
};
UsageEntryStatus usage_entry_status_ = kNoUsageEntry;
// These are used when doing full decrypt path testing.
bool compute_hash_ = false; // True if the current frame needs a hash.
uint32_t current_hash_ = 0; // Running CRC hash of frame.
uint32_t given_hash_ = 0; // True CRC hash of frame.
uint32_t current_frame_number_ = 0; // Current frame for CRC hash.
uint32_t bad_frame_number_ = 0; // Frame number with bad hash.
OEMCryptoResult hash_error_ =
OEMCrypto_SUCCESS; // Error code for first bad frame.
// The bare minimum state machine is to only call each of these function
// categories at most once.
bool state_nonce_created_ = false;
bool state_request_signed_ = false;
bool state_response_loaded_ = false;
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
};
} // namespace wvoec_ref
#endif // REF_OEMCRYPTO_SESSION_H_

View File

@@ -1,105 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_session_key_table.h"
#include "keys.h"
#include "log.h"
namespace wvoec_ref {
bool SessionKeyTable::Insert(const KeyId key_id, const Key& key_data) {
if (keys_.find(key_id) != keys_.end()) return false;
keys_[key_id] = std::unique_ptr<Key>(new Key(key_data));
return true;
}
Key* SessionKeyTable::Find(const KeyId key_id) {
if (keys_.find(key_id) == keys_.end()) {
return nullptr;
}
return keys_[key_id].get();
}
void SessionKeyTable::Remove(const KeyId key_id) {
if (keys_.find(key_id) != keys_.end()) {
keys_.erase(key_id);
}
}
void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) {
for (KeyMap::iterator it = keys_.begin(); it != keys_.end(); ++it) {
it->second->UpdateDuration(control);
}
}
bool EntitlementKeyTable::Insert(const KeyId key_id, const Key& key_data) {
// |key_id| and |key_data| are for an entitlement key. Insert a new
// entitlement key entry.
if (keys_.find(key_id) != keys_.end()) return false;
keys_[key_id] = std::unique_ptr<EntitlementKey>(new EntitlementKey(key_data));
// If this is a new insertion, we don't have a content key assigned yet.
return true;
}
Key* EntitlementKeyTable::Find(const KeyId key_id) {
// |key_id| refers to a content key.
ContentIdToEntitlementIdMap::iterator it =
contentid_to_entitlementid_.find(key_id);
if (it == contentid_to_entitlementid_.end()) {
return nullptr;
}
if (keys_.find(it->second) == keys_.end()) {
return nullptr;
}
return keys_[it->second].get();
}
void EntitlementKeyTable::Remove(const KeyId key_id) {
// |key_id| refers to a content key. No one currently calls Remove so this
// method is free to change if needed.
ContentIdToEntitlementIdMap::iterator it =
contentid_to_entitlementid_.find(key_id);
if (it == contentid_to_entitlementid_.end()) {
return;
}
keys_.erase(it->second);
contentid_to_entitlementid_.erase(key_id);
}
void EntitlementKeyTable::UpdateDuration(const KeyControlBlock& control) {
for (EntitlementKeyMap::iterator it = keys_.begin(); it != keys_.end();
++it) {
it->second->UpdateDuration(control);
}
}
bool EntitlementKeyTable::SetContentKey(
const KeyId& entitlement_id, const KeyId& content_key_id,
const std::vector<uint8_t> content_key) {
EntitlementKeyMap::iterator it = keys_.find(entitlement_id);
if (it == keys_.end()) {
return false;
}
contentid_to_entitlementid_.erase(it->second->content_key_id());
if (!it->second->SetContentKey(content_key_id, content_key)) {
return false;
}
contentid_to_entitlementid_[content_key_id] = entitlement_id;
return true;
}
EntitlementKey* EntitlementKeyTable::GetEntitlementKey(
const KeyId& entitlement_id) {
EntitlementKeyMap::iterator it = keys_.find(entitlement_id);
if (it == keys_.end()) {
return nullptr;
}
return it->second.get();
}
} // namespace wvoec_ref

View File

@@ -1,73 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef REF_OEMCRYPTO_SESSION_KEY_TABLE_H_
#define REF_OEMCRYPTO_SESSION_KEY_TABLE_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <vector>
#include "disallow_copy_and_assign.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_types.h"
namespace wvoec_ref {
class SessionContext;
class CryptoEngine;
class UsageTable;
class UsageTableEntry;
typedef std::vector<uint8_t> KeyId;
typedef std::map<KeyId, std::unique_ptr<Key>> KeyMap;
typedef std::map<KeyId, std::unique_ptr<EntitlementKey>> EntitlementKeyMap;
// SessionKeyTable holds the keys for the current session
class SessionKeyTable {
public:
SessionKeyTable() {}
~SessionKeyTable() {}
bool Insert(const KeyId key_id, const Key& key_data);
Key* Find(const KeyId key_id);
Key* FirstKey() { return keys_.begin()->second.get(); }
void Remove(const KeyId key_id);
void UpdateDuration(const KeyControlBlock& control);
size_t size() const { return keys_.size(); }
private:
KeyMap keys_;
CORE_DISALLOW_COPY_AND_ASSIGN(SessionKeyTable);
};
class EntitlementKeyTable {
typedef std::map<KeyId, KeyId> ContentIdToEntitlementIdMap;
public:
EntitlementKeyTable() {}
~EntitlementKeyTable() {}
bool Insert(const KeyId key_id, const Key& key_data);
Key* Find(const KeyId key_id);
Key* FirstKey() { return keys_.begin()->second.get(); }
void Remove(const KeyId key_id);
void UpdateDuration(const KeyControlBlock& control);
size_t size() const { return contentid_to_entitlementid_.size(); }
bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id,
const std::vector<uint8_t> content_key);
EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id);
private:
EntitlementKeyMap keys_;
ContentIdToEntitlementIdMap contentid_to_entitlementid_;
CORE_DISALLOW_COPY_AND_ASSIGN(EntitlementKeyTable);
};
} // namespace wvoec_ref
#endif // REF_OEMCRYPTO_SESSION_KEY_TABLE_H_

View File

@@ -1,710 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_usage_table_ref.h"
#include <string.h>
#include <time.h>
#include <string>
#include <vector>
#include <openssl/aes.h>
#include <openssl/crypto.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include "file_store.h"
#include "log.h"
#include "odk.h"
#include "oemcrypto_engine_ref.h"
// TODO(fredgc): Setting the device files base bath is currently broken as
// wvcdm::Properties is no longer used by the reference code.
//#include "properties.h"
#include "pst_report.h"
#include "string_conversions.h"
namespace wvoec_ref {
namespace {
const size_t kMagicLength = 8;
const char* kEntryVerification = "USEENTRY";
const char* kHeaderVerification = "USEHEADR";
// Offset into a signed block where we start encrypting. We need to
// skip the signature and the iv.
const size_t kEncryptionOffset = SHA256_DIGEST_LENGTH + SHA256_DIGEST_LENGTH;
// A structure that holds an usage entry and its signature.
struct SignedEntryBlock {
uint8_t signature[SHA256_DIGEST_LENGTH];
uint8_t iv[SHA256_DIGEST_LENGTH];
uint8_t verification[kMagicLength];
StoredUsageEntry data;
};
// This has the data in the header of constant size. There is also an array
// of generation numbers.
struct SignedHeaderBlock {
uint8_t signature[SHA256_DIGEST_LENGTH];
uint8_t iv[SHA256_DIGEST_LENGTH];
uint8_t verification[kMagicLength];
int64_t master_generation;
uint64_t count;
};
} // namespace
UsageTableEntry::UsageTableEntry(UsageTable* table, uint32_t index,
int64_t generation)
: usage_table_(table), recent_decrypt_(false), forbid_report_(true) {
memset(&data_, 0, sizeof(data_));
data_.generation_number = generation;
data_.index = index;
}
UsageTableEntry::~UsageTableEntry() { usage_table_->ReleaseEntry(data_.index); }
OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) {
if (pst_length > kMaxPSTLength) return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
data_.pst_length = pst_length;
if (!pst || !pst_length) return OEMCrypto_ERROR_INVALID_CONTEXT;
memcpy(data_.pst, pst, pst_length);
data_.time_of_license_received = usage_table_->ce_->SystemTime();
return OEMCrypto_SUCCESS;
}
bool UsageTableEntry::VerifyPST(const uint8_t* pst, size_t pst_length) {
if (pst_length > kMaxPSTLength) return false;
if (data_.pst_length != pst_length) return false;
if (!pst || !pst_length) return false;
return 0 == CRYPTO_memcmp(pst, data_.pst, pst_length);
}
bool UsageTableEntry::VerifyMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client) {
return (server.size() == wvoec::MAC_KEY_SIZE) &&
(client.size() == wvoec::MAC_KEY_SIZE) &&
(0 == CRYPTO_memcmp(&server[0], data_.mac_key_server,
wvoec::MAC_KEY_SIZE)) &&
(0 ==
CRYPTO_memcmp(&client[0], data_.mac_key_client, wvoec::MAC_KEY_SIZE));
}
bool UsageTableEntry::SetMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client) {
if ((server.size() != wvoec::MAC_KEY_SIZE) ||
(client.size() != wvoec::MAC_KEY_SIZE))
return false;
memcpy(data_.mac_key_server, &server[0], wvoec::MAC_KEY_SIZE);
memcpy(data_.mac_key_client, &client[0], wvoec::MAC_KEY_SIZE);
return true;
}
void UsageTableEntry::ForbidReport() {
forbid_report_ = true;
data_.generation_number++;
usage_table_->IncrementGeneration();
}
OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
uint8_t* buffer,
size_t* buffer_length) {
if (forbid_report_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
if (recent_decrypt_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
if (pst.size() == 0 || pst.size() > kMaxPSTLength ||
pst.size() != data_.pst_length) {
LOGE("ReportUsage: bad pst length = %zu, should be %u.", pst.size(),
data_.pst_length);
return OEMCrypto_ERROR_WRONG_PST;
}
if (CRYPTO_memcmp(&pst[0], data_.pst, data_.pst_length)) {
LOGE("ReportUsage: wrong pst %s, should be %s.",
wvcdm::b2a_hex(pst).c_str(),
wvcdm::HexEncode(data_.pst, data_.pst_length).c_str());
return OEMCrypto_ERROR_WRONG_PST;
}
const size_t length_needed =
wvcdm::Unpacked_PST_Report::report_size(pst.size());
if (*buffer_length < length_needed) {
*buffer_length = length_needed;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (!buffer) {
LOGE("ReportUsage: buffer was null pointer.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
wvcdm::Unpacked_PST_Report pst_report(buffer);
const int64_t now = usage_table_->ce_->SystemTime();
pst_report.set_seconds_since_license_received(now -
data_.time_of_license_received);
pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt);
pst_report.set_seconds_since_last_decrypt(now - data_.time_of_last_decrypt);
pst_report.set_status(data_.status);
pst_report.set_clock_security_level(kSecureTimer);
pst_report.set_pst_length(data_.pst_length);
memcpy(pst_report.pst(), data_.pst, data_.pst_length);
unsigned int md_len = SHA_DIGEST_LENGTH;
if (!HMAC(EVP_sha1(), data_.mac_key_client, wvoec::MAC_KEY_SIZE,
buffer + SHA_DIGEST_LENGTH, length_needed - SHA_DIGEST_LENGTH,
pst_report.signature(), &md_len)) {
LOGE("ReportUsage: could not compute signature.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
void UsageTableEntry::UpdateAndIncrement(ODK_ClockValues* clock_values) {
if (recent_decrypt_) {
data_.time_of_last_decrypt = usage_table_->ce_->SystemTime();
recent_decrypt_ = false;
}
data_.time_of_license_received = clock_values->time_of_license_signed;
data_.time_of_first_decrypt = clock_values->time_of_first_decrypt;
// Use the most recent time_of_last_decrypt.
if (static_cast<uint64_t>(data_.time_of_last_decrypt) <
clock_values->time_of_last_decrypt) {
// For the reference implementation, we update the clock_values on every
// decrypt.
data_.time_of_last_decrypt = clock_values->time_of_last_decrypt;
} else {
// For this reference implementation of OEMCrypto, we regularly update
// clock_values->time_of_last_decrypt and we could just update
// data_.time_of_last_decrypt here. However, I'm including the line below to
// make it clear that you could do it the other way around. When this
// function is called, the two values should be synced so that the usage
// entry can be saved with the correct value.
clock_values->time_of_last_decrypt = data_.time_of_last_decrypt;
}
data_.status = clock_values->status;
data_.generation_number++;
usage_table_->IncrementGeneration();
forbid_report_ = false;
}
OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
SessionContext* session,
uint8_t* signed_buffer,
size_t buffer_size) {
// buffer_size was determined by calling function.
if (buffer_size != SignedEntrySize()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
std::vector<uint8_t> clear_buffer(buffer_size);
memset(&clear_buffer[0], 0, buffer_size);
memset(signed_buffer, 0, buffer_size);
SignedEntryBlock* clear =
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
SignedEntryBlock* encrypted =
reinterpret_cast<SignedEntryBlock*>(signed_buffer);
clear->data = data_; // Copy the current data.
memcpy(clear->verification, kEntryVerification, kMagicLength);
// This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce->DeviceRootKey();
if (key.empty()) {
LOGE("SaveUsageEntry: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Encrypt the entry.
if (RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE) != 1) {
LOGE("SaveUsageEntry: Could not generate iv.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer.
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(
&clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset],
buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT);
// Sign the entry.
unsigned int sig_length = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), &key[0], key.size(),
&signed_buffer[SHA256_DIGEST_LENGTH],
buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature,
&sig_length)) {
LOGE("SaveUsageEntry: Could not sign entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values) {
if (buffer.size() < SignedEntrySize()) return OEMCrypto_ERROR_SHORT_BUFFER;
if (buffer.size() > SignedEntrySize())
LOGW("LoadUsageTableEntry: buffer is large. %zu > %zu", buffer.size(),
SignedEntrySize());
std::vector<uint8_t> clear_buffer(buffer.size());
SignedEntryBlock* clear =
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
const SignedEntryBlock* encrypted =
reinterpret_cast<const SignedEntryBlock*>(&buffer[0]);
// This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce->DeviceRootKey();
if (key.empty()) {
LOGE("LoadUsageEntry: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Verify the signature of the usage entry. Sign encrypted into clear buffer.
unsigned int sig_length = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH],
buffer.size() - SHA256_DIGEST_LENGTH, clear->signature,
&sig_length)) {
LOGE("LoadUsageEntry: Could not sign entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (CRYPTO_memcmp(clear->signature, encrypted->signature,
SHA256_DIGEST_LENGTH)) {
LOGE("LoadUsageEntry: Signature did not match.");
LOGE("LoadUsageEntry: Invalid signature given: %s",
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
LOGE("LoadUsageEntry: Invalid signature computed: %s",
wvcdm::HexEncode(clear->signature, sig_length).c_str());
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Next, decrypt the entry.
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_decrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
buffer.size() - kEncryptionOffset, &aes_key, iv_buffer,
AES_DECRYPT);
// Check the verification string is correct.
if (memcmp(kEntryVerification, clear->verification, kMagicLength)) {
LOGE("LoadUsageEntry: Invalid magic: %s=%8.8s expected: %s=%8.8s",
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
clear->verification,
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kEntryVerification),
kMagicLength)
.c_str(),
reinterpret_cast<const uint8_t*>(kEntryVerification));
return OEMCrypto_ERROR_BAD_MAGIC;
}
// Check that the index is correct.
if (index != clear->data.index) {
LOGE("LoadUsageEntry: entry says index is %u, not %u", clear->data.index,
index);
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (clear->data.status > kInactiveUnused) {
LOGE("LoadUsageEntry: entry has bad status %d", clear->data.status);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
data_ = clear->data;
return ODK_ReloadClockValues(
clock_values, data_.time_of_license_received, data_.time_of_first_decrypt,
data_.time_of_last_decrypt, data_.status, ce->SystemTime());
}
size_t UsageTableEntry::SignedEntrySize() {
size_t base = sizeof(SignedEntryBlock);
// round up to make even number of blocks:
size_t blocks = (base - 1) / wvoec::KEY_IV_SIZE + 1;
return blocks * wvoec::KEY_IV_SIZE;
}
UsageTable::~UsageTable() {}
size_t UsageTable::SignedHeaderSize(size_t count) {
size_t base = sizeof(SignedHeaderBlock) + count * sizeof(int64_t);
// round up to make even number of blocks:
size_t blocks = (base - 1) / wvoec::KEY_IV_SIZE + 1;
return blocks * wvoec::KEY_IV_SIZE;
}
OEMCryptoResult UsageTable::UpdateUsageEntry(
SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer,
size_t* header_buffer_length, uint8_t* entry_buffer,
size_t* entry_buffer_length, ODK_ClockValues* clock_values) {
size_t signed_header_size = SignedHeaderSize(generation_numbers_.size());
if (*entry_buffer_length < UsageTableEntry::SignedEntrySize() ||
*header_buffer_length < signed_header_size) {
*entry_buffer_length = UsageTableEntry::SignedEntrySize();
*header_buffer_length = signed_header_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*entry_buffer_length = UsageTableEntry::SignedEntrySize();
*header_buffer_length = signed_header_size;
if ((!header_buffer) || (!entry_buffer))
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
entry->UpdateAndIncrement(clock_values);
generation_numbers_[entry->index()] = entry->generation_number();
OEMCryptoResult result =
entry->SaveData(ce_, session, entry_buffer, *entry_buffer_length);
if (result != OEMCrypto_SUCCESS) return result;
result = SaveUsageTableHeader(header_buffer, *header_buffer_length);
return result;
}
UsageTableEntry* UsageTable::MakeEntry(uint32_t index) {
return new UsageTableEntry(this, index, master_generation_number_);
}
OEMCryptoResult UsageTable::CreateNewUsageEntry(
SessionContext* session, std::unique_ptr<UsageTableEntry>* entry,
uint32_t* usage_entry_number) {
if (!header_loaded_) {
LOGE("CreateNewUsageEntry: Header not loaded.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (!usage_entry_number) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const size_t index = generation_numbers_.size();
const size_t max = ce_->max_usage_table_size();
if (max > 0 && index >= max) {
LOGE("Too many usage entries: %zu/%zu", index, max);
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
UsageTableEntry* new_entry = MakeEntry(index);
generation_numbers_.push_back(master_generation_number_);
sessions_.push_back(session);
master_generation_number_++;
entry->reset(new_entry);
*usage_entry_number = index;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult UsageTable::LoadUsageEntry(
SessionContext* session, std::unique_ptr<UsageTableEntry>* entry,
uint32_t index, const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values) {
if (!header_loaded_) {
LOGE("LoadUsageEntry: Header not loaded.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (index >= generation_numbers_.size())
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (sessions_[index]) {
LOGE("LoadUsageEntry: index %u used by other session.", index);
return OEMCrypto_ERROR_INVALID_SESSION;
}
const size_t max = ce_->max_usage_table_size();
if (max > 0 && index >= max) {
LOGE("Too many usage entries: %u/%zu", index, max);
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
std::unique_ptr<UsageTableEntry> new_entry(MakeEntry(index));
OEMCryptoResult status =
new_entry->LoadData(ce_, index, buffer, clock_values);
if (status != OEMCrypto_SUCCESS) {
return status;
}
if (new_entry->generation_number() != generation_numbers_[index]) {
LOGE("Generation SKEW: %ld -> %ld", new_entry->generation_number(),
generation_numbers_[index]);
if ((new_entry->generation_number() + 1 < generation_numbers_[index]) ||
(new_entry->generation_number() - 1 > generation_numbers_[index])) {
return OEMCrypto_ERROR_GENERATION_SKEW;
}
status = OEMCrypto_WARNING_GENERATION_SKEW;
}
sessions_[index] = session;
*entry = std::move(new_entry);
return status;
}
OEMCryptoResult UsageTable::ShrinkUsageTableHeader(
uint32_t new_table_size, uint8_t* header_buffer,
size_t* header_buffer_length) {
if (new_table_size > generation_numbers_.size()) {
LOGE("OEMCrypto_ShrinkUsageTableHeader: %u > %zu", new_table_size,
generation_numbers_.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
size_t signed_header_size = SignedHeaderSize(new_table_size);
if (*header_buffer_length < signed_header_size) {
*header_buffer_length = signed_header_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*header_buffer_length = signed_header_size;
if (!header_buffer) {
LOGE("OEMCrypto_ShrinkUsageTableHeader: buffer null.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
for (size_t i = new_table_size; i < sessions_.size(); ++i) {
if (sessions_[i]) {
LOGE("ShrinkUsageTableHeader: session open for %zu", i);
return OEMCrypto_ERROR_ENTRY_IN_USE;
}
}
generation_numbers_.resize(new_table_size);
sessions_.resize(new_table_size);
master_generation_number_++;
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
}
OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer,
size_t buffer_size) {
if (!SaveGenerationNumber()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
size_t count = generation_numbers_.size();
// buffer_size was determined by calling function.
if (buffer_size != SignedHeaderSize(count))
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
std::vector<uint8_t> clear_buffer(buffer_size);
memset(&clear_buffer[0], 0, buffer_size);
memset(signed_buffer, 0, buffer_size);
SignedHeaderBlock* clear =
reinterpret_cast<SignedHeaderBlock*>(&clear_buffer[0]);
SignedHeaderBlock* encrypted =
reinterpret_cast<SignedHeaderBlock*>(signed_buffer);
// Pack the clear data into the clear buffer.
memcpy(clear->verification, kHeaderVerification, kMagicLength);
clear->master_generation = master_generation_number_;
clear->count = count;
// This points to the variable size part of the buffer.
int64_t* stored_generations =
reinterpret_cast<int64_t*>(&clear_buffer[sizeof(SignedHeaderBlock)]);
std::copy(generation_numbers_.begin(), generation_numbers_.begin() + count,
stored_generations);
// This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce_->DeviceRootKey();
if (key.empty()) {
LOGE("SaveUsageTableHeader: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Encrypt the entry.
if (RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE) != 1) {
LOGE("SaveUsageHeader: Could not generate iv entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer.
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(
&clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset],
buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT);
// Sign the entry.
unsigned int sig_length = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), &key[0], key.size(),
&signed_buffer[SHA256_DIGEST_LENGTH],
buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature,
&sig_length)) {
LOGE("SaveUsageHeader: Could not sign entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult UsageTable::LoadUsageTableHeader(
const std::vector<uint8_t>& buffer) {
if (!LoadGenerationNumber(false)) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (buffer.size() < SignedHeaderSize(0)) return OEMCrypto_ERROR_SHORT_BUFFER;
size_t max = ce_->max_usage_table_size();
if (max > 0 && buffer.size() > SignedHeaderSize(max)) {
LOGE("Header too big: %zu bytes/%zu bytes", buffer.size(),
SignedHeaderSize(max));
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
std::vector<uint8_t> clear_buffer(buffer.size());
SignedHeaderBlock* clear =
reinterpret_cast<SignedHeaderBlock*>(&clear_buffer[0]);
const SignedHeaderBlock* encrypted =
reinterpret_cast<const SignedHeaderBlock*>(&buffer[0]);
// This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce_->DeviceRootKey();
if (key.empty()) {
LOGE("LoadUsageTableHeader: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Verify the signature of the usage entry. Sign encrypted into clear buffer.
unsigned int sig_length = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH],
buffer.size() - SHA256_DIGEST_LENGTH, clear->signature,
&sig_length)) {
LOGE("LoadUsageTableHeader: Could not sign entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (CRYPTO_memcmp(clear->signature, encrypted->signature,
SHA256_DIGEST_LENGTH)) {
LOGE("LoadUsageTableHeader: Signature did not match.");
LOGE("LoadUsageTableHeader: Invalid signature given: %s",
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
LOGE("LoadUsageTableHeader: Invalid signature computed: %s",
wvcdm::HexEncode(clear->signature, sig_length).c_str());
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Next, decrypt the entry.
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_decrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
buffer.size() - kEncryptionOffset, &aes_key, iv_buffer,
AES_DECRYPT);
// Check the verification string is correct.
if (memcmp(kHeaderVerification, clear->verification, kMagicLength)) {
LOGE("LoadUsageTableHeader: Invalid magic: %s=%8.8s expected: %s=%8.8s",
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
clear->verification,
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kHeaderVerification),
kMagicLength)
.c_str(),
reinterpret_cast<const uint8_t*>(kHeaderVerification));
return OEMCrypto_ERROR_BAD_MAGIC;
}
// Check that size is correct, now that we know what it should be.
if (buffer.size() < SignedHeaderSize(clear->count)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (buffer.size() > SignedHeaderSize(clear->count)) {
LOGW("LoadUsageTableHeader: buffer is large. %zu > %zu", buffer.size(),
SignedHeaderSize(clear->count));
}
OEMCryptoResult status = OEMCrypto_SUCCESS;
if (clear->master_generation != master_generation_number_) {
LOGE("Generation SKEW: %ld -> %ld", clear->master_generation,
master_generation_number_);
if ((clear->master_generation + 1 < master_generation_number_) ||
(clear->master_generation - 1 > master_generation_number_)) {
return OEMCrypto_ERROR_GENERATION_SKEW;
}
status = OEMCrypto_WARNING_GENERATION_SKEW;
}
int64_t* stored_generations =
reinterpret_cast<int64_t*>(&clear_buffer[0] + sizeof(SignedHeaderBlock));
generation_numbers_.assign(stored_generations,
stored_generations + clear->count);
sessions_.clear();
sessions_.resize(clear->count);
header_loaded_ = true;
return status;
}
OEMCryptoResult UsageTable::MoveEntry(UsageTableEntry* entry,
uint32_t new_index) {
if (new_index >= generation_numbers_.size()) {
LOGE("MoveEntry: index beyond end of usage table %u >= %zu", new_index,
generation_numbers_.size());
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (sessions_[new_index]) {
LOGE("MoveEntry: session open for %u", new_index);
return OEMCrypto_ERROR_ENTRY_IN_USE;
}
if (!entry) {
LOGE("MoveEntry: null entry");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
sessions_[new_index] = sessions_[entry->index()];
sessions_[entry->index()] = 0;
entry->set_index(new_index);
generation_numbers_[new_index] = master_generation_number_;
entry->set_generation_number(master_generation_number_);
master_generation_number_++;
return OEMCrypto_SUCCESS;
}
void UsageTable::IncrementGeneration() {
master_generation_number_++;
SaveGenerationNumber();
}
bool UsageTable::SaveGenerationNumber() {
wvcdm::FileSystem* file_system = ce_->file_system();
std::string path;
// Note: this path is OK for a real implementation, but using security level 1
// would be better.
// TODO(jfore, rfrias): Address how this property is presented to the ref.
// For now, the path is empty.
/*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3,
&path)) {
LOGE("UsageTable: Unable to get base path");
return false;
}*/
// On a real implementation, you should NOT put the generation number in
// a file in user space. It should be stored in secure memory.
std::string filename = path + "GenerationNumber.dat";
auto file = file_system->Open(
filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
if (!file) {
LOGE("UsageTable: File open failed: %s", path.c_str());
return false;
}
file->Write(reinterpret_cast<char*>(&master_generation_number_),
sizeof(int64_t));
return true;
}
bool UsageTable::LoadGenerationNumber(bool or_make_new_one) {
wvcdm::FileSystem* file_system = ce_->file_system();
std::string path;
// Note: this path is OK for a real implementation, but using security level 1
// would be better.
// TODO(jfore, rfrias): Address how this property is presented to the ref.
// For now, the path is empty.
/*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3,
&path)) {
LOGE("UsageTable: Unable to get base path");
return false;
}*/
// On a real implementation, you should NOT put the generation number in
// a file in user space. It should be stored in secure memory.
std::string filename = path + "GenerationNumber.dat";
auto file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
if (!file) {
if (or_make_new_one) {
return RAND_bytes(reinterpret_cast<uint8_t*>(&master_generation_number_),
sizeof(int64_t)) == 1;
}
LOGE("UsageTable: File open failed: %s (clearing table)", path.c_str());
master_generation_number_ = 0;
return false;
}
file->Read(reinterpret_cast<char*>(&master_generation_number_),
sizeof(int64_t));
return true;
}
OEMCryptoResult UsageTable::CreateUsageTableHeader(
uint8_t* header_buffer, size_t* header_buffer_length) {
size_t signed_header_size = SignedHeaderSize(0);
if (*header_buffer_length < signed_header_size) {
*header_buffer_length = signed_header_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*header_buffer_length = signed_header_size;
if (!LoadGenerationNumber(true)) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
// Make sure there are no entries that are currently tied to an open session.
for (size_t i = 0; i < sessions_.size(); ++i) {
if (sessions_[i] != nullptr) {
LOGE("CreateUsageTableHeader: index %zu used by session.", i);
return OEMCrypto_ERROR_INVALID_SESSION;
}
}
sessions_.clear();
generation_numbers_.clear();
header_loaded_ = true;
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
}
} // namespace wvoec_ref

View File

@@ -1,132 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_USAGE_TABLE_REF_H_
#define OEMCRYPTO_USAGE_TABLE_REF_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "OEMCryptoCENC.h"
#include "odk_structs.h"
#include "oemcrypto_types.h"
#include "openssl/sha.h"
namespace wvoec_ref {
class SessionContext;
class CryptoEngine;
class UsageTable;
const size_t kMaxPSTLength = 255;
// This is the data we store offline.
struct StoredUsageEntry {
int64_t generation_number;
int64_t time_of_license_received;
int64_t time_of_first_decrypt;
int64_t time_of_last_decrypt;
enum OEMCrypto_Usage_Entry_Status status;
uint8_t mac_key_server[wvoec::MAC_KEY_SIZE];
uint8_t mac_key_client[wvoec::MAC_KEY_SIZE];
uint32_t index;
uint8_t pst[kMaxPSTLength+1]; // add 1 for padding.
uint8_t pst_length;
};
class UsageTableEntry {
public:
UsageTableEntry(UsageTable* table, uint32_t index, int64_t generation);
virtual ~UsageTableEntry(); // Free memory, remove reference in header.
bool Inactive() { return data_.status >= kInactive; }
// Mark this entry as modified and forbid a usage report until the data has
// been saved. This is done on important events like first decrypt and
// deactivation.
void ForbidReport();
OEMCryptoResult SetPST(const uint8_t* pst, size_t pst_length);
bool VerifyPST(const uint8_t* pst, size_t pst_length);
bool VerifyMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client);
bool SetMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client);
virtual OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst,
uint8_t* buffer, size_t* buffer_length);
virtual void UpdateAndIncrement(ODK_ClockValues* clock_values);
// Save all data to the given buffer. This should be called after updating the
// data.
OEMCryptoResult SaveData(CryptoEngine* ce, SessionContext* session,
uint8_t* signed_buffer, size_t buffer_size);
// Load all data from the buffer, and then update clock_values.
OEMCryptoResult LoadData(CryptoEngine* ce, uint32_t index,
const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values);
int64_t generation_number() { return data_.generation_number; }
void set_generation_number(int64_t value) { data_.generation_number = value; }
void set_index(int32_t index) { data_.index = index; }
uint32_t index() { return data_.index; }
void set_recent_decrypt(bool recent_decrypt) {
recent_decrypt_ = recent_decrypt;
}
static size_t SignedEntrySize();
const uint8_t* mac_key_server() const { return data_.mac_key_server; }
const uint8_t* mac_key_client() const { return data_.mac_key_client; }
protected:
UsageTable* usage_table_; // Owner of this object.
bool recent_decrypt_;
bool forbid_report_;
StoredUsageEntry data_;
};
class UsageTable {
public:
explicit UsageTable(CryptoEngine* ce) : ce_(ce), header_loaded_(false){};
virtual ~UsageTable();
OEMCryptoResult CreateNewUsageEntry(SessionContext* session,
std::unique_ptr<UsageTableEntry>* entry,
uint32_t* usage_entry_number);
OEMCryptoResult LoadUsageEntry(SessionContext* session,
std::unique_ptr<UsageTableEntry>* entry,
uint32_t index,
const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values);
OEMCryptoResult UpdateUsageEntry(
SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer,
size_t* header_buffer_length, uint8_t* entry_buffer,
size_t* entry_buffer_length, ODK_ClockValues* clock_values);
OEMCryptoResult MoveEntry(UsageTableEntry* entry, uint32_t new_index);
OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer,
size_t* header_buffer_length);
OEMCryptoResult LoadUsageTableHeader(const std::vector<uint8_t>& buffer);
OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_table_size,
uint8_t* header_buffer,
size_t* header_buffer_length);
void ReleaseEntry(uint32_t index) { sessions_[index] = 0; }
void IncrementGeneration();
static size_t SignedHeaderSize(size_t count);
protected:
virtual UsageTableEntry* MakeEntry(uint32_t index);
virtual OEMCryptoResult SaveUsageTableHeader(uint8_t* signed_buffer,
size_t buffer_size);
virtual bool SaveGenerationNumber();
virtual bool LoadGenerationNumber(bool or_make_new_one);
CryptoEngine* ce_;
bool header_loaded_;
int64_t master_generation_number_;
std::vector<int64_t> generation_numbers_;
std::vector<SessionContext*> sessions_;
friend class UsageTableEntry;
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_USAGE_TABLE_REF_H_

View File

@@ -1,71 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef SCOPED_OBJECT_H_
#define SCOPED_OBJECT_H_
namespace wvoec_ref {
// A generic wrapper around pointer. This allows for automatic
// memory clean up when the ScopedObject variable goes out of scope.
// This is intended to be used with OpenSSL/BoringSSL structs.
template <typename Type, void Destructor(Type*)>
class ScopedObject {
public:
ScopedObject() : ptr_(nullptr) {}
ScopedObject(Type* ptr) : ptr_(ptr) {}
~ScopedObject() {
if (ptr_) {
Destructor(ptr_);
ptr_ = nullptr;
}
}
// Copy construction and assignment are not allowed.
ScopedObject(const ScopedObject& other) = delete;
ScopedObject& operator=(const ScopedObject& other) = delete;
// Move construction and assignment are allowed.
ScopedObject(ScopedObject&& other) : ptr_(other.ptr_) {
other.ptr_ = nullptr;
}
ScopedObject& operator=(ScopedObject&& other) {
if (ptr_) {
Destructor(ptr_);
}
ptr_ = other.ptr_;
other.ptr_ = nullptr;
return *this;
}
explicit operator bool() const { return ptr_ != nullptr; }
Type& operator*() { return *ptr_; }
Type* get() const { return ptr_; }
Type* operator->() const { return ptr_; }
// Releasing the pointer will remove the responsibility of the
// ScopedObject to clean up the pointer.
Type* release() {
Type* temp = ptr_;
ptr_ = nullptr;
return temp;
}
void reset(Type* ptr = nullptr) {
if (ptr_) {
Destructor(ptr_);
}
ptr_ = ptr;
}
private:
Type* ptr_ = nullptr;
};
} // namespace wvoec_ref
#endif // SCOPED_OBJECT_H_

View File

@@ -1,108 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Compute CRC32/MPEG2 Checksum. Needed for verification of WV Keybox.
//
#include "platform.h"
#include "wvcrc32.h"
namespace wvoec_ref {
#define INIT_CRC32 0xffffffff
uint32_t wvrunningcrc32(const uint8_t* p_begin, int i_count, uint32_t i_crc) {
static uint32_t CRC32[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
/* Calculate the CRC */
while (i_count > 0) {
i_crc = (i_crc << 8) ^ CRC32[(i_crc >> 24) ^ ((uint32_t) * p_begin)];
p_begin++;
i_count--;
}
return(i_crc);
}
uint32_t wvcrc32(const uint8_t* p_begin, int i_count) {
return(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
}
uint32_t wvcrc32Init() {
return INIT_CRC32;
}
uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc) {
return(wvrunningcrc32(p_begin, i_count, prev_crc));
}
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count) {
return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
}
} // namespace wvoec_ref

View File

@@ -1,23 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Compute CRC32 Checksum. Needed for verification of WV Keybox.
//
#ifndef WVCRC32_H_
#define WVCRC32_H_
#include <stdint.h>
namespace wvoec_ref {
uint32_t wvcrc32(const uint8_t* p_begin, int i_count);
uint32_t wvcrc32Init();
uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc);
// Convert to network byte order
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count);
} // namespace wvoec_ref
#endif // WVCRC32_H_

View File

@@ -1,536 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#include "oem_cert.h"
namespace wvoec_ref {
namespace {
const uint32_t kTestOemSystemId = 7913;
// clang-format off
// OEM Certificate private key.
// RSA Private-Key: (2048 bit, 2 primes).
const uint8_t kTestOemPrivateKey[] = {
0x30, 0x82, 0x04, 0xbd, 0x02, 0x01, 0x00, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xa7, 0x30, 0x82, 0x04, 0xa3, 0x02, 0x01,
0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa8, 0x75,
0xd5, 0x3d, 0xd3, 0xf3, 0x59, 0xd1, 0x63, 0x0f,
0x5d, 0x5f, 0x2c, 0xaf, 0x80, 0x4e, 0x9a, 0xef,
0x9a, 0x8f, 0x88, 0x37, 0xe5, 0x56, 0xf8, 0x66,
0xcb, 0xa6, 0x61, 0xab, 0xc1, 0xa9, 0x04, 0xc2,
0x12, 0x9d, 0xa6, 0x0c, 0x2c, 0xcb, 0x42, 0x09,
0xd0, 0x36, 0xf0, 0x85, 0x01, 0xdf, 0xd5, 0xbd,
0xaf, 0x82, 0xbb, 0x25, 0xa1, 0x61, 0x17, 0xfe,
0xa1, 0x65, 0x34, 0xda, 0x91, 0xee, 0x91, 0x46,
0xd6, 0x63, 0x47, 0x6a, 0xa5, 0x32, 0x62, 0xe2,
0x4c, 0x7c, 0xf7, 0x76, 0x59, 0xe1, 0x2b, 0x47,
0x8d, 0x1c, 0xe6, 0xa0, 0xbd, 0xc3, 0xc9, 0x36,
0x0e, 0x90, 0x75, 0xba, 0x1c, 0xbd, 0xca, 0x85,
0x0a, 0x4e, 0xcc, 0xfe, 0x91, 0x3f, 0x22, 0x42,
0x96, 0xae, 0xa0, 0x87, 0x82, 0x63, 0x3b, 0x22,
0x54, 0xbc, 0x28, 0xa3, 0x45, 0x4b, 0x34, 0x12,
0x4e, 0xeb, 0x04, 0x4d, 0x29, 0xb3, 0x05, 0x62,
0x0d, 0x51, 0x16, 0x46, 0x98, 0x21, 0xc8, 0x59,
0x96, 0x53, 0x43, 0x38, 0x95, 0x1a, 0x42, 0x94,
0x8b, 0x49, 0x5d, 0x1b, 0x8a, 0xd5, 0x82, 0x6a,
0x32, 0x6f, 0x0e, 0x5a, 0x85, 0x3b, 0xd5, 0x42,
0xc0, 0x4c, 0x34, 0x43, 0x7c, 0x4f, 0xef, 0xca,
0x02, 0x99, 0x38, 0xf9, 0xa5, 0xc0, 0xd8, 0x1d,
0xe7, 0x9e, 0x8c, 0x4d, 0x9c, 0x40, 0xcd, 0x4b,
0x5e, 0x44, 0x37, 0x8d, 0xc5, 0x96, 0xd4, 0xf7,
0xb3, 0x37, 0x4c, 0x2e, 0x2d, 0x30, 0xca, 0x97,
0x39, 0xed, 0xe8, 0x73, 0xc5, 0xe7, 0xcb, 0x95,
0xf0, 0x84, 0x4a, 0x5a, 0x9e, 0x13, 0x19, 0x5f,
0x98, 0xe5, 0xbe, 0x31, 0x5b, 0xff, 0xed, 0x29,
0x26, 0xc4, 0x93, 0x54, 0x49, 0x84, 0xd2, 0xeb,
0x21, 0x40, 0x19, 0x5f, 0xf7, 0x32, 0x67, 0x93,
0xe0, 0xda, 0x77, 0xfc, 0xda, 0x5e, 0xc4, 0x5b,
0x95, 0x2e, 0x46, 0xf3, 0xce, 0xfd, 0x02, 0x03,
0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x01, 0x00,
0x9e, 0x6d, 0x82, 0xc8, 0x0c, 0xc6, 0xb5, 0xd7,
0xa7, 0xb3, 0xd1, 0x7a, 0x2a, 0x8a, 0x3a, 0xbe,
0xb2, 0x13, 0x58, 0x66, 0x58, 0x13, 0x49, 0x4a,
0x0b, 0x7e, 0x91, 0x53, 0xbe, 0x53, 0x4b, 0x63,
0xeb, 0x27, 0xa1, 0x5e, 0x45, 0xc4, 0xf9, 0x73,
0x86, 0x7d, 0xb8, 0x25, 0x92, 0xf9, 0x63, 0x93,
0xe0, 0x6d, 0xed, 0xdb, 0xa2, 0xa9, 0x77, 0x25,
0xda, 0xed, 0x0b, 0x58, 0x24, 0xe6, 0xd1, 0x8b,
0x6d, 0x71, 0x13, 0x3a, 0x76, 0xf5, 0xa2, 0xba,
0xca, 0x28, 0x4d, 0x0a, 0xd1, 0xa7, 0xaa, 0x4b,
0x8a, 0xea, 0x55, 0x99, 0xb2, 0x83, 0xc5, 0x33,
0x95, 0xcd, 0x92, 0xd0, 0xe5, 0x06, 0xcc, 0xf4,
0xe8, 0xbb, 0x49, 0xc0, 0x66, 0x25, 0x9a, 0xef,
0xa7, 0x06, 0xbc, 0xb3, 0x2a, 0x21, 0x86, 0xcc,
0x4f, 0xd6, 0xaf, 0x9d, 0xed, 0x11, 0xef, 0x9f,
0x14, 0x2f, 0x8b, 0xac, 0x96, 0x75, 0x03, 0x1a,
0xe4, 0x5c, 0x48, 0x81, 0x3a, 0x4b, 0x21, 0x6e,
0xad, 0xb3, 0x27, 0x51, 0xe9, 0x35, 0xbe, 0xed,
0x42, 0x5f, 0x8f, 0x83, 0xf0, 0x99, 0xb0, 0xaf,
0xa9, 0x9c, 0x2f, 0xee, 0x5f, 0xee, 0x39, 0x2b,
0x1d, 0xb0, 0xb1, 0xf8, 0x7b, 0x69, 0x38, 0x68,
0xae, 0xa0, 0x36, 0x2a, 0xf5, 0xed, 0x96, 0xfa,
0x7c, 0x1c, 0x59, 0x29, 0xbf, 0xb3, 0x9e, 0x14,
0x97, 0x06, 0xc2, 0x40, 0x30, 0x00, 0x6a, 0x95,
0xd3, 0x86, 0x86, 0xb9, 0x4c, 0xf5, 0x51, 0xa3,
0x6d, 0x5a, 0xd1, 0x46, 0x43, 0x24, 0xa4, 0xa9,
0x59, 0xcf, 0xa2, 0xa7, 0x4e, 0x50, 0x7a, 0xa3,
0x14, 0xe4, 0x4e, 0x32, 0x4d, 0xd4, 0xc2, 0xcf,
0x2d, 0x74, 0xfb, 0x51, 0x34, 0x98, 0x68, 0xc3,
0xd2, 0xb1, 0xd9, 0x38, 0x94, 0x91, 0x28, 0xb1,
0x69, 0x9a, 0xbf, 0xbf, 0x1a, 0xdf, 0xd3, 0xb6,
0x21, 0x38, 0x94, 0x1b, 0x81, 0x00, 0xb5, 0x39,
0x02, 0x81, 0x81, 0x00, 0xdb, 0xe4, 0x83, 0xc5,
0x7a, 0xe0, 0xcf, 0xeb, 0x07, 0x37, 0xfb, 0xf6,
0xfe, 0xb3, 0x62, 0x72, 0x86, 0xd0, 0x12, 0x96,
0x9d, 0xf4, 0x93, 0x90, 0xdc, 0xf6, 0xc6, 0x03,
0x0c, 0x46, 0xb8, 0x66, 0x60, 0xf3, 0x46, 0x5b,
0xab, 0x9f, 0x9d, 0x81, 0xac, 0x26, 0x8f, 0xd7,
0xa3, 0xbd, 0x16, 0xbb, 0xb4, 0x4e, 0xf6, 0xc0,
0x12, 0xb6, 0x99, 0x4a, 0xf5, 0xc1, 0x6c, 0x40,
0x72, 0x18, 0x71, 0x02, 0x65, 0x77, 0xb1, 0xfb,
0xec, 0x19, 0xbb, 0x8c, 0x03, 0xea, 0x7b, 0x17,
0x63, 0xc9, 0xb9, 0x3b, 0x10, 0x56, 0x19, 0xef,
0x86, 0x69, 0x4d, 0x61, 0x03, 0xac, 0x30, 0x65,
0x63, 0xe5, 0xe1, 0x0f, 0xd6, 0xf6, 0x5b, 0xc9,
0x7c, 0xde, 0x9b, 0x26, 0xca, 0x98, 0xda, 0x0c,
0x5b, 0x6f, 0x91, 0x88, 0xbf, 0x98, 0xc3, 0xbc,
0x72, 0x21, 0xa0, 0x07, 0x0a, 0x5e, 0xc7, 0x61,
0x4a, 0xb3, 0x32, 0xc7, 0x02, 0x81, 0x81, 0x00,
0xc4, 0x1f, 0x4a, 0x23, 0xa6, 0x0b, 0xb9, 0xd5,
0xc7, 0xe9, 0x1a, 0x24, 0xe8, 0x2b, 0xf2, 0x1f,
0x17, 0xc3, 0xe6, 0x14, 0x76, 0x71, 0x11, 0x76,
0x8f, 0xfc, 0x66, 0xb8, 0x8c, 0xe2, 0xf5, 0x46,
0x89, 0x0d, 0xd7, 0xe3, 0x56, 0x19, 0xd7, 0x1a,
0xfe, 0x1c, 0xd4, 0x0f, 0x8b, 0x72, 0xd1, 0x20,
0xb0, 0xa4, 0xbe, 0x6b, 0x6b, 0x01, 0x57, 0xe8,
0x6b, 0xdf, 0x89, 0x55, 0x3f, 0x10, 0x41, 0x63,
0xb0, 0x62, 0xa5, 0x7f, 0x4f, 0xe7, 0x42, 0x54,
0xe4, 0x0e, 0x55, 0xae, 0xa2, 0x53, 0x3d, 0xb8,
0x4a, 0xff, 0xeb, 0xe2, 0x8a, 0x71, 0x17, 0x54,
0x20, 0x05, 0x51, 0xed, 0xae, 0xb0, 0xca, 0x7e,
0xc6, 0xd7, 0x09, 0xa8, 0x39, 0x88, 0xac, 0x7f,
0x4b, 0xe0, 0x49, 0xd5, 0x6c, 0x89, 0xf0, 0xbc,
0xe4, 0xe9, 0xb0, 0x29, 0x73, 0x6c, 0x55, 0x7d,
0x8f, 0xbe, 0x32, 0x31, 0x14, 0xd2, 0xec, 0x1b,
0x02, 0x81, 0x80, 0x67, 0xf6, 0x55, 0x5a, 0xa3,
0xaa, 0xf0, 0x82, 0x75, 0x2a, 0x41, 0xe5, 0x58,
0x2c, 0x65, 0xaa, 0x32, 0x14, 0xe4, 0x04, 0xf3,
0xef, 0x33, 0x69, 0x75, 0x1e, 0xf3, 0x25, 0x73,
0xc3, 0x67, 0xe1, 0x77, 0x8a, 0xed, 0x43, 0xe0,
0x13, 0x99, 0xfb, 0x39, 0xf2, 0x0d, 0x65, 0xed,
0x93, 0x33, 0xd1, 0x51, 0x01, 0x58, 0x66, 0x1d,
0x32, 0xd9, 0xac, 0xf8, 0x1e, 0x17, 0xd9, 0x2c,
0x58, 0x63, 0xed, 0xb7, 0x1d, 0x6d, 0x37, 0xe7,
0x3b, 0x8f, 0x51, 0x36, 0x74, 0xc0, 0xf7, 0xa1,
0x05, 0x39, 0x9f, 0x34, 0x2d, 0x11, 0x1c, 0x0e,
0xd7, 0x70, 0x6f, 0x22, 0xb6, 0x61, 0x37, 0x3e,
0x90, 0xeb, 0xe4, 0x7a, 0x44, 0x85, 0xc6, 0xf0,
0x53, 0xaa, 0xd5, 0x1f, 0x4a, 0x3f, 0x25, 0x42,
0x81, 0xb0, 0x34, 0x10, 0x29, 0xe0, 0xb9, 0x12,
0xd8, 0xd4, 0xf9, 0x1f, 0x2d, 0x0a, 0x64, 0xf4,
0x55, 0x5e, 0xf7, 0x02, 0x81, 0x80, 0x3d, 0x06,
0x1f, 0x63, 0x88, 0x3f, 0x0d, 0xcb, 0xdf, 0x30,
0x40, 0xda, 0x4b, 0x03, 0xa1, 0x8a, 0xdb, 0x32,
0x31, 0x5d, 0x1c, 0x9d, 0x81, 0xf9, 0x8a, 0x43,
0xd7, 0x12, 0x85, 0x83, 0xf9, 0x1d, 0xc1, 0x77,
0x75, 0x3d, 0x5f, 0x85, 0x1a, 0xd1, 0x63, 0x50,
0x45, 0x0b, 0xb1, 0x30, 0x40, 0xb2, 0x13, 0x44,
0xaf, 0x9b, 0x6c, 0xe8, 0x36, 0x1a, 0x33, 0xb6,
0x92, 0x5c, 0xdc, 0x0a, 0x8a, 0xce, 0x22, 0x0c,
0x0f, 0xc2, 0xd5, 0x71, 0xf7, 0xc9, 0xc2, 0x4c,
0x53, 0x8c, 0xcb, 0x25, 0x6b, 0x86, 0xf4, 0x8f,
0x3d, 0x2e, 0x78, 0x35, 0x48, 0x34, 0xfc, 0xe1,
0xaa, 0xe4, 0x71, 0xfe, 0xc0, 0x83, 0x42, 0x0b,
0x97, 0x0d, 0xa9, 0x19, 0x45, 0xd3, 0x36, 0x20,
0xcb, 0xd8, 0x84, 0xb5, 0x47, 0x1a, 0xff, 0x7f,
0x57, 0x39, 0x0e, 0x99, 0x1e, 0xe0, 0xba, 0xe1,
0x4b, 0x6c, 0xca, 0x35, 0xf7, 0x11, 0x02, 0x81,
0x80, 0x5a, 0x59, 0xf0, 0x8e, 0x07, 0x9c, 0x1a,
0x83, 0x2b, 0x28, 0xc4, 0x82, 0xcc, 0xb7, 0x9e,
0x41, 0xa5, 0x15, 0xa2, 0x37, 0xa7, 0x0c, 0x77,
0x09, 0x73, 0xf5, 0xb1, 0x3f, 0x7a, 0x55, 0x9f,
0x15, 0x90, 0xa3, 0x5e, 0x6e, 0x19, 0x46, 0x6d,
0x1f, 0x28, 0x64, 0xad, 0xa0, 0xb5, 0xca, 0x7d,
0x06, 0x44, 0x88, 0xae, 0x2b, 0x80, 0x21, 0x84,
0x3d, 0x8d, 0xa5, 0x09, 0x4f, 0xa1, 0xd9, 0x7d,
0x7c, 0x9a, 0x8b, 0x64, 0x8f, 0xf6, 0xa5, 0xce,
0x56, 0x65, 0xba, 0xcb, 0x30, 0x38, 0x53, 0xf8,
0x1b, 0x89, 0x8f, 0xdf, 0xb5, 0xc3, 0x86, 0x3c,
0x24, 0xef, 0xbc, 0xc0, 0xfc, 0x6c, 0xa4, 0xc6,
0x74, 0xbb, 0xeb, 0x79, 0xa9, 0x8e, 0xe5, 0x25,
0xc0, 0x0a, 0xe5, 0x90, 0x08, 0x43, 0x82, 0xec,
0x17, 0x5e, 0x9e, 0xa2, 0x05, 0xc5, 0x03, 0x20,
0x12, 0xf7, 0x86, 0x2e, 0x7e, 0x8e, 0x11, 0xf7,
0x14
};
const size_t kTestOemPrivateKeySize = sizeof(kTestOemPrivateKey);
// OEM Certificate public cert data.
// Leaf (device) certificate:
// version: 2
// serialNumber: 61412119066269531030714093834591281593
// signature algorithm: sha256WithRSAEncryption (1.2.840.113549.1.1.11)
// issuer:
// C=US, ST=WA, L=Kirkland, O=Google, OU=Widevine, CN=system id: 7913
// validity:
// notBefore: Jan 27 15:55:47 2021 GMT
// notAfter: Jan 25 15:55:47 2031 GMT
// subject:
// CN=7913-leaf, C=US, ST=WA, L=Kirkland, O=Google, OU=Widevine
// key: RSA Public key
// extensions:
// - object: Widevine System Id (1.3.6.1.4.1.11129.4.1.1)
// critical: BOOL ABSENT
// value: 02 02 1e e9 (7913)
// sig_alg: sha256WithRSAEncryption (1.2.840.113549.1.1.11)
// signature: ...
//
// Intermediate (manufacturer) certificate:
// version: 2
// serialNumber: 4911737327617104025470773024969385060
// signature: sha256WithRSAEncryption (1.2.840.113549.1.1.11)
// issuer:
// C=US, ST=Washington, L=Kirkland, O=Google, OU=Widevine,
// CN=widevine.com/oem-root-prod
// validity:
// notBefore: Nov 18 01:13:35 2017 GMT
// notAfter: Nov 18 01:13:13 2027 GMT
// subject:
// C=US, ST=WA, L=Kirkland, O=Google, OU=Widevine, CN=system id: 7913
// key: RSA Public key
// extensions:
// - object: X509v3 Basic Constraints (2.5.29.19)
// critical: TRUE
// value: 30 06 01 01 ff 02 01 00
// - object: X509v3 Key Usage (2.5.29.15)
// critical: TRUE
// value: 03 02 02 04
// - object: X509v3 Subject Key Identifier (2.5.29.14)
// critical: BOOL ABSENT
// value:
// 04 14 4b cb df aa 02 de 8d c3 e7 e5 85 db 2e 8a be 75 6b 8a 67-58
// - object: X509v3 Authority Key Identifier (2.5.29.35)
// critical: BOOL ABSENT
// value: ...
// - object: Widevine System Id (1.3.6.1.4.1.11129.4.1.1)
// critical: BOOL ABSENT
// value: 02 02 1e e9 (7913)
// sig_alg: sha256WithRSAEncryption (1.2.840.113549.1.1.11)
// signature: ...
const uint8_t kTestOemPublicCert[] = {
0x30, 0x82, 0x09, 0x28, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
0x82, 0x09, 0x19, 0x30, 0x82, 0x09, 0x15, 0x02,
0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x01, 0xa0, 0x82, 0x08, 0xfd, 0x30, 0x82, 0x03,
0x70, 0x30, 0x82, 0x02, 0x58, 0xa0, 0x03, 0x02,
0x01, 0x02, 0x02, 0x10, 0x2e, 0x33, 0x8b, 0x3d,
0x69, 0x18, 0x4c, 0xf7, 0x78, 0x2e, 0x3b, 0x3b,
0x43, 0xb4, 0x21, 0xb9, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x0b, 0x05, 0x00, 0x30, 0x6b, 0x31, 0x0b, 0x30,
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61,
0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69,
0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x18,
0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
0x0f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31, 0x33,
0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x31,
0x32, 0x37, 0x31, 0x35, 0x35, 0x35, 0x34, 0x37,
0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x31, 0x32,
0x35, 0x31, 0x35, 0x35, 0x35, 0x34, 0x37, 0x5a,
0x30, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x39, 0x31,
0x33, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41,
0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c,
0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06,
0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f,
0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57,
0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30,
0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa8, 0x75, 0xd5, 0x3d, 0xd3, 0xf3, 0x59, 0xd1,
0x63, 0x0f, 0x5d, 0x5f, 0x2c, 0xaf, 0x80, 0x4e,
0x9a, 0xef, 0x9a, 0x8f, 0x88, 0x37, 0xe5, 0x56,
0xf8, 0x66, 0xcb, 0xa6, 0x61, 0xab, 0xc1, 0xa9,
0x04, 0xc2, 0x12, 0x9d, 0xa6, 0x0c, 0x2c, 0xcb,
0x42, 0x09, 0xd0, 0x36, 0xf0, 0x85, 0x01, 0xdf,
0xd5, 0xbd, 0xaf, 0x82, 0xbb, 0x25, 0xa1, 0x61,
0x17, 0xfe, 0xa1, 0x65, 0x34, 0xda, 0x91, 0xee,
0x91, 0x46, 0xd6, 0x63, 0x47, 0x6a, 0xa5, 0x32,
0x62, 0xe2, 0x4c, 0x7c, 0xf7, 0x76, 0x59, 0xe1,
0x2b, 0x47, 0x8d, 0x1c, 0xe6, 0xa0, 0xbd, 0xc3,
0xc9, 0x36, 0x0e, 0x90, 0x75, 0xba, 0x1c, 0xbd,
0xca, 0x85, 0x0a, 0x4e, 0xcc, 0xfe, 0x91, 0x3f,
0x22, 0x42, 0x96, 0xae, 0xa0, 0x87, 0x82, 0x63,
0x3b, 0x22, 0x54, 0xbc, 0x28, 0xa3, 0x45, 0x4b,
0x34, 0x12, 0x4e, 0xeb, 0x04, 0x4d, 0x29, 0xb3,
0x05, 0x62, 0x0d, 0x51, 0x16, 0x46, 0x98, 0x21,
0xc8, 0x59, 0x96, 0x53, 0x43, 0x38, 0x95, 0x1a,
0x42, 0x94, 0x8b, 0x49, 0x5d, 0x1b, 0x8a, 0xd5,
0x82, 0x6a, 0x32, 0x6f, 0x0e, 0x5a, 0x85, 0x3b,
0xd5, 0x42, 0xc0, 0x4c, 0x34, 0x43, 0x7c, 0x4f,
0xef, 0xca, 0x02, 0x99, 0x38, 0xf9, 0xa5, 0xc0,
0xd8, 0x1d, 0xe7, 0x9e, 0x8c, 0x4d, 0x9c, 0x40,
0xcd, 0x4b, 0x5e, 0x44, 0x37, 0x8d, 0xc5, 0x96,
0xd4, 0xf7, 0xb3, 0x37, 0x4c, 0x2e, 0x2d, 0x30,
0xca, 0x97, 0x39, 0xed, 0xe8, 0x73, 0xc5, 0xe7,
0xcb, 0x95, 0xf0, 0x84, 0x4a, 0x5a, 0x9e, 0x13,
0x19, 0x5f, 0x98, 0xe5, 0xbe, 0x31, 0x5b, 0xff,
0xed, 0x29, 0x26, 0xc4, 0x93, 0x54, 0x49, 0x84,
0xd2, 0xeb, 0x21, 0x40, 0x19, 0x5f, 0xf7, 0x32,
0x67, 0x93, 0xe0, 0xda, 0x77, 0xfc, 0xda, 0x5e,
0xc4, 0x5b, 0x95, 0x2e, 0x46, 0xf3, 0xce, 0xfd,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x16, 0x30,
0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01,
0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04,
0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
0x00, 0x04, 0x9e, 0xbb, 0x41, 0x3e, 0x1b, 0x35,
0xca, 0x24, 0xe3, 0xa7, 0x62, 0xf7, 0xbf, 0x54,
0x88, 0x1d, 0xa3, 0x6c, 0x30, 0x1f, 0xb7, 0xe4,
0x2b, 0x76, 0x54, 0x4f, 0xb1, 0x30, 0xba, 0x86,
0x21, 0x12, 0xc3, 0xd9, 0x25, 0xfd, 0x94, 0xab,
0x3c, 0x9d, 0x4d, 0xbc, 0x2b, 0xdc, 0x68, 0x01,
0x8d, 0x59, 0x4f, 0x81, 0xe8, 0x87, 0xbe, 0x05,
0x75, 0x3e, 0x24, 0xd9, 0xf1, 0x55, 0xe3, 0x56,
0x75, 0xa4, 0x7f, 0xb4, 0x50, 0x41, 0x4b, 0x88,
0x0e, 0x8f, 0x6e, 0x10, 0x13, 0x25, 0x24, 0xda,
0x4c, 0x97, 0x0a, 0xdc, 0xbf, 0x2a, 0x1d, 0x4d,
0x02, 0xb3, 0x4b, 0x6a, 0x96, 0xe6, 0x0e, 0xd1,
0x61, 0x80, 0x78, 0xab, 0xf0, 0x7b, 0x8b, 0x1e,
0x99, 0x48, 0x84, 0x31, 0xd2, 0xaf, 0x23, 0x32,
0x01, 0x5e, 0x11, 0x55, 0x06, 0x6e, 0x0e, 0xed,
0x69, 0x7b, 0xb8, 0x41, 0x63, 0x3b, 0x30, 0x05,
0x1e, 0xcd, 0x3e, 0x49, 0xb8, 0x0c, 0x83, 0x50,
0x26, 0x4e, 0xd8, 0x97, 0x9d, 0x89, 0x30, 0x15,
0xb9, 0x20, 0x20, 0xba, 0x5d, 0x8b, 0xad, 0x3d,
0x7f, 0x52, 0xcd, 0x1e, 0xc0, 0x0e, 0xe1, 0xdc,
0x21, 0x9b, 0xb0, 0x89, 0xa0, 0x20, 0xc6, 0x8c,
0x56, 0x39, 0xc3, 0x40, 0x30, 0x40, 0x52, 0x2f,
0x3b, 0x87, 0x96, 0xe2, 0x4d, 0x80, 0x57, 0xb3,
0xb3, 0xe0, 0xb7, 0x5c, 0x55, 0x6a, 0x0f, 0x44,
0x91, 0xe8, 0x98, 0xb3, 0xb4, 0xd3, 0x07, 0x8e,
0x85, 0x8e, 0xc0, 0xcb, 0x85, 0x92, 0x0e, 0xca,
0x7c, 0x03, 0x23, 0xa0, 0x1f, 0x4e, 0x75, 0x01,
0x95, 0x61, 0x2c, 0x21, 0x2f, 0x4f, 0x6d, 0x55,
0xa3, 0xcc, 0x23, 0x62, 0x7f, 0xcb, 0x0a, 0x8a,
0x8b, 0x82, 0xb5, 0x8c, 0x8a, 0xaa, 0x88, 0xb4,
0x65, 0x82, 0x6d, 0x12, 0x4a, 0x06, 0xe7, 0xde,
0xcd, 0x3c, 0xf9, 0x1c, 0x02, 0x9c, 0xf8, 0x21,
0x20, 0x30, 0x82, 0x05, 0x85, 0x30, 0x82, 0x03,
0x6d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10,
0x03, 0xb1, 0xf7, 0x58, 0xdf, 0x1d, 0xe3, 0x25,
0x00, 0x0b, 0x10, 0x3d, 0xd5, 0xe6, 0xe4, 0x64,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67,
0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69,
0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f,
0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69,
0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64,
0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f,
0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30,
0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x31, 0x31,
0x38, 0x30, 0x31, 0x31, 0x33, 0x33, 0x35, 0x5a,
0x17, 0x0d, 0x32, 0x37, 0x31, 0x31, 0x31, 0x38,
0x30, 0x31, 0x31, 0x33, 0x31, 0x33, 0x5a, 0x30,
0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69,
0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f,
0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69,
0x6e, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79, 0x73,
0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20,
0x37, 0x39, 0x31, 0x33, 0x30, 0x82, 0x01, 0x22,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc8, 0x71,
0xae, 0x08, 0x0c, 0x06, 0x06, 0x2d, 0x81, 0x7c,
0xa9, 0x8b, 0xb3, 0xd6, 0x66, 0xe4, 0xf6, 0x08,
0x5e, 0x5a, 0x75, 0xe8, 0x74, 0x61, 0x7a, 0x88,
0xca, 0x85, 0x14, 0x0d, 0x58, 0xa4, 0x09, 0x19,
0x6c, 0x60, 0xc9, 0xad, 0x91, 0x1c, 0xbf, 0x04,
0xb3, 0x47, 0x10, 0x63, 0x7f, 0x02, 0x58, 0xc2,
0x1e, 0xbd, 0xcc, 0x07, 0x77, 0xaa, 0x7e, 0x14,
0xa8, 0xc2, 0x01, 0xcd, 0xe8, 0x46, 0x60, 0x53,
0x6f, 0x2f, 0xda, 0x17, 0x2d, 0x4d, 0x9d, 0x0e,
0x5d, 0xb5, 0x50, 0x95, 0xae, 0xab, 0x6e, 0x43,
0xe3, 0xb0, 0x00, 0x12, 0xb4, 0x05, 0x82, 0x4a,
0x2b, 0x14, 0x63, 0x0d, 0x1f, 0x06, 0x12, 0xaa,
0xe1, 0x9d, 0xe7, 0xba, 0xda, 0xe3, 0xfc, 0x7c,
0x6c, 0x73, 0xae, 0x56, 0xf8, 0xab, 0xf7, 0x51,
0x93, 0x31, 0xef, 0x8f, 0xe4, 0xb6, 0x01, 0x2c,
0xeb, 0x7b, 0xe4, 0xd8, 0xb3, 0xea, 0x70, 0x37,
0x89, 0x05, 0xa9, 0x51, 0x57, 0x72, 0x98, 0x9e,
0xa8, 0x46, 0xdb, 0xeb, 0x7a, 0x38, 0x2b, 0x2f,
0xc0, 0x27, 0xb7, 0xc2, 0xe1, 0x9a, 0x17, 0xdf,
0xf5, 0xd6, 0x9c, 0xd5, 0x8c, 0xb8, 0x66, 0x42,
0xd5, 0x04, 0x1e, 0x7c, 0x36, 0x4c, 0x1e, 0x3e,
0x45, 0x51, 0x4d, 0x41, 0x72, 0x22, 0x53, 0x3d,
0xf4, 0x57, 0x7c, 0x6c, 0x33, 0x34, 0x24, 0x45,
0xdf, 0x84, 0x87, 0x4a, 0xa6, 0xcb, 0x7c, 0x03,
0xa3, 0xaa, 0x8e, 0x2d, 0x82, 0x01, 0x27, 0x87,
0x74, 0x82, 0x1a, 0xbc, 0x0f, 0x76, 0x69, 0xab,
0xe0, 0x4e, 0x70, 0xbe, 0x37, 0xfc, 0xc8, 0x2c,
0x91, 0x17, 0x4f, 0xd5, 0x26, 0x3b, 0x7b, 0x90,
0xb5, 0x2d, 0x64, 0xba, 0xf7, 0xd2, 0x8a, 0xb4,
0x8f, 0x38, 0x9d, 0x8e, 0xba, 0xe7, 0x5c, 0x52,
0xf1, 0x0a, 0xb8, 0xc0, 0x1b, 0xb6, 0xb1, 0x70,
0x7e, 0x47, 0x59, 0x94, 0x59, 0x02, 0x03, 0x01,
0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82,
0x01, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d,
0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06,
0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e,
0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x1d,
0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
0x14, 0x4b, 0xcb, 0xdf, 0xaa, 0x02, 0xde, 0x8d,
0xc3, 0xe7, 0xe5, 0x85, 0xdb, 0x2e, 0x8a, 0xbe,
0x75, 0x6b, 0x8a, 0x67, 0x58, 0x30, 0x81, 0xb2,
0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa,
0x30, 0x81, 0xa7, 0x80, 0x14, 0x04, 0x94, 0x66,
0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7,
0x13, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a,
0x8f, 0xa1, 0x81, 0x83, 0xa4, 0x81, 0x80, 0x30,
0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67,
0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69,
0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f,
0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69,
0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64,
0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f,
0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82,
0x09, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe,
0x9a, 0x9a, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06,
0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01,
0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
0x01, 0x00, 0x61, 0x3f, 0x2f, 0x43, 0xe4, 0xbe,
0x66, 0x34, 0xef, 0x92, 0x06, 0xe9, 0x88, 0xba,
0x6a, 0x1d, 0x4f, 0x54, 0x5a, 0x97, 0xb1, 0x75,
0xd7, 0x93, 0xf8, 0x45, 0xc6, 0x83, 0x92, 0x36,
0xfd, 0x55, 0xa9, 0x21, 0x0b, 0xdc, 0xf6, 0xae,
0x11, 0xdc, 0x62, 0x21, 0x44, 0xbd, 0x04, 0x1d,
0x58, 0x2c, 0x03, 0xf8, 0xe4, 0xe2, 0x1e, 0xba,
0xe6, 0xdd, 0x19, 0xdd, 0x56, 0xfd, 0xce, 0x06,
0x73, 0x5f, 0x94, 0x1e, 0xb6, 0x03, 0xdb, 0x3d,
0x7b, 0xab, 0xab, 0x72, 0x64, 0x7b, 0xde, 0x7d,
0x4d, 0xcf, 0x7e, 0xf0, 0x91, 0x29, 0xc1, 0x77,
0x13, 0xc2, 0x6f, 0x80, 0xab, 0x7a, 0xa8, 0xce,
0xb0, 0x1c, 0x2a, 0xc5, 0x9c, 0xfb, 0x0b, 0xe5,
0x9f, 0x9c, 0x1b, 0xc9, 0x4b, 0x58, 0xdf, 0x96,
0x18, 0xf7, 0x67, 0x67, 0x89, 0xa4, 0xe9, 0x14,
0x48, 0xac, 0xfa, 0x9d, 0x86, 0x2a, 0xeb, 0x75,
0x2c, 0x2b, 0xbf, 0x63, 0x7d, 0xc7, 0x4e, 0x7e,
0xad, 0x39, 0x2d, 0xb4, 0x7c, 0x07, 0xa5, 0x5a,
0xe8, 0x3a, 0xd4, 0xf5, 0x0c, 0x4f, 0xf3, 0xa2,
0x9c, 0x3c, 0x32, 0xed, 0x9d, 0x4b, 0x49, 0x05,
0xbc, 0x1f, 0xa0, 0x13, 0xe6, 0xdd, 0x82, 0x79,
0x06, 0x31, 0x3b, 0xc6, 0x97, 0xec, 0x8d, 0xaa,
0x4f, 0xef, 0x14, 0x3c, 0x21, 0xf6, 0x72, 0xb2,
0x09, 0x42, 0xc7, 0x74, 0xfe, 0xef, 0x70, 0xbd,
0xe9, 0x85, 0x41, 0x30, 0x0b, 0xb3, 0x6b, 0x59,
0x0c, 0x0f, 0x11, 0x75, 0xd4, 0xbb, 0xb1, 0xdf,
0xb1, 0xdf, 0xb3, 0xfa, 0xb3, 0x3a, 0x43, 0x17,
0x7d, 0x8a, 0x82, 0xae, 0xa2, 0x07, 0xf8, 0x83,
0x51, 0xfb, 0x16, 0xfb, 0x64, 0xb6, 0x46, 0xda,
0xbe, 0x32, 0x2b, 0xc0, 0xee, 0x78, 0x2a, 0x84,
0xa9, 0x54, 0x0a, 0xf9, 0x2d, 0x61, 0x65, 0xde,
0xa5, 0x97, 0x66, 0x79, 0x02, 0xf8, 0x97, 0x17,
0xe2, 0xd4, 0x9f, 0x9e, 0xac, 0xcc, 0xae, 0x99,
0x9a, 0x03, 0x04, 0xbb, 0x45, 0xfe, 0xb2, 0xf5,
0x80, 0xba, 0xbf, 0xdd, 0x24, 0xe5, 0xe6, 0x1e,
0x5d, 0x36, 0xa5, 0x87, 0x0c, 0xdf, 0x60, 0x81,
0x6f, 0xb7, 0x5f, 0xb9, 0x1f, 0xca, 0x75, 0x3c,
0x1a, 0x63, 0xb0, 0xeb, 0xe6, 0x95, 0x86, 0x0d,
0xae, 0xa6, 0xc9, 0x2a, 0x94, 0xf1, 0xd0, 0xbe,
0x75, 0xc8, 0xf8, 0x07, 0xd7, 0x88, 0xff, 0xec,
0xf9, 0xcd, 0x49, 0xc6, 0xfe, 0x4d, 0x7f, 0x44,
0x1e, 0xd8, 0xaf, 0xa9, 0x72, 0x27, 0x98, 0xe2,
0x5a, 0x08, 0xea, 0x55, 0xd3, 0xb3, 0xea, 0xdc,
0x76, 0x69, 0x51, 0x10, 0x01, 0x46, 0x7d, 0x33,
0x94, 0x9c, 0x94, 0xef, 0xfe, 0x76, 0x1c, 0xc6,
0xd7, 0x15, 0x53, 0x3e, 0x8d, 0x3d, 0x29, 0x9a,
0x58, 0x6a, 0xf1, 0x75, 0x9e, 0xea, 0x1b, 0x4c,
0xf0, 0x47, 0x76, 0xac, 0xc6, 0xa2, 0x32, 0x44,
0x40, 0xdf, 0xfe, 0xff, 0x9d, 0xf4, 0xe2, 0xc2,
0xfa, 0xa1, 0x5f, 0x2e, 0x66, 0xe9, 0x97, 0xcb,
0x27, 0x26, 0x6e, 0x53, 0xe4, 0xe8, 0x86, 0x2c,
0xea, 0xd3, 0x69, 0x6c, 0x61, 0x4f, 0xfe, 0xc1,
0xc9, 0x8b, 0x05, 0x92, 0x6f, 0x47, 0x96, 0xce,
0xf0, 0x33, 0xfa, 0x7c, 0x78, 0x24, 0x9b, 0xd7,
0x8d, 0x36, 0x56, 0x37, 0x86, 0xbc, 0x72, 0x5a,
0xf9, 0xb9, 0xb0, 0x93, 0xf0, 0x81, 0x78, 0x10,
0xf2, 0xb0, 0xc2, 0x79, 0x91, 0x5e, 0xcf, 0xbc,
0x8c, 0xf2, 0x32, 0x0f, 0xf7, 0x2d, 0x30, 0xd8,
0x13, 0x77, 0x4f, 0x78, 0x9e, 0x40, 0x8d, 0xe6,
0x3a, 0x98, 0xb2, 0xaa, 0x13, 0x4d, 0x25, 0x49,
0x34, 0x6c, 0x80, 0x9e, 0x19, 0x03, 0xdb, 0xcd,
0xf5, 0xb1, 0x54, 0x74, 0x1b, 0x67, 0x3c, 0x46,
0xac, 0x3e, 0x5d, 0xa2, 0xd9, 0x13, 0x83, 0x30,
0xeb, 0x82, 0x3b, 0x06, 0xab, 0x3c, 0x39, 0x7d,
0xd0, 0x68, 0x31, 0x00
};
// clang-format on
} // namespace
const size_t kTestOemPublicCertSize = sizeof(kTestOemPublicCert);
const uint32_t kOEMSystemId = kTestOemSystemId;
const uint8_t* kOEMPrivateKey = kTestOemPrivateKey;
const uint8_t* kOEMPublicCert = kTestOemPublicCert;
const size_t kOEMPrivateKeySize = kTestOemPrivateKeySize;
const size_t kOEMPublicCertSize = kTestOemPublicCertSize;
} // namespace wvoec_ref

View File

@@ -1,232 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include <gtest/gtest.h>
#include "OEMCryptoCENCCommon.h"
#include "oemcrypto_ecc_key.h"
#include "oemcrypto_ref_test_utils.h"
namespace wvoec_ref {
constexpr size_t kMessageSize = 4 * 1024; // 4 kB
class OEMCryptoEccKeyTest : public ::testing::TestWithParam<EccCurve> {
public:
void SetUp() override { key_ = EccPrivateKey::New(GetParam()); }
void TearDown() override { key_.reset(); }
protected:
std::unique_ptr<EccPrivateKey> key_;
};
// Basic verification of ECC private key generation.
TEST_P(OEMCryptoEccKeyTest, KeyProperties) {
ASSERT_TRUE(key_);
const EccCurve expected_curve = GetParam();
EXPECT_EQ(key_->curve(), expected_curve);
EXPECT_NE(nullptr, key_->GetEcKey());
}
// Checks that the private key serialization APIs are compatible
// and performing in a manner that is similar to other OEMCrypto methods
// that retrieve data.
TEST_P(OEMCryptoEccKeyTest, SerializePrivateKey) {
ASSERT_TRUE(key_);
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
key_->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, key_->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = key_->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << i;
}
}
// Checks that a private key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoEccKeyTest, SerializeAndReloadPrivateKey) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> key_data = key_->Serialize();
std::unique_ptr<EccPrivateKey> loaded_key = EccPrivateKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(key_->curve(), loaded_key->curve());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << i;
}
}
// Checks that a public key can be created from the private key.
TEST_P(OEMCryptoEccKeyTest, DerivePublicKey) {
ASSERT_TRUE(key_);
std::unique_ptr<EccPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_TRUE(key_->IsMatchingPublicKey(*pub_key));
}
// Checks that a public key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoEccKeyTest, SerializePublicKey) {
ASSERT_TRUE(key_);
std::unique_ptr<EccPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
pub_key->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = pub_key->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << i;
}
}
// Checks that a public key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
// It is anticipated that OEMCrypto will need to parse the licensing
// server's ephemerial key when deriving the session key.
TEST_P(OEMCryptoEccKeyTest, SerializeAndReloadPublicKey) {
ASSERT_TRUE(key_);
std::unique_ptr<EccPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
const std::vector<uint8_t> key_data = pub_key->Serialize();
std::unique_ptr<EccPublicKey> loaded_key = EccPublicKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(pub_key->curve(), loaded_key->curve());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << i;
}
}
// Checks that the ECC signature generating API operates similar to
// existing signature generation functions.
TEST_P(OEMCryptoEccKeyTest, GenerateSignature) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t signature_size = kInitialBufferSize;
std::vector<uint8_t> signature(signature_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
key_->GenerateSignature(message.data(), message.size(),
signature.data(), &signature_size));
EXPECT_GT(signature_size, kInitialBufferSize);
signature.resize(signature_size);
EXPECT_EQ(OEMCrypto_SUCCESS,
key_->GenerateSignature(message.data(), message.size(),
signature.data(), &signature_size));
signature.resize(signature_size);
EXPECT_LE(signature_size, key_->SignatureSize());
}
// Checks that ECC signatures can be verified by an ECC public key.
TEST_P(OEMCryptoEccKeyTest, VerifySignature) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
const std::vector<uint8_t> signature = key_->GenerateSignature(message);
std::unique_ptr<EccPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->VerifySignature(message, signature));
// Check with different message.
const std::vector<uint8_t> message_two = RandomData(kMessageSize);
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message_two, signature));
// Check with bad signature.
const std::vector<uint8_t> bad_signature = RandomData(signature.size());
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message, bad_signature));
}
// Verifies the session key exchange protocol used by the licensing
// server.
TEST_P(OEMCryptoEccKeyTest, DeriveSessionKey) {
ASSERT_TRUE(key_);
// Set up Alice.
EccPrivateKey* alice_private_key = key_.get();
std::unique_ptr<EccPublicKey> alice_public_key =
alice_private_key->MakePublicKey();
ASSERT_TRUE(alice_public_key);
// Set up Bob.
std::unique_ptr<EccPrivateKey> bob_private_key =
EccPrivateKey::New(alice_private_key->curve());
ASSERT_TRUE(bob_private_key);
std::unique_ptr<EccPublicKey> bob_public_key =
bob_private_key->MakePublicKey();
ASSERT_TRUE(bob_public_key);
const size_t session_key_length = alice_private_key->SessionKeyLength();
EXPECT_EQ(session_key_length, bob_private_key->SessionKeyLength());
// From Alice's perspective.
const std::vector<uint8_t> alice_session_key =
alice_private_key->DeriveSessionKey(*bob_public_key);
// From Bob's perspective.
const std::vector<uint8_t> bob_session_key =
bob_private_key->DeriveSessionKey(*alice_public_key);
// Both should have the same session key.
ASSERT_EQ(session_key_length, alice_session_key.size());
ASSERT_EQ(session_key_length, bob_session_key.size());
for (size_t i = 0; i < session_key_length; i++) {
ASSERT_EQ(alice_session_key[i], bob_session_key[i]) << "i = " << i;
}
}
INSTANTIATE_TEST_CASE_P(AllCurves, OEMCryptoEccKeyTest,
::testing::Values(kEccSecp256r1, kEccSecp384r1,
kEccSecp521r1));
} // namespace wvoec_ref

View File

@@ -1,115 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include <gtest/gtest.h>
#include "OEMCryptoCENCCommon.h"
#include "oem_cert.h"
#include "oemcrypto_oem_cert.h"
#include "oemcrypto_rsa_key.h"
namespace wvoec_ref {
namespace {
const std::vector<uint8_t> kOEMPrivateKeyVector(kOEMPrivateKey,
kOEMPrivateKey +
kOEMPrivateKeySize);
const std::vector<uint8_t> kOEMPublicCertVector(kOEMPublicCert,
kOEMPublicCert +
kOEMPublicCertSize);
} // namespace
// Creates an OemCertificate wrapper around the built-in reference
// OEM cert.
// Creating the OemCertificate should succeed so long as the data
// is well-formed.
// Validating the OEM cert should succeed (assuming built-in cert+key
// are valid).
TEST(OEMCryptoOemCertTest, CreateFromArray) {
std::unique_ptr<OemCertificate> oem_cert = OemCertificate::Create(
kOEMPrivateKey, kOEMPrivateKeySize, kOEMPublicCert, kOEMPublicCertSize);
ASSERT_TRUE(oem_cert);
EXPECT_EQ(OemCertificate::kRsa, oem_cert->key_type());
const std::vector<uint8_t> private_key = oem_cert->GetPrivateKey();
EXPECT_EQ(kOEMPrivateKeyVector, private_key);
size_t public_cert_size = 10;
std::vector<uint8_t> public_cert(public_cert_size, 0);
EXPECT_EQ(
OEMCrypto_ERROR_SHORT_BUFFER,
oem_cert->GetPublicCertificate(public_cert.data(), &public_cert_size));
public_cert.resize(public_cert_size);
EXPECT_EQ(OEMCrypto_SUCCESS, oem_cert->GetPublicCertificate(
public_cert.data(), &public_cert_size));
EXPECT_EQ(kOEMPublicCertSize, public_cert_size);
EXPECT_EQ(kOEMPublicCertVector, public_cert);
EXPECT_EQ(OEMCrypto_SUCCESS, oem_cert->IsCertificateValid());
}
TEST(OEMCryptoOemCertTest, CreateFromVector) {
std::unique_ptr<OemCertificate> oem_cert =
OemCertificate::Create(kOEMPrivateKeyVector, kOEMPublicCertVector);
ASSERT_TRUE(oem_cert);
EXPECT_EQ(OemCertificate::kRsa, oem_cert->key_type());
const std::vector<uint8_t> private_key = oem_cert->GetPrivateKey();
EXPECT_EQ(kOEMPrivateKeyVector, private_key);
const std::vector<uint8_t> public_cert = oem_cert->GetPublicCertificate();
EXPECT_EQ(kOEMPublicCertVector, public_cert);
EXPECT_EQ(OEMCrypto_SUCCESS, oem_cert->IsCertificateValid());
}
// Creation of OemCertificate wrapper should fail if the provided
// key is not well-formed.
TEST(OEMCryptoOemCertTest, CreateWithABadPrivateKey) {
static const uint8_t kBadPrivateKeyData[] = {'n', 'o', 't', ' ', 'a', ' ',
'p', 'r', 'i', 'v', 'a', 't',
'e', 'k', 'e', 'y'};
std::unique_ptr<OemCertificate> oem_cert =
OemCertificate::Create(kBadPrivateKeyData, sizeof(kBadPrivateKeyData),
kOEMPublicCert, kOEMPublicCertSize);
EXPECT_FALSE(oem_cert);
}
// Creation of OemCertificate wrapper should fail if the provided
// OEM Public Cert is not well-formed.
TEST(OEMCryptoOemCertTest, CreateWithABadPublicCert) {
static const uint8_t kBadPublicCert[] = {'n', 'o', 't', ' ', 'a', ' ', 'o',
'e', 'm', ' ', 'p', 'u', 'b', 'l',
'i', 'c', ' ', 'c', 'e', 'r', 't'};
std::unique_ptr<OemCertificate> oem_cert =
OemCertificate::Create(kOEMPrivateKey, kOEMPrivateKeySize, kBadPublicCert,
sizeof(kBadPublicCert));
EXPECT_FALSE(oem_cert);
}
// It is possible to create an OEM Certificate using a non-matching
// public-private key pair so long as the key types are the same.
// However, OEM Cert validation should catch the problem.
TEST(OEMCryptoOemCertTest, CreateWithDifferentPrivateRsaKey) {
std::unique_ptr<RsaPrivateKey> key = RsaPrivateKey::New(kRsa2048Bit);
ASSERT_TRUE(key);
const std::vector<uint8_t> private_key = key->Serialize();
ASSERT_FALSE(private_key.empty());
// Creating the OEM Certificate should succeed.
std::unique_ptr<OemCertificate> oem_cert =
OemCertificate::Create(private_key, kOEMPublicCertVector);
ASSERT_TRUE(oem_cert);
EXPECT_EQ(OemCertificate::kRsa, oem_cert->key_type());
// Validating key should return an error.
EXPECT_EQ(OEMCrypto_ERROR_INVALID_RSA_KEY, oem_cert->IsCertificateValid());
}
} // namespace wvoec_ref

View File

@@ -1,20 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_ref_test_utils.h"
#include <string>
#include "cdm_random.h"
namespace wvoec_ref {
std::vector<uint8_t> RandomData(size_t length) {
const std::string data = wvcdm::CdmRandom::RandomData(length);
return std::vector<uint8_t>(data.begin(), data.end());
}
} // namespace wvoec_ref

View File

@@ -1,21 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_REF_TEST_UTILS_H_
#define OEMCRYPTO_REF_TEST_UTILS_H_
#include <stdint.h>
#include <vector>
namespace wvoec_ref {
// Returns a vector of random bytes.
std::vector<uint8_t> RandomData(size_t length);
} // namespace wvoec_ref
#endif // OEMCRYPTO_REF_TEST_UTILS_H_

View File

@@ -1,406 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include <stdlib.h>
#include <mutex>
#include <gtest/gtest.h>
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oemcrypto_ref_test_utils.h"
#include "oemcrypto_rsa_key.h"
namespace wvoec_ref {
constexpr size_t kMessageSize = 4 * 1024; // 4 kB
constexpr size_t kCastMessageSize = 83; // Special max size.
class OEMCryptoRsaKeyTest : public ::testing::TestWithParam<RsaFieldSize> {
public:
void SetUp() override {
// RSA key generation is slow (~2 seconds) compared to the
// operations they perform (<50 ms). Each key type is generated
// once and globally stored in serialized form.
// Caching the instance may result in test failures for
// memory-leak detection.
const RsaFieldSize field_size = GetParam();
std::lock_guard<std::mutex> rsa_key_lock(rsa_key_mutex_);
// Use of a switch case is intentional to cause compiler warnings
// if a new field size is introduced without updating the test.
switch (field_size) {
case kRsa2048Bit: {
if (!rsa_2048_key_data_.empty()) {
key_ = RsaPrivateKey::Load(rsa_2048_key_data_);
}
if (!key_) {
key_ = RsaPrivateKey::New(kRsa2048Bit);
}
if (rsa_2048_key_data_.empty() && key_) {
rsa_2048_key_data_ = key_->Serialize();
}
} break;
case kRsa3072Bit: {
if (!rsa_3072_key_data_.empty()) {
key_ = RsaPrivateKey::Load(rsa_3072_key_data_);
}
if (!key_) {
key_ = RsaPrivateKey::New(kRsa3072Bit);
}
if (rsa_3072_key_data_.empty() && key_) {
rsa_3072_key_data_ = key_->Serialize();
}
} break;
case kRsaFieldUnknown: // Suppress compiler warnings
LOGE("RSA test was incorrectly instantiation");
exit(EXIT_FAILURE);
break;
}
}
void TearDown() override { key_.reset(); }
protected:
std::unique_ptr<RsaPrivateKey> key_;
static std::mutex rsa_key_mutex_;
static std::vector<uint8_t> rsa_2048_key_data_;
static std::vector<uint8_t> rsa_3072_key_data_;
};
std::mutex OEMCryptoRsaKeyTest::rsa_key_mutex_;
std::vector<uint8_t> OEMCryptoRsaKeyTest::rsa_2048_key_data_;
std::vector<uint8_t> OEMCryptoRsaKeyTest::rsa_3072_key_data_;
// Basic verification of RSA private key generation.
TEST_P(OEMCryptoRsaKeyTest, KeyProperties) {
ASSERT_TRUE(key_);
const RsaFieldSize expected_field_size = GetParam();
EXPECT_EQ(key_->field_size(), expected_field_size);
EXPECT_NE(nullptr, key_->GetRsaKey());
}
// Checks that the private key serialization APIs are compatible
// and performing in a manner that is similar to other OEMCrypto methods
// that retrieve data.
TEST_P(OEMCryptoRsaKeyTest, SerializePrivateKey) {
ASSERT_TRUE(key_);
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
key_->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, key_->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = key_->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a private key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPrivateKey) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> key_data = key_->Serialize();
std::unique_ptr<RsaPrivateKey> loaded_key = RsaPrivateKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(key_->field_size(), loaded_key->field_size());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a private key with explicitly indicated schemes include
// the scheme fields in the reserialized key.
TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPrivateKeyWithAllowedSchemes) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> raw_key_data = key_->Serialize();
std::vector<uint8_t> key_data = {'S', 'I', 'G', 'N', 0x00, 0x00, 0x00, 0x03};
key_data.insert(key_data.end(), raw_key_data.begin(), raw_key_data.end());
std::unique_ptr<RsaPrivateKey> explicit_key = RsaPrivateKey::Load(key_data);
ASSERT_TRUE(explicit_key);
EXPECT_EQ(key_->field_size(), explicit_key->field_size());
EXPECT_EQ(explicit_key->allowed_schemes(), 0x03);
const std::vector<uint8_t> explicit_key_data = explicit_key->Serialize();
ASSERT_EQ(key_data.size(), explicit_key_data.size());
ASSERT_EQ(key_data, explicit_key_data);
}
// Checks that a public key can be created from the private key.
TEST_P(OEMCryptoRsaKeyTest, DerivePublicKey) {
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_TRUE(key_->IsMatchingPublicKey(*pub_key));
}
// Checks that the public key serialization APIs are compatible
// and performing in a manner that is similar to other OEMCrypto methods
// that retrieve data.
TEST_P(OEMCryptoRsaKeyTest, SerializePublicKey) {
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t buffer_size = kInitialBufferSize;
std::vector<uint8_t> buffer(buffer_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
pub_key->Serialize(buffer.data(), &buffer_size));
EXPECT_GT(buffer_size, kInitialBufferSize);
buffer.resize(buffer_size);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->Serialize(buffer.data(), &buffer_size));
buffer.resize(buffer_size);
const std::vector<uint8_t> direct_key_data = pub_key->Serialize();
EXPECT_FALSE(direct_key_data.empty());
ASSERT_EQ(buffer.size(), direct_key_data.size());
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that a public key that is serialized can be deserialized and
// reload. Also checks that the serialization of a key produces the
// same data to ensure consistency.
TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPublicKey) {
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
const std::vector<uint8_t> key_data = pub_key->Serialize();
std::unique_ptr<RsaPublicKey> loaded_key = RsaPublicKey::Load(key_data);
ASSERT_TRUE(loaded_key);
EXPECT_EQ(pub_key->field_size(), loaded_key->field_size());
EXPECT_EQ(pub_key->allowed_schemes(), loaded_key->allowed_schemes());
const std::vector<uint8_t> loaded_key_data = loaded_key->Serialize();
ASSERT_EQ(key_data.size(), loaded_key_data.size());
for (size_t i = 0; i < key_data.size(); i++) {
ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << std::to_string(i);
}
}
// Checks that the RSA signature generating API operates similar to
// existing signature generation functions.
TEST_P(OEMCryptoRsaKeyTest, GenerateSignature) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t signature_size = kInitialBufferSize;
std::vector<uint8_t> signature(signature_size);
EXPECT_EQ(
OEMCrypto_ERROR_SHORT_BUFFER,
key_->GenerateSignature(message.data(), message.size(), kRsaPssDefault,
signature.data(), &signature_size));
EXPECT_GT(signature_size, kInitialBufferSize);
signature.resize(signature_size);
EXPECT_EQ(
OEMCrypto_SUCCESS,
key_->GenerateSignature(message.data(), message.size(), kRsaPssDefault,
signature.data(), &signature_size));
signature.resize(signature_size);
EXPECT_LE(signature_size, key_->SignatureSize());
}
// Checks that RSA signatures can be verified by an RSA public key.
TEST_P(OEMCryptoRsaKeyTest, VerifySignature) {
ASSERT_TRUE(key_);
const std::vector<uint8_t> message = RandomData(kMessageSize);
ASSERT_FALSE(message.empty()) << "CdmRandom failed";
const std::vector<uint8_t> signature = key_->GenerateSignature(message);
std::unique_ptr<RsaPublicKey> pub_key = key_->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->VerifySignature(message, signature));
// Check with different message.
const std::vector<uint8_t> message_two = RandomData(kMessageSize);
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message_two, signature));
// Check with bad signature.
const std::vector<uint8_t> bad_signature = RandomData(signature.size());
EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
pub_key->VerifySignature(message, bad_signature));
}
// Checks that the special CAST receiver signature scheme works
// to the degree that it is possible to test.
TEST_P(OEMCryptoRsaKeyTest, GenerateAndVerifyRsaSignature) {
ASSERT_TRUE(key_);
// Key must be enabled for PKCS1 Block 1 padding scheme.
// To do so, the key is serialized and the padding scheme is
// added to the key data.
const std::vector<uint8_t> key_data = key_->Serialize();
ASSERT_FALSE(key_data.empty());
std::vector<uint8_t> pkcs_enabled_key_data = {
'S', 'I', 'G', 'N', 0x00, 0x00, 0x00, kSign_PKCS1_Block1};
pkcs_enabled_key_data.insert(pkcs_enabled_key_data.end(), key_data.begin(),
key_data.end());
std::unique_ptr<RsaPrivateKey> pkcs_enabled_key =
RsaPrivateKey::Load(pkcs_enabled_key_data);
ASSERT_TRUE(pkcs_enabled_key);
// The actual cast message is a domain specific hash of the message,
// however, random data works for testing purposes.
const std::vector<uint8_t> message = RandomData(kCastMessageSize);
// Generate signature.
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t signature_size = kInitialBufferSize;
std::vector<uint8_t> signature(signature_size);
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
pkcs_enabled_key->GenerateSignature(message.data(), message.size(),
kRsaPkcs1Cast, signature.data(),
&signature_size));
EXPECT_GT(signature_size, kInitialBufferSize);
signature.resize(signature_size);
EXPECT_EQ(OEMCrypto_SUCCESS,
pkcs_enabled_key->GenerateSignature(message.data(), message.size(),
kRsaPkcs1Cast, signature.data(),
&signature_size));
signature.resize(signature_size);
EXPECT_LE(signature_size, pkcs_enabled_key->SignatureSize());
// Verify signature.
std::unique_ptr<RsaPublicKey> pub_key = pkcs_enabled_key->MakePublicKey();
ASSERT_TRUE(pub_key);
EXPECT_EQ(OEMCrypto_SUCCESS,
pub_key->VerifySignature(message, signature, kRsaPkcs1Cast));
}
// Verifies the session key exchange protocol used by the licensing
// server.
TEST_P(OEMCryptoRsaKeyTest, ShareSessionKey) {
constexpr size_t kSessionKeySize = 16;
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> public_key = key_->MakePublicKey();
ASSERT_TRUE(public_key);
// Generate session key.
const std::vector<uint8_t> session_key = RandomData(kSessionKeySize);
ASSERT_FALSE(session_key.empty());
// Server's perspective.
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t enc_session_key_size = kInitialBufferSize;
std::vector<uint8_t> enc_session_key(enc_session_key_size);
OEMCryptoResult result = public_key->EncryptSessionKey(
session_key.data(), session_key.size(), enc_session_key.data(),
&enc_session_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
enc_session_key.resize(enc_session_key_size);
result = public_key->EncryptSessionKey(session_key.data(), session_key.size(),
enc_session_key.data(),
&enc_session_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
enc_session_key.resize(enc_session_key_size);
// Client's perspective.
size_t received_session_key_size = kInitialBufferSize;
std::vector<uint8_t> received_session_key(received_session_key_size);
result = key_->DecryptSessionKey(
enc_session_key.data(), enc_session_key.size(),
received_session_key.data(), &received_session_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
received_session_key.resize(received_session_key_size);
result = key_->DecryptSessionKey(
enc_session_key.data(), enc_session_key.size(),
received_session_key.data(), &received_session_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
received_session_key.resize(received_session_key_size);
// Compare keys.
ASSERT_EQ(session_key.size(), received_session_key.size());
ASSERT_EQ(session_key, received_session_key);
}
// Verifies the encryption key exchange protocol used by the licensing
// server.
TEST_P(OEMCryptoRsaKeyTest, ShareEncryptionKey) {
constexpr size_t kEncryptionKeySize = 16;
ASSERT_TRUE(key_);
std::unique_ptr<RsaPublicKey> public_key = key_->MakePublicKey();
ASSERT_TRUE(public_key);
// Generate session key.
const std::vector<uint8_t> encryption_key = RandomData(kEncryptionKeySize);
ASSERT_FALSE(encryption_key.empty());
// Server's perspective.
constexpr size_t kInitialBufferSize = 10; // Definitely too small.
size_t enc_encryption_key_size = kInitialBufferSize;
std::vector<uint8_t> enc_encryption_key(enc_encryption_key_size);
OEMCryptoResult result = public_key->EncryptEncryptionKey(
encryption_key.data(), encryption_key.size(), enc_encryption_key.data(),
&enc_encryption_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
enc_encryption_key.resize(enc_encryption_key_size);
result = public_key->EncryptEncryptionKey(
encryption_key.data(), encryption_key.size(), enc_encryption_key.data(),
&enc_encryption_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
enc_encryption_key.resize(enc_encryption_key_size);
// Client's perspective.
size_t received_encryption_key_size = kInitialBufferSize;
std::vector<uint8_t> received_encryption_key(received_encryption_key_size);
result = key_->DecryptEncryptionKey(
enc_encryption_key.data(), enc_encryption_key.size(),
received_encryption_key.data(), &received_encryption_key_size);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
received_encryption_key.resize(received_encryption_key_size);
result = key_->DecryptEncryptionKey(
enc_encryption_key.data(), enc_encryption_key.size(),
received_encryption_key.data(), &received_encryption_key_size);
ASSERT_EQ(OEMCrypto_SUCCESS, result);
received_encryption_key.resize(received_encryption_key_size);
// Compare keys.
ASSERT_EQ(encryption_key.size(), received_encryption_key.size());
ASSERT_EQ(encryption_key, received_encryption_key);
}
INSTANTIATE_TEST_CASE_P(AllFieldSizes, OEMCryptoRsaKeyTest,
::testing::Values(kRsa2048Bit, kRsa3072Bit));
} // namespace wvoec_ref

View File

@@ -1,74 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include <gtest/gtest.h>
#include "wvcrc32.h"
namespace wvoec_ref {
uint32_t ComputeCrc32(const std::string& s) {
return wvcrc32(reinterpret_cast<const uint8_t*>(s.data()), s.size());
}
uint32_t ComputeCrc32Cont(const std::string& s, uint32_t prev_crc) {
return wvcrc32Cont(reinterpret_cast<const uint8_t*>(s.data()), s.size(),
prev_crc);
}
TEST(OEMCryptoWvCrc32Test, BasicTest) {
EXPECT_EQ(0xF88AC628, ComputeCrc32("abcdefg"));
EXPECT_EQ(0xDF520F72, ComputeCrc32("Widevine"));
EXPECT_EQ(0x0376E6E7, ComputeCrc32("123456789"));
EXPECT_EQ(0xBA62119E,
ComputeCrc32("The quick brown fox jumps over the lazy dog"));
}
TEST(OEMCryptoWvCrc32Test, StreamTest) {
const std::vector<std::string> parts = {"The ", "quick", " brown ",
"fox", " jumps ", "over",
" the ", "lazy", " dog"};
uint32_t crc = wvcrc32Init();
for (const auto& part : parts) {
crc = ComputeCrc32Cont(part, crc);
}
EXPECT_EQ(0xBA62119E, crc);
}
TEST(OEMCryptoWvCrc32Test, Keybox) {
// clang-format off
const uint8_t kKeyboxData[128] = {
// deviceID = WidevineCRCTestKeyBox
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
0x43, 0x52, 0x43, 0x54, 0x65, 0x73, 0x74, 0x4b,
0x65, 0x79, 0x62, 0x6f, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// key = random
0x8a, 0x7c, 0xda, 0x3e, 0x09, 0xd9, 0x8e, 0xd5,
0x47, 0x47, 0x00, 0x84, 0x5a, 0x1f, 0x52, 0xd4,
// data = random
0x98, 0xa5, 0x00, 0x19, 0x8b, 0xfe, 0x54, 0xfd,
0xca, 0x4d, 0x26, 0xa3, 0xfa, 0xaa, 0x3b, 0x6c,
0x35, 0xfe, 0x03, 0x7c, 0xbf, 0x35, 0xba, 0xce,
0x31, 0xb5, 0x1e, 0x3c, 0x49, 0xd6, 0x3f, 0x9c,
0x3a, 0xde, 0x9b, 0x58, 0xcc, 0x54, 0x8d, 0xc0,
0x4b, 0x04, 0xcc, 0xee, 0xae, 0x4d, 0x9f, 0x90,
0xd3, 0xf3, 0xfe, 0x23, 0x26, 0x13, 0x56, 0x80,
0xe4, 0x3b, 0x79, 0x22, 0x69, 0x5d, 0xd6, 0xb7,
0xa0, 0x0e, 0x7e, 0x07, 0xcd, 0x1a, 0x15, 0xca,
// magic
'k', 'b', 'o', 'x',
// crc
0x09, 0x7b, 0x7e, 0xcc
};
// clang-format on
const uint32_t crc_computed = wvcrc32n(kKeyboxData, 124);
uint32_t crc_current;
memcpy(&crc_current, &kKeyboxData[124], 4);
EXPECT_EQ(crc_computed, crc_current);
}
} // namespace wvoec_ref