Implement provisioning 3.0 functionality in oemcrypto mock

Merge from widevine repo of http://go/wvgerrit/21684

This CL adds provisioning 3.0 functionality to the OEMCrypto reference
implementation.

Change-Id: I60c1fd88f246d443e0ae59ad56862c2ea9d95445
This commit is contained in:
Fred Gylys-Colwell
2016-11-29 16:00:22 -08:00
parent 3e525dfdd3
commit 08ad98cad9
9 changed files with 673 additions and 248 deletions

View File

@@ -0,0 +1,141 @@
// This file contains the test OEM cert.
#include "oem_cert.h"
// TODO(fredgc, b/30141311): get a real certificate from server gang.
// TODO(fredgc): This is in PEM format. Is that what we want?
const uint8_t kOEMPublicCert[] = "-----BEGIN CERTIFICATE-----\n"
"MIIEOTCCAyGgAwIBAgIJAJNm87hSM9ZIMA0GCSqGSIb3DQEBCwUAMIGyMQswCQYD\n"
"VQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2lya2xhbmQx\n"
"GDAWBgNVBAoMD0dvb2dsZSBXaWRldmluZTEXMBUGA1UECwwOVGVzdCBhbmQgRGVi\n"
"dWcxJjAkBgNVBAMMHU9FTUNyeXB0byBNb2NrIFJlZmVyZW5jZSBDb2RlMSAwHgYJ\n"
"KoZIhvcNAQkBFhFmcmVkZ2NAZ29vZ2xlLmNvbTAeFw0xNjEwMDYxODUzNDZaFw0x\n"
"NjEwMTYxODUzNDZaMIGyMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3Rv\n"
"bjERMA8GA1UEBwwIS2lya2xhbmQxGDAWBgNVBAoMD0dvb2dsZSBXaWRldmluZTEX\n"
"MBUGA1UECwwOVGVzdCBhbmQgRGVidWcxJjAkBgNVBAMMHU9FTUNyeXB0byBNb2Nr\n"
"IFJlZmVyZW5jZSBDb2RlMSAwHgYJKoZIhvcNAQkBFhFmcmVkZ2NAZ29vZ2xlLmNv\n"
"bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMuQQOqS9Q6K/Di8G4xl\n"
"8pz6Ea90D1FLYzIZXd98Ybd94qwWHYaaNuTfTXvZH07fWxrc8HG44N51ArzZGEaT\n"
"h1O7Jt39qLGMirocCgQLxNI3SP7l/pXmsZBM20tYKOoSq7E68eFbXWp39LDOVElS\n"
"/Lib0QkcwmJd55Fnxk6PIscBqYQilLIglQheoDLcljmOd9Rcr59JTtDENfBJE+SC\n"
"ZD0Kckc2e6lBvy/VGKUqE2hmt00pFBugWsN+SkasLGst5/pTVZfTKOBd1E3OvfL3\n"
"qtli4bRyPVX23zSk/bCzxQO47pXe6nVna9m4Yk/LfwJfDIb+r1ErNwyZ4SmZLw6T\n"
"LrkCAwEAAaNQME4wHQYDVR0OBBYEFNx/l/kMs1AY9IhIphtjzR7cwIVBMB8GA1Ud\n"
"IwQYMBaAFNx/l/kMs1AY9IhIphtjzR7cwIVBMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n"
"hvcNAQELBQADggEBAFSaXoWtFU/895lD1Sh/u6pdJcGuCJS0/s2scs95T1sglpfn\n"
"7pdTNtC1aniGuN0T+Aa2O95rJnS0W6RBGdKt1umFOcC7NfRBq1h7a1rn5wYicE5z\n"
"6rIumCSU4oniKMnQ5J+6LpKUFDVJt2W2o8LCKrHWgvcomo8B4ffdKrg+IKpS9Lxc\n"
"U3wyi27rRCyH004YpyE48hPXB3et6OmP2/Aw01d9LxTXieDh0HkhptEllV5EyGM2\n"
"nnRkbd21nHMkVUDzXYWDibxQj6PXw57smnjx7vTiZ1GoE72g2ENSwT1MQhoI59hy\n"
"WCKO91GNxZnyblSTrjLvzAY2hlVCauo7NmLG/yM=\n"
"-----END CERTIFICATE-----\n";
const size_t kOEMPublicCertSize = sizeof(kOEMPublicCert);
// TODO(fredgc): get the private key that goes with the certificat above.
const uint8_t kOEMPrivateKey[] = {
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, 0xcb, 0x90, 0x40, 0xea, 0x92, 0xf5, 0x0e, 0x8a, 0xfc, 0x38,
0xbc, 0x1b, 0x8c, 0x65, 0xf2, 0x9c, 0xfa, 0x11, 0xaf, 0x74, 0x0f, 0x51,
0x4b, 0x63, 0x32, 0x19, 0x5d, 0xdf, 0x7c, 0x61, 0xb7, 0x7d, 0xe2, 0xac,
0x16, 0x1d, 0x86, 0x9a, 0x36, 0xe4, 0xdf, 0x4d, 0x7b, 0xd9, 0x1f, 0x4e,
0xdf, 0x5b, 0x1a, 0xdc, 0xf0, 0x71, 0xb8, 0xe0, 0xde, 0x75, 0x02, 0xbc,
0xd9, 0x18, 0x46, 0x93, 0x87, 0x53, 0xbb, 0x26, 0xdd, 0xfd, 0xa8, 0xb1,
0x8c, 0x8a, 0xba, 0x1c, 0x0a, 0x04, 0x0b, 0xc4, 0xd2, 0x37, 0x48, 0xfe,
0xe5, 0xfe, 0x95, 0xe6, 0xb1, 0x90, 0x4c, 0xdb, 0x4b, 0x58, 0x28, 0xea,
0x12, 0xab, 0xb1, 0x3a, 0xf1, 0xe1, 0x5b, 0x5d, 0x6a, 0x77, 0xf4, 0xb0,
0xce, 0x54, 0x49, 0x52, 0xfc, 0xb8, 0x9b, 0xd1, 0x09, 0x1c, 0xc2, 0x62,
0x5d, 0xe7, 0x91, 0x67, 0xc6, 0x4e, 0x8f, 0x22, 0xc7, 0x01, 0xa9, 0x84,
0x22, 0x94, 0xb2, 0x20, 0x95, 0x08, 0x5e, 0xa0, 0x32, 0xdc, 0x96, 0x39,
0x8e, 0x77, 0xd4, 0x5c, 0xaf, 0x9f, 0x49, 0x4e, 0xd0, 0xc4, 0x35, 0xf0,
0x49, 0x13, 0xe4, 0x82, 0x64, 0x3d, 0x0a, 0x72, 0x47, 0x36, 0x7b, 0xa9,
0x41, 0xbf, 0x2f, 0xd5, 0x18, 0xa5, 0x2a, 0x13, 0x68, 0x66, 0xb7, 0x4d,
0x29, 0x14, 0x1b, 0xa0, 0x5a, 0xc3, 0x7e, 0x4a, 0x46, 0xac, 0x2c, 0x6b,
0x2d, 0xe7, 0xfa, 0x53, 0x55, 0x97, 0xd3, 0x28, 0xe0, 0x5d, 0xd4, 0x4d,
0xce, 0xbd, 0xf2, 0xf7, 0xaa, 0xd9, 0x62, 0xe1, 0xb4, 0x72, 0x3d, 0x55,
0xf6, 0xdf, 0x34, 0xa4, 0xfd, 0xb0, 0xb3, 0xc5, 0x03, 0xb8, 0xee, 0x95,
0xde, 0xea, 0x75, 0x67, 0x6b, 0xd9, 0xb8, 0x62, 0x4f, 0xcb, 0x7f, 0x02,
0x5f, 0x0c, 0x86, 0xfe, 0xaf, 0x51, 0x2b, 0x37, 0x0c, 0x99, 0xe1, 0x29,
0x99, 0x2f, 0x0e, 0x93, 0x2e, 0xb9, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
0x82, 0x01, 0x00, 0x5d, 0xc7, 0x67, 0x20, 0xa9, 0xf3, 0x1b, 0x70, 0x0c,
0x22, 0x57, 0x06, 0x99, 0xf7, 0x9d, 0x7d, 0x93, 0xf6, 0xf1, 0xcd, 0x96,
0x00, 0xed, 0xaa, 0x15, 0x3a, 0x7a, 0x74, 0xaa, 0xe8, 0x99, 0x8f, 0xf5,
0x0d, 0x32, 0x63, 0x07, 0xcf, 0xa3, 0xda, 0x6c, 0xc5, 0x55, 0x79, 0x01,
0x63, 0x64, 0xa2, 0xa4, 0x0d, 0x84, 0xf7, 0xdf, 0x24, 0x39, 0x57, 0xce,
0x9b, 0x11, 0xa8, 0x8d, 0x5b, 0x09, 0xcd, 0x19, 0x3b, 0x1e, 0xa9, 0xed,
0x3d, 0x5e, 0x71, 0xca, 0xab, 0x80, 0x31, 0xbc, 0xfa, 0x3f, 0x9e, 0x18,
0x92, 0xd5, 0x82, 0x23, 0xac, 0xd3, 0xc0, 0x96, 0xa7, 0xb0, 0x5e, 0x3c,
0xfb, 0x18, 0xfe, 0xdf, 0xf7, 0x37, 0xd7, 0x8a, 0x2f, 0xcf, 0x0c, 0xd4,
0x3d, 0x5f, 0xd0, 0x94, 0xb7, 0x16, 0x96, 0x35, 0xb2, 0x67, 0x70, 0x48,
0x5c, 0xe8, 0xc5, 0xf5, 0xc6, 0xc9, 0x25, 0x07, 0xec, 0x0d, 0xa1, 0x74,
0x09, 0x9d, 0xcd, 0x25, 0xa5, 0x7a, 0x2f, 0xa6, 0x4c, 0xba, 0x7d, 0x55,
0x4f, 0x79, 0x83, 0xaa, 0xfa, 0x3a, 0xc0, 0xaf, 0xc2, 0x33, 0xb2, 0x9a,
0x68, 0x89, 0x72, 0x2f, 0x86, 0x69, 0x28, 0x1b, 0xdc, 0xa2, 0x05, 0xe3,
0xfc, 0x24, 0x4c, 0xe0, 0x02, 0xb7, 0x06, 0x4b, 0xe0, 0x88, 0xe9, 0x79,
0x72, 0x46, 0x1c, 0x49, 0x5e, 0xfa, 0x2d, 0x29, 0xe5, 0xbf, 0x29, 0xfe,
0xf2, 0xee, 0xeb, 0xe8, 0x4a, 0x8d, 0xdd, 0xfa, 0x8e, 0xb0, 0x65, 0x68,
0x38, 0xa5, 0xb4, 0xd7, 0x75, 0xd7, 0x8c, 0x32, 0x51, 0xe3, 0x97, 0x00,
0x91, 0x19, 0x87, 0xaa, 0xeb, 0x4b, 0xcf, 0xf9, 0x6b, 0xf2, 0x87, 0xb9,
0x93, 0x4e, 0xd7, 0x5c, 0x27, 0xbb, 0x92, 0x29, 0x5e, 0xb8, 0xe9, 0x75,
0xc0, 0xc6, 0xa3, 0x8a, 0xb7, 0x1e, 0x19, 0xce, 0xd9, 0x5a, 0xc1, 0x0f,
0x6d, 0xa6, 0x4a, 0x56, 0x24, 0x10, 0x01, 0x02, 0x81, 0x81, 0x00, 0xe8,
0x1b, 0x99, 0x55, 0x0e, 0x19, 0x8b, 0x48, 0x46, 0xb1, 0x36, 0xb0, 0xe8,
0x15, 0x5f, 0x45, 0x8b, 0x09, 0xac, 0x82, 0xd1, 0x93, 0x6f, 0x8d, 0xed,
0xe8, 0x80, 0x82, 0xe4, 0xbc, 0x33, 0x40, 0x50, 0x71, 0x3f, 0x2c, 0x20,
0x46, 0x34, 0x3f, 0x27, 0xc3, 0x98, 0x66, 0x34, 0x99, 0x05, 0x06, 0x53,
0x43, 0xdf, 0x52, 0x0b, 0x56, 0x1a, 0xde, 0x3f, 0xbf, 0xba, 0x61, 0xd3,
0xcf, 0xfd, 0xee, 0x34, 0x71, 0x75, 0x9f, 0xfd, 0xc4, 0xb0, 0x8b, 0x26,
0xb1, 0x77, 0x83, 0xd4, 0x90, 0x28, 0xc2, 0xb7, 0x52, 0x98, 0xa0, 0x6b,
0x4b, 0x19, 0x8b, 0x28, 0xbb, 0x18, 0x3e, 0x29, 0x14, 0x7e, 0xa3, 0x87,
0xf8, 0x4d, 0x8a, 0x67, 0x3a, 0xf6, 0xec, 0x04, 0x7b, 0xfb, 0x3e, 0xa5,
0xe3, 0xbb, 0xb2, 0x35, 0xf2, 0xd1, 0x63, 0x55, 0xb6, 0x87, 0x07, 0xea,
0xbb, 0x06, 0x62, 0xbf, 0xaa, 0xbb, 0x19, 0x02, 0x81, 0x81, 0x00, 0xe0,
0x84, 0x77, 0xb0, 0xc1, 0x94, 0x89, 0xc6, 0x54, 0x78, 0x8a, 0xf0, 0xcd,
0xa4, 0x88, 0x92, 0xb4, 0xc9, 0xf1, 0x1c, 0x60, 0xea, 0x6d, 0x1c, 0x1d,
0x33, 0x92, 0x12, 0xe3, 0xe3, 0xd4, 0x11, 0xb6, 0x4d, 0x05, 0x93, 0xbc,
0x19, 0x50, 0xfc, 0x20, 0xe6, 0x07, 0x4a, 0xbc, 0xb6, 0x4f, 0xc1, 0x81,
0xc8, 0x71, 0xa7, 0xe2, 0x79, 0xb3, 0xc9, 0x43, 0x43, 0xca, 0x27, 0xe7,
0x37, 0x5b, 0x20, 0x83, 0x14, 0x8f, 0xb7, 0xba, 0x6c, 0x19, 0x21, 0xd5,
0x60, 0x87, 0xae, 0x45, 0xa8, 0x17, 0xd8, 0x73, 0xae, 0x65, 0xae, 0x83,
0x26, 0xff, 0x4e, 0x4f, 0x95, 0xdc, 0xce, 0x12, 0x40, 0xe6, 0xdd, 0xf2,
0x64, 0x84, 0x65, 0x86, 0x3e, 0xb4, 0xbe, 0x2d, 0x95, 0x74, 0x5c, 0xb2,
0xc6, 0x7c, 0x84, 0x17, 0x06, 0xe8, 0x80, 0xc8, 0xfe, 0x79, 0x22, 0xe6,
0xfa, 0x1f, 0xd2, 0x71, 0x84, 0x24, 0xa1, 0x02, 0x81, 0x80, 0x1d, 0x33,
0x63, 0xad, 0xfc, 0xb1, 0x20, 0x01, 0xbe, 0xcb, 0x0a, 0xbb, 0x64, 0xe7,
0x53, 0x6e, 0x17, 0x58, 0xe7, 0x38, 0x2a, 0x0f, 0xa7, 0x68, 0x2e, 0xb7,
0x22, 0x7b, 0xd5, 0x35, 0x0c, 0x29, 0x9a, 0x35, 0x35, 0x22, 0x63, 0x09,
0x12, 0x07, 0xa4, 0x04, 0x0a, 0x87, 0x49, 0x34, 0xbb, 0x1a, 0x19, 0x9d,
0x9f, 0x59, 0xde, 0x0d, 0x3e, 0x22, 0x19, 0xd9, 0x10, 0x24, 0xc0, 0x96,
0x19, 0x37, 0x3f, 0xa7, 0xca, 0x89, 0x8f, 0x4e, 0x90, 0x7b, 0x61, 0x29,
0xd0, 0x84, 0x68, 0x58, 0x9e, 0x98, 0x28, 0xa2, 0x1e, 0x8b, 0x88, 0x14,
0x11, 0xa9, 0x9d, 0x3d, 0x34, 0x86, 0x95, 0x7a, 0x7b, 0x98, 0x2d, 0x42,
0x02, 0xd7, 0x57, 0xb7, 0x66, 0x5b, 0x39, 0x11, 0x34, 0x01, 0xa4, 0xb3,
0x2a, 0xe8, 0xf7, 0xba, 0x8d, 0xb7, 0x36, 0x90, 0x59, 0x1a, 0x98, 0xe0,
0x60, 0xa4, 0x49, 0xc2, 0xbb, 0xf9, 0x02, 0x81, 0x80, 0x06, 0x01, 0x65,
0x16, 0x34, 0x47, 0x5d, 0xdc, 0x11, 0x3c, 0x5c, 0x33, 0x0e, 0xbd, 0x1c,
0xee, 0x17, 0xa9, 0xe3, 0x2a, 0x28, 0x29, 0x7d, 0x1b, 0xa8, 0x68, 0x4d,
0xba, 0xf5, 0x9f, 0x8d, 0x77, 0x9f, 0xd1, 0xb5, 0x99, 0x7b, 0x09, 0x8e,
0x52, 0x00, 0x2b, 0x46, 0xfc, 0xa7, 0xc9, 0x94, 0x9e, 0x8f, 0x73, 0x26,
0x1f, 0x20, 0x7e, 0xb2, 0xe1, 0x6a, 0x4c, 0x30, 0xe7, 0x1a, 0x57, 0x2f,
0xb7, 0xd1, 0xe9, 0xc5, 0xe2, 0x5b, 0x39, 0x32, 0xfe, 0xe5, 0xaf, 0x3c,
0x51, 0xdc, 0x09, 0x20, 0x02, 0x29, 0x2d, 0xfc, 0x08, 0x4b, 0xf7, 0xca,
0x12, 0x75, 0x2c, 0x84, 0x08, 0x7b, 0x12, 0x83, 0x5a, 0x62, 0x76, 0x6f,
0xd8, 0x2b, 0x5c, 0x18, 0x07, 0x92, 0x3e, 0x92, 0x2b, 0x3c, 0x98, 0xf4,
0x91, 0xaf, 0xef, 0xfe, 0x5e, 0x1b, 0x82, 0x3b, 0x09, 0x44, 0xf6, 0x61,
0xcd, 0x86, 0x3d, 0xcb, 0xa1, 0x02, 0x81, 0x81, 0x00, 0xe5, 0x81, 0xf6,
0x6f, 0x37, 0xf4, 0xef, 0xc7, 0x0e, 0xdf, 0x39, 0xd0, 0x97, 0x68, 0x1c,
0xd5, 0x12, 0x42, 0x00, 0x0e, 0xd1, 0x89, 0xdc, 0xf5, 0x24, 0x30, 0xb3,
0xeb, 0xea, 0x64, 0x3c, 0x9e, 0xa2, 0xc3, 0x49, 0x3c, 0xed, 0x2d, 0x4e,
0x9a, 0x00, 0x23, 0x71, 0xcc, 0x15, 0xda, 0x49, 0xdc, 0xab, 0xd1, 0x36,
0xe1, 0x8c, 0x91, 0x6c, 0x5b, 0x47, 0x43, 0x34, 0xec, 0xcd, 0x0c, 0xd0,
0x88, 0x7c, 0x5a, 0xd4, 0x91, 0x79, 0xe5, 0xe6, 0xd2, 0x5d, 0x2e, 0x14,
0x26, 0x81, 0x94, 0x9f, 0x29, 0x2b, 0x3e, 0xd6, 0x2f, 0x2d, 0xd9, 0xec,
0x88, 0x6a, 0xd3, 0x35, 0x71, 0x8a, 0xb2, 0xef, 0x22, 0xdc, 0xab, 0x26,
0xf9, 0x4d, 0x4c, 0x08, 0x8e, 0x16, 0x5b, 0x56, 0xb6, 0x76, 0x61, 0x89,
0x8a, 0x3a, 0xdb, 0xbb, 0x42, 0xe3, 0x50, 0x3f, 0xa1, 0x08, 0x82, 0xc2,
0x92, 0xef, 0x8c, 0xc2, 0xca
};
const size_t kOEMPrivateKeySize = sizeof(kOEMPrivateKey);

View File

@@ -0,0 +1,14 @@
// 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>
extern const uint8_t kOEMPrivateKey[];
extern const size_t kOEMPrivateKeySize;
extern const uint8_t kOEMPublicCert[];
extern const size_t kOEMPublicCertSize;
#endif // OEM_CERT_H_

View File

@@ -38,6 +38,17 @@ bool CryptoEngine::supports_keybox() {
return true;
}
// This version uses a keybox.
OEMCrypto_ProvisioningMethod CryptoEngine::provisioning_method() {
return OEMCrypto_Keybox;
}
OEMCryptoResult CryptoEngine::get_oem_certificate(SessionContext *session,
uint8_t *public_cert,
size_t *public_cert_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
// Returns false for mock library to indicate the client does not support
// anti-rollback hardware.
bool CryptoEngine::is_anti_rollback_hw_present() {

View File

@@ -40,6 +40,17 @@ bool CryptoEngine::supports_keybox() {
return true;
}
// This version uses a keybox.
OEMCrypto_ProvisioningMethod CryptoEngine::provisioning_method() {
return OEMCrypto_Keybox;
}
OEMCryptoResult CryptoEngine::get_oem_certificate(SessionContext *session,
uint8_t *public_cert,
size_t *public_cert_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
// Returns true to indicate the client does support anti-rollback hardware.
bool CryptoEngine::is_anti_rollback_hw_present() {
return true;

View File

@@ -41,6 +41,17 @@ bool CryptoEngine::supports_keybox() {
return false;
}
// This version uses a baked in DRM certificate.
OEMCrypto_ProvisioningMethod CryptoEngine::provisioning_method() {
return OEMCrypto_DrmCertificate;
}
OEMCryptoResult CryptoEngine::get_oem_certificate(SessionContext *session,
uint8_t *public_cert,
size_t *public_cert_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
// Returns true to indicate the client does support anti-rollback hardware.
bool CryptoEngine::is_anti_rollback_hw_present() {
return false;

View File

@@ -0,0 +1,97 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Mock 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_mock.h"
#include <string.h>
#include "log.h"
#include "oem_cert.h"
namespace wvoec_mock {
// If local_display() returns true, we pretend we are using a built-in display,
// instead of HDMI or WiFi output.
bool CryptoEngine::local_display() {
return true;
}
// A closed platform is permitted to use clear buffers.
bool CryptoEngine::closed_platform() {
return false;
}
// Returns the HDCP version currently in use.
OEMCrypto_HDCP_Capability CryptoEngine::current_hdcp_capability() {
return local_display() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1;
}
// Returns the max HDCP version supported.
OEMCrypto_HDCP_Capability CryptoEngine::maximum_hdcp_capability() {
return HDCP_NO_DIGITAL_OUTPUT;
}
// Returns true if the client supports persistent storage of
// offline usage table information.
bool CryptoEngine::supports_storage() {
return false;
}
// Returns true if the client uses a keybox as the root of trust.
bool CryptoEngine::supports_keybox() {
return false;
}
// This version uses a keybox.
OEMCrypto_ProvisioningMethod CryptoEngine::provisioning_method() {
return OEMCrypto_OEMCertificate;
}
OEMCryptoResult CryptoEngine::get_oem_certificate(SessionContext *session,
uint8_t *public_cert,
size_t *public_cert_length) {
if (kOEMPublicCertSize == 0) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (public_cert_length == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (*public_cert_length < kOEMPublicCertSize) {
*public_cert_length = kOEMPublicCertSize;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*public_cert_length = kOEMPublicCertSize;
if (public_cert == NULL) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize);
if (!session->LoadRSAKey(kOEMPrivateKey, kOEMPrivateKeySize)) {
LOGE("Private RSA Key did not load correctly.");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
return OEMCrypto_SUCCESS;
}
// Returns true to indicate the client does support anti-rollback hardware.
bool CryptoEngine::is_anti_rollback_hw_present() {
return false;
}
// 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* CryptoEngine::security_level() {
return "L2";
}
// 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 CryptoEngine::security_patch_level() {
return 0;
}
} // namespace wvoec_mock

View File

@@ -242,12 +242,71 @@ void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) {
}
}
void RSA_shared_ptr::reset() {
if (rsa_key_ && key_owned_) {
RSA_free(rsa_key_);
}
key_owned_ = false;
rsa_key_ = NULL;
}
bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
assert(buffer != NULL);
reset();
key_owned_ = true;
uint8_t* pkcs8_rsa_key = const_cast<uint8_t*>(buffer);
BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length);
if (bio == NULL) {
LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]");
return false;
}
bool success = true;
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
if (pkcs8_pki == NULL) {
LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL]");
success = false;
}
EVP_PKEY* evp = NULL;
if (success) {
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == NULL) {
LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned NULL]");
success = false;
}
}
if (success) {
rsa_key_ = EVP_PKEY_get1_RSA(evp);
if (rsa_key_ == NULL) {
LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]");
success = false;
}
}
if (evp != NULL) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != NULL) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
if (!success) {
return false;
}
switch (RSA_check_key(rsa_key_)) {
case 1: // valid.
return true;
case 0: // not valid.
LOGE("[LoadPkcs8RsaKey(): rsa key not valid]");
dump_openssl_error();
return false;
default: // -1 == check failed.
LOGE("[LoadPkcs8RsaKey(): error checking rsa key]");
dump_openssl_error();
return false;
}
}
SessionContext::~SessionContext() {
if (usage_entry_) usage_entry_->set_session(NULL);
if (rsa_key_ && rsa_key_ != ce_->rsa_key()) {
RSA_free(rsa_key_);
rsa_key_ = NULL;
}
}
// Internal utility function to derive key using CMAC-128
@@ -339,20 +398,20 @@ bool SessionContext::DeriveKeys(const std::vector<uint8_t>& master_key,
bool SessionContext::RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
const std::vector<uint8_t>& mac_key_context,
const std::vector<uint8_t>& enc_key_context) {
if (!rsa_key_) {
if (!rsa_key()) {
LOGE("[RSADeriveKeys(): no RSA key set]");
return false;
}
if (enc_session_key.size() != static_cast<size_t>(RSA_size(rsa_key_))) {
if (enc_session_key.size() != static_cast<size_t>(RSA_size(rsa_key()))) {
LOGE("[RSADeriveKeys(): encrypted session key wrong size:%zu, expected %d]",
enc_session_key.size(), RSA_size(rsa_key_));
enc_session_key.size(), RSA_size(rsa_key()));
dump_openssl_error();
return false;
}
session_key_.resize(RSA_size(rsa_key_));
session_key_.resize(RSA_size(rsa_key()));
int decrypted_size = RSA_private_decrypt(enc_session_key.size(),
&enc_session_key[0],
&session_key_[0], rsa_key_,
&session_key_[0], rsa_key(),
RSA_PKCS1_OAEP_PADDING);
if (-1 == decrypted_size) {
LOGE("[RSADeriveKeys(): error decrypting session key.]");
@@ -402,11 +461,11 @@ bool SessionContext::GenerateSignature(const uint8_t* message,
}
size_t SessionContext::RSASignatureSize() {
if (!rsa_key_) {
if (!rsa_key()) {
LOGE("[GenerateRSASignature(): no RSA key set]");
return 0;
}
return static_cast<size_t>(RSA_size(rsa_key_));
return static_cast<size_t>(RSA_size(rsa_key()));
}
OEMCryptoResult SessionContext::GenerateRSASignature(
@@ -417,19 +476,18 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
LOGE("[GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!rsa_key_) {
if (!rsa_key()) {
LOGE("[GenerateRSASignature(): no RSA key set]");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (*signature_length < static_cast<size_t>(RSA_size(rsa_key_))) {
*signature_length = RSA_size(rsa_key_);
if (*signature_length < static_cast<size_t>(RSA_size(rsa_key()))) {
*signature_length = RSA_size(rsa_key());
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if ((padding_scheme & allowed_schemes_) != padding_scheme) {
LOGE("[GenerateRSASignature(): padding_scheme not allowed]");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
// This is the standard padding scheme used for license requests.
if (padding_scheme == kSign_RSASSA_PSS) {
// Hash the message using SHA1.
@@ -442,7 +500,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
// Add PSS padding.
std::vector<uint8_t> padded_digest(*signature_length);
int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa_key_, &padded_digest[0],
int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa_key(), &padded_digest[0],
hash, EVP_sha1(), NULL,
kPssSaltLength);
if (status == -1) {
@@ -453,7 +511,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
// Encrypt PSS padded digest.
status = RSA_private_encrypt(*signature_length, &padded_digest[0], signature,
rsa_key_, RSA_NO_PADDING);
rsa_key(), RSA_NO_PADDING);
if (status == -1) {
LOGE("[GeneratRSASignature(): error in private encrypt.]");
dump_openssl_error();
@@ -467,7 +525,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
}
// Pad the message with PKCS1 padding, and then encrypt.
size_t status = RSA_private_encrypt(message_length, message, signature,
rsa_key_, RSA_PKCS1_PADDING);
rsa_key(), RSA_PKCS1_PADDING);
if (status != *signature_length) {
LOGE("[GeneratRSASignature(): error in RSA private encrypt. status=%d]", status);
dump_openssl_error();
@@ -711,6 +769,29 @@ bool SessionContext::InstallKey(const KeyId& key_id,
return true;
}
bool SessionContext::InstallRSAEncryptedKey(const uint8_t *encrypted_message_key,
size_t encrypted_message_key_length) {
encryption_key_.resize(RSA_size(rsa_key()));
int decrypted_size = RSA_private_decrypt( encrypted_message_key_length,
encrypted_message_key,
&encryption_key_[0], rsa_key(),
RSA_PKCS1_OAEP_PADDING);
if (-1 == decrypted_size) {
LOGE("[RSADeriveKeys(): error decrypting session key.]");
dump_openssl_error();
return false;
}
encryption_key_.resize(decrypted_size);
if (decrypted_size != static_cast<int>(wvcdm::KEY_SIZE)) {
LOGE("[RSADeriveKeys(): error. session key is wrong size: %d.]",
decrypted_size);
dump_openssl_error();
encryption_key_.clear();
return false;
}
return true;
}
OEMCryptoResult SessionContext::RefreshKey(
const KeyId& key_id, const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv) {
@@ -790,7 +871,7 @@ bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key,
const uint8_t* enc_rsa_key_iv,
uint8_t* pkcs8_rsa_key) {
// Decrypt rsa key with keybox.
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_decrypt_key(&encryption_key_[0], 128, &aes_key);
@@ -804,7 +885,7 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
const uint8_t* enc_rsa_key_iv,
uint8_t* enc_rsa_key) {
// Encrypt rsa key with keybox.
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&encryption_key_[0], 128, &aes_key);
@@ -813,79 +894,22 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
return true;
}
bool SessionContext::LoadRSAKey(uint8_t* pkcs8_rsa_key,
size_t rsa_key_length,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length) {
// Validate message signature
if (!ValidateMessage(message, message_length, signature, signature_length)) {
LOGE("[LoadRSAKey(): Could not verify signature]");
return false;
}
if (rsa_key_) {
RSA_free(rsa_key_);
rsa_key_ = NULL;
}
bool SessionContext::LoadRSAKey(const uint8_t* pkcs8_rsa_key,
size_t rsa_key_length) {
rsa_key_.reset();
if (rsa_key_length < 8) {
LOGE("[LoadRSAKey(): Very Short Buffer]");
return false;
}
if( (memcmp(pkcs8_rsa_key, "SIGN", 4) == 0) ) {
uint32_t *schemes_n = (uint32_t *)(pkcs8_rsa_key + 4);
if ((memcmp(pkcs8_rsa_key, "SIGN", 4) == 0)) {
uint32_t* schemes_n = (uint32_t*)(pkcs8_rsa_key + 4);
allowed_schemes_ = htonl(*schemes_n);
pkcs8_rsa_key += 8;
rsa_key_length -= 8;
} else {
allowed_schemes_ = kSign_RSASSA_PSS;
}
BIO *bio = BIO_new_mem_buf(pkcs8_rsa_key, rsa_key_length);
if ( bio == NULL ) {
LOGE("[LoadRSAKey(): Could not allocate bio buffer]");
return false;
}
bool success = true;
PKCS8_PRIV_KEY_INFO *pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
if (pkcs8_pki == NULL) {
LOGE("d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL.");
success = false;
}
EVP_PKEY *evp = NULL;
if (success) {
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == NULL) {
LOGE("EVP_PKCS82PKEY returned NULL.");
success = false;
}
}
if (success) {
rsa_key_ = EVP_PKEY_get1_RSA(evp);
if (rsa_key_ == NULL) {
LOGE("PrivateKeyInfo did not contain an RSA key.");
success = false;
}
}
if (evp != NULL) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != NULL) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
if (!success) {
return false;
}
switch (RSA_check_key(rsa_key_)) {
case 1: // valid.
return true;
case 0: // not valid.
LOGE("[LoadRSAKey(): rsa key not valid]");
dump_openssl_error();
return false;
default: // -1 == check failed.
LOGE("[LoadRSAKey(): error checking rsa key]");
dump_openssl_error();
return false;
}
return rsa_key_.LoadPkcs8RsaKey(pkcs8_rsa_key, rsa_key_length);
}
OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
@@ -921,11 +945,11 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if ( algorithm != OEMCrypto_AES_CBC_128_NO_PADDING ) {
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
LOGE("[Generic_Encrypt(): algorithm bad.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if ( buffer_length % AES_BLOCK_SIZE != 0 ) {
if (buffer_length % AES_BLOCK_SIZE != 0) {
LOGE("[Generic_Encrypt(): buffers size bad.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -935,7 +959,7 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
LOGE("[Generic_Encrypt(): FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE);
AES_cbc_encrypt(in_buffer, out_buffer, buffer_length,
&aes_key, iv_buffer, AES_ENCRYPT);
@@ -981,11 +1005,11 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if ( algorithm != OEMCrypto_AES_CBC_128_NO_PADDING ) {
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
LOGE("[Generic_Decrypt(): bad algorithm.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if ( buffer_length % AES_BLOCK_SIZE != 0 ) {
if (buffer_length % AES_BLOCK_SIZE != 0) {
LOGE("[Generic_Decrypt(): bad buffer size.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -995,7 +1019,7 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
LOGE("[Generic_Decrypt(): FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE);
AES_cbc_encrypt(in_buffer, out_buffer, buffer_length,
&aes_key, iv_buffer, AES_DECRYPT);
@@ -1039,7 +1063,7 @@ OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if( algorithm != OEMCrypto_HMAC_SHA256 ) {
if (algorithm != OEMCrypto_HMAC_SHA256) {
LOGE("[Generic_Sign(): bad algorithm.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -1089,7 +1113,7 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if ( algorithm != OEMCrypto_HMAC_SHA256 ) {
if (algorithm != OEMCrypto_HMAC_SHA256) {
LOGE("[Generic_Verify(): bad algorithm.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -1190,21 +1214,20 @@ bool SessionContext::IsUsageEntryValid() {
void SessionContext::ReleaseUsageEntry() { usage_entry_ = NULL; }
CryptoEngine::CryptoEngine(wvcdm::FileSystem* file_system)
: current_session_(NULL),
use_test_keybox_(false),
: use_test_keybox_(false),
file_system_(file_system),
usage_table_(new UsageTable(this)),
rsa_key_(NULL) {
usage_table_(new UsageTable(this)) {
ERR_load_crypto_strings();
if (!supports_keybox() && !LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) {
if ((provisioning_method() == OEMCrypto_DrmCertificate) &&
!rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) {
// 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.");
}
}
CryptoEngine::~CryptoEngine() {
current_session_ = NULL;
sessions_.clear();
if (usage_table_) delete usage_table_;
}
@@ -1214,19 +1237,15 @@ void CryptoEngine::Terminate() {}
KeyboxError CryptoEngine::ValidateKeybox() { return keybox().Validate(); }
bool CryptoEngine::LoadTestRSAKey() {
if (rsa_key_) {
RSA_free(rsa_key_);
rsa_key_ = NULL;
}
return LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
return rsa_key_.LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
}
SessionId CryptoEngine::CreateSession() {
wvcdm::AutoLock lock(session_table_lock_);
static int unique_id = 1;
SessionId sid = (SessionId)++unique_id;
SessionContext* sctx = new SessionContext(this, sid, this->rsa_key_);
SessionContext* sctx = new SessionContext(this, sid, rsa_key_);
sessions_[sid] = sctx;
return sid;
}
@@ -1252,59 +1271,6 @@ SessionContext* CryptoEngine::FindSession(SessionId sid) {
return NULL;
}
bool CryptoEngine::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
assert(buffer != NULL);
uint8_t* pkcs8_rsa_key = const_cast<uint8_t*>(buffer);
BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length);
if (bio == NULL) {
LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]");
return false;
}
bool success = true;
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
if (pkcs8_pki == NULL) {
LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL]");
success = false;
}
EVP_PKEY* evp = NULL;
if (success) {
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == NULL) {
LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned NULL]");
success = false;
}
}
if (success) {
rsa_key_ = EVP_PKEY_get1_RSA(evp);
if (rsa_key_ == NULL) {
LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]");
success = false;
}
}
if (evp != NULL) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != NULL) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
if (!success) {
return false;
}
switch (RSA_check_key(rsa_key_)) {
case 1: // valid.
return true;
case 0: // not valid.
LOGE("[LoadPkcs8RsaKey(): rsa key not valid]");
dump_openssl_error();
return false;
default: // -1 == check failed.
LOGE("[LoadPkcs8RsaKey(): error checking rsa key]");
dump_openssl_error();
return false;
}
}
// Internal utility function to decrypt the message
bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv,

View File

@@ -12,11 +12,11 @@
#include <openssl/rsa.h>
#include "OEMCryptoCENC.h" // Needed for enums only.
#include "file_store.h"
#include "lock.h"
#include "oemcrypto_key_mock.h"
#include "oemcrypto_keybox_mock.h"
#include "OEMCryptoCENC.h" // Needed for enums only.
#include "wv_cdm_types.h"
namespace wvoec_mock {
@@ -61,6 +61,7 @@ class NonceTable {
void AddNonce(uint32_t nonce);
bool CheckNonce(uint32_t nonce);
void Flush();
private:
enum NonceTableState {
kNTStateInvalid,
@@ -72,12 +73,34 @@ class NonceTable {
uint32_t nonces_[kTableSize];
};
// Shared pointer with specialized destructor. This pointer is only shared
// from a CryptoEngine to a Session -- so we don't have to use full reference
// counting.
class RSA_shared_ptr {
public:
RSA_shared_ptr() : rsa_key_(NULL), key_owned_(false) {}
~RSA_shared_ptr() { reset(); };
// Explicitly allow copy as share.
explicit RSA_shared_ptr(const RSA_shared_ptr& other) :
rsa_key_(other.rsa_key_), key_owned_(false) {}
RSA* get() { return rsa_key_; }
void reset();
bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length);
private:
void operator=(const RSA_shared_ptr); // disallow assign.
RSA* rsa_key_;
bool key_owned_;
};
class SessionContext {
private:
SessionContext() {}
public:
explicit SessionContext(CryptoEngine* ce, SessionId sid, RSA* rsa_key)
SessionContext(CryptoEngine* ce, SessionId sid,
const RSA_shared_ptr& rsa_key)
: valid_(true),
ce_(ce),
id_(sid),
@@ -132,7 +155,7 @@ class SessionContext {
const uint8_t* signature,
size_t signature_length);
void StartTimer();
uint32_t CurrentTimer(); // (seconds).
uint32_t CurrentTimer(); // (seconds).
OEMCryptoResult LoadKeys(const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length,
const uint8_t* enc_mac_key_iv,
@@ -146,6 +169,8 @@ class SessionContext {
const std::vector<uint8_t>& key_control_iv,
const std::vector<uint8_t>& pst,
bool ctr_mode);
bool InstallRSAEncryptedKey(const uint8_t *encrypted_message_key,
size_t encrypted_message_key_length);
bool DecryptRSAKey(const uint8_t* enc_rsa_key,
size_t enc_rsa_key_length,
const uint8_t* wrapped_rsa_key_iv,
@@ -154,12 +179,8 @@ class SessionContext {
size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv,
uint8_t* enc_rsa_key);
bool LoadRSAKey(uint8_t* pkcs8_rsa_key,
size_t rsa_key_length,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length);
bool LoadRSAKey(const uint8_t* pkcs8_rsa_key,
size_t rsa_key_length);
OEMCryptoResult RefreshKey(const KeyId& key_id,
const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv);
@@ -212,6 +233,8 @@ class SessionContext {
size_t block_offset, const uint8_t* cipher_data,
size_t cipher_data_length, uint8_t* clear_data);
RSA* rsa_key() { return rsa_key_.get(); }
bool valid_;
CryptoEngine* ce_;
SessionId id_;
@@ -222,7 +245,7 @@ class SessionContext {
const Key* current_content_key_;
SessionKeyTable session_keys_;
NonceTable nonce_table_;
RSA* rsa_key_;
RSA_shared_ptr rsa_key_;
uint32_t allowed_schemes_; // for RSA signatures.
time_t timer_start_;
UsageTableEntry* usage_entry_;
@@ -243,7 +266,7 @@ class CryptoEngine {
WvKeybox& keybox() { return use_test_keybox_ ? test_keybox_ : keybox_; }
WvKeybox& real_keybox() { return keybox_; }
void UseTestKeybox() { use_test_keybox_ = true; }
RSA* rsa_key() { return rsa_key_; }
RSA* rsa_key() { return rsa_key_.get(); }
bool LoadTestRSAKey();
SessionId CreateSession();
@@ -260,10 +283,6 @@ class CryptoEngine {
return kMaxSupportedOEMCryptoSessions;
}
void set_current_session_(SessionContext* current) {
current_session_ = current;
}
OEMCrypto_HDCP_Capability current_hdcp_capability();
OEMCrypto_HDCP_Capability maximum_hdcp_capability();
@@ -273,14 +292,15 @@ class CryptoEngine {
bool closed_platform();
bool supports_storage();
bool supports_keybox();
OEMCrypto_ProvisioningMethod provisioning_method();
OEMCryptoResult get_oem_certificate(SessionContext* session,
uint8_t* public_cert,
size_t* public_cert_length);
bool is_anti_rollback_hw_present();
const char* security_level();
uint8_t security_patch_level();
private:
bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length);
SessionContext* current_session_;
ActiveSessions sessions_;
WvKeybox keybox_;
WvTestKeybox test_keybox_;
@@ -288,7 +308,7 @@ class CryptoEngine {
wvcdm::Lock session_table_lock_;
wvcdm::FileSystem* file_system_;
UsageTable* usage_table_;
RSA* rsa_key_; // If no keybox, this is baked in certificate.
RSA_shared_ptr rsa_key_; // If no keybox, this is baked in certificate.
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
};

View File

@@ -747,6 +747,45 @@ OEMCryptoResult OEMCrypto_IsKeyboxValid(void) {
}
}
extern "C"
OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod() {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(void) {\n");
}
if (!crypto_engine) {
LOGE("OEMCrypto_GetProvisioningMethod: OEMCrypto Not Initialized.");
return OEMCrypto_ProvisioningError;
}
return crypto_engine->provisioning_method();
}
extern "C"
OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(OEMCrypto_SESSION session,
uint8_t *public_cert,
size_t *public_cert_length) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(%d) {\n",
session);
}
if (!crypto_engine) {
LOGE("OEMCrypto_GetOEMPublicCertificate: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (crypto_engine->provisioning_method() != OEMCrypto_OEMCertificate) {
LOGE("OEMCrypto_GetOEMPublicCertificate: Provisioning method = %d.",
crypto_engine->provisioning_method()
);
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (!session_ctx || !session_ctx->isValid()) {
LOGE("[OEMCrypto_GetOEMPublicCertificate(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
return crypto_engine->get_oem_certificate(session_ctx,
public_cert, public_cert_length);
}
extern "C"
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
size_t* idLength) {
@@ -831,6 +870,135 @@ OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
OEMCrypto_SESSION session, const uint32_t* nonce,
const uint8_t* encrypted_message_key, size_t encrypted_message_key_length,
const uint8_t* enc_rsa_key, size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key,
size_t* wrapped_rsa_key_length) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls | kLoggingTraceNonce)) {
LOGI("-- OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(%d)\n", session);
LOGI("nonce = %08X;\n", *nonce);
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
dump_hex("encrypted_message_key", encrypted_message_key,
encrypted_message_key_length);
dump_hex("enc_rsa_key", enc_rsa_key, enc_rsa_key_length);
dump_hex("enc_rsa_key_iv", enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
}
}
if (!crypto_engine) {
LOGE("OEMCrypto_RewrapDeviceRSAKey30: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (wrapped_rsa_key_length == NULL) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// For the reference implementation, the wrapped key and the encrypted
// key are the same size -- just encrypted with different keys.
// We add 32 bytes for a context, 32 for iv, and 32 bytes for a signature.
// Important: This layout must match OEMCrypto_LoadDeviceRSAKey below.
size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
if (wrapped_rsa_key == NULL || *wrapped_rsa_key_length < buffer_size) {
if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
LOGW("[OEMCrypto_RewrapDeviceRSAKey30(): Wrapped Keybox Short Buffer]");
}
*wrapped_rsa_key_length = buffer_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*wrapped_rsa_key_length = buffer_size; // Tell caller how much space we used.
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (!session_ctx || !session_ctx->isValid()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (encrypted_message_key == NULL || encrypted_message_key_length == 0
|| enc_rsa_key == NULL || enc_rsa_key_iv == NULL) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Validate nonce
if (!session_ctx->CheckNonce(*nonce)) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
session_ctx->FlushNonces();
if(!session_ctx->InstallRSAEncryptedKey(encrypted_message_key,
encrypted_message_key_length)) {
LOGE("OEMCrypto_RewrapDeviceRSAKey30: Error loading encrypted_message_key.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Decrypt RSA key.
std::vector<uint8_t> pkcs8_rsa_key(enc_rsa_key_length);
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
enc_rsa_key_iv, &pkcs8_rsa_key[0])) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
if (padding > 16) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Encrypted RSA has bad padding: %d]",
padding);
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Failed to LoadRSAKey.");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
// Now we generate a wrapped keybox.
WrappedRSAKey* wrapped = reinterpret_cast<WrappedRSAKey*>(wrapped_rsa_key);
// Pick a random context and IV for generating keys.
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// TODO(fredgc): Don't use the keybox to encrypt the wrapped RSA key.
const std::vector<uint8_t>
context(wrapped->context, wrapped->context + sizeof(wrapped->context));
// Generate mac and encryption keys for encrypting the signature.
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key(), context,
context)) {
LOGE("[_RewrapDeviceRSAKey30(): DeriveKeys failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Encrypt rsa key with keybox.
if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length,
wrapped->iv, wrapped->enc_rsa_key)) {
LOGE("[_RewrapDeviceRSAKey30(): EncrypteRSAKey failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// The wrapped keybox must be signed with the same key we verify with. I'll
// pick the server key, so I don't have to modify LoadRSAKey.
unsigned int sig_length = sizeof(wrapped->signature);
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
session_ctx->mac_key_server().size(), wrapped->context,
buffer_size - sizeof(wrapped->signature), wrapped->signature,
&sig_length)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
dump_hex("wrapped_rsa_key", wrapped_rsa_key, *wrapped_rsa_key_length);
dump_hex("context", wrapped->context, sizeof(wrapped->context));
dump_hex("iv", wrapped->iv, sizeof(wrapped->iv));
}
}
return OEMCrypto_SUCCESS;
}
extern "C"
OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
const uint8_t* message,
@@ -844,7 +1012,7 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
uint8_t* wrapped_rsa_key,
size_t* wrapped_rsa_key_length) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls | kLoggingTraceNonce)) {
LOGI("-- OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey()\n");
LOGI("-- OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(%d)\n", session);
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
dump_hex("message", message, message_length);
dump_hex("signature", signature, signature_length);
@@ -914,70 +1082,58 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
session_ctx->FlushNonces();
// Decrypt RSA key.
uint8_t* pkcs8_rsa_key = new uint8_t[enc_rsa_key_length];
OEMCryptoResult result = OEMCrypto_SUCCESS;
std::vector<uint8_t> pkcs8_rsa_key(enc_rsa_key_length);
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
enc_rsa_key_iv, pkcs8_rsa_key)) {
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
enc_rsa_key_iv, &pkcs8_rsa_key[0])) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
if (result == OEMCrypto_SUCCESS) {
if (padding > 16) {
LOGE("[RewrapRSAKey(): Encrypted RSA has bad padding: %d]", padding);
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (padding > 16) {
LOGE("[RewrapDeviceRSAKey(): Encrypted RSA has bad padding: %d]",
padding);
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
// verify signature, verify RSA key, and load it.
if (result == OEMCrypto_SUCCESS) {
if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length,
message, message_length,
signature, signature_length)) {
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (!session_ctx->ValidateMessage(message, message_length, signature,
signature_length)) {
LOGE("[RewrapDeviceRSAKey(): Could not verify signature]");
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
// Now we generate a wrapped keybox.
WrappedRSAKey* wrapped = reinterpret_cast<WrappedRSAKey*>(wrapped_rsa_key);
// Pick a random context and IV for generating keys.
if (result == OEMCrypto_SUCCESS) {
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const std::vector<uint8_t>
context(wrapped->context, wrapped->context + sizeof(wrapped->context));
// Generate mac and encryption keys for encrypting the signature.
if (result == OEMCrypto_SUCCESS) {
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key(), context,
context)) {
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key(), context,
context)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Encrypt rsa key with keybox.
if (result == OEMCrypto_SUCCESS) {
if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key, enc_rsa_key_length,
wrapped->iv, wrapped->enc_rsa_key)) {
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length,
wrapped->iv, wrapped->enc_rsa_key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
delete[] pkcs8_rsa_key;
// The wrapped keybox must be signed with the same key we verify with. I'll
// pick the server key, so I don't have to modify LoadRSAKey.
if (result == OEMCrypto_SUCCESS) {
unsigned int sig_length = sizeof(wrapped->signature);
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
session_ctx->mac_key_server().size(), wrapped->context,
buffer_size - sizeof(wrapped->signature), wrapped->signature,
&sig_length)) {
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
unsigned int sig_length = sizeof(wrapped->signature);
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
session_ctx->mac_key_server().size(), wrapped->context,
buffer_size - sizeof(wrapped->signature), wrapped->signature,
&sig_length)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
@@ -987,7 +1143,7 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
dump_hex("iv", wrapped->iv, sizeof(wrapped->iv));
}
}
return result;
return OEMCrypto_SUCCESS;
}
extern "C"
@@ -1002,12 +1158,13 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
LOGE("OEMCrypto_LoadDeviceRSAKey: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->supports_keybox()) {
// If we are not using keyboxes, the "wrapped RSA key" should actually be
if (crypto_engine->provisioning_method() == OEMCrypto_DrmCertificate) {
// If we are using a baked in cert, the "wrapped RSA key" should actually be
// the magic value for baked-in certificates.
if (wrapped_rsa_key_length != sizeof(kBakedInCertificateMagicBytes) ||
memcmp(kBakedInCertificateMagicBytes, wrapped_rsa_key,
wrapped_rsa_key_length) != 0) {
LOGE("OEMCrypto_LoadDeviceRSAKey: Baked in Cert has wrong size.");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
} else {
return OEMCrypto_SUCCESS;
@@ -1024,6 +1181,7 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
dump_hex("iv", wrapped->iv, sizeof(wrapped->iv));
}
}
// TODO(fredgc): Don't use the keybox to encrypt the wrapped RSA key.
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
@@ -1042,34 +1200,31 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Decrypt RSA key.
uint8_t* pkcs8_rsa_key = new uint8_t[wrapped_rsa_key_length
- sizeof(wrapped->signature)];
std::vector<uint8_t> pkcs8_rsa_key(wrapped_rsa_key_length
- sizeof(wrapped->signature));
size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey);
OEMCryptoResult result = OEMCrypto_SUCCESS;
if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length,
wrapped->iv, pkcs8_rsa_key)) {
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
wrapped->iv, &pkcs8_rsa_key[0])) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
if (result == OEMCrypto_SUCCESS) {
if (padding > 16) {
LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding);
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (padding > 16) {
LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding);
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
// verify signature.
if (result == OEMCrypto_SUCCESS) {
if (!session_ctx->LoadRSAKey(
pkcs8_rsa_key, rsa_key_length, wrapped->context,
wrapped_rsa_key_length - sizeof(wrapped->signature),
wrapped->signature, sizeof(wrapped->signature))) {
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (!session_ctx->ValidateMessage(
wrapped->context,
wrapped_rsa_key_length - sizeof(wrapped->signature),
wrapped->signature, sizeof(wrapped->signature))) {
LOGE("[LoadDeviceRSAKey(): Could not verify signature]");
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
delete[] pkcs8_rsa_key;
return result;
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
return OEMCrypto_SUCCESS;
}
extern "C"
@@ -1208,8 +1363,7 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
extern "C"
uint32_t OEMCrypto_APIVersion() {
// TODO(fredgc): Implement new API.
return 11;
return 12;
}
extern "C"
@@ -1319,7 +1473,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt(OEMCrypto_SESSION session,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
LOGE("[OEMCrypto_Generic_Enrcypt(): ERROR_KEYBOX_INVALID]");
LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);