Merge "Remove OEMCrypto reference"
This commit is contained in:
committed by
Android (Google) Code Review
commit
f6211cf0ee
@@ -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.**
|
||||
@@ -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;
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user