Certificate provisioning verification

bug: 8620943

This is a merge of changes made to the Widevine CDM
repository during certificate provisioning verification.

The following changes are included:

Fixes for certificate based licensing
https://widevine-internal-review.googlesource.com/#/c/5162/

Base64 encode and decode now handles non-multiple of 24-bits input
https://widevine-internal-review.googlesource.com/#/c/4981/

Fixed issues with device provisioning response handling
https://widevine-internal-review.googlesource.com/#/c/5153/

Persistent storage to support device certificates
https://widevine-internal-review.googlesource.com/#/c/5161/

Enable loading of certificates
https://widevine-internal-review.googlesource.com/#/c/5172/

Provide license server url
https://widevine-internal-review.googlesource.com/#/c/5173/

Change-Id: I0c032c1ae0055dcc1a7a77ad4b0ea0898030dc7d
This commit is contained in:
Jeff Tinker
2013-04-22 20:05:55 -07:00
parent 3a28eeeb68
commit 958bbe6d05
30 changed files with 1497 additions and 290 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2012 Google Inc. All Rights Reserved.
// Copyright 2013 Google Inc. All Rights Reserved.
#include "string_conversions.h"
@@ -12,14 +12,41 @@
#include "log.h"
namespace {
// Helper for Base64SafeDecode()
char B64ToBin(char inch) {
if (inch >= 'A' && inch <= 'Z') return inch - 'A';
if (inch >= 'a' && inch <= 'z') return inch - 'a' + 26;
if (inch >= '0' && inch <= '9') return inch - '0' + 52;
if (inch == '-') return 62;
// if (inch == '_')
return 63;
/*
* Returns a 8-bit char that is mapped to the 6-bit base64 in_ch.
*
* Extracted from http://www.ietf.org/rfc/rfc3548.txt.
*
The "URL and Filename safe" Base 64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 - (minus)
12 M 29 d 46 u 63 _
13 N 30 e 47 v (underline)
14 O 31 f 48 w
15 P 32 g 49 x
16 Q 33 h 50 y (pad) =
*/
char B64ToBin(char in_ch) {
if (in_ch >= 'A' && in_ch <= 'Z') return in_ch - 'A';
if (in_ch >= 'a' && in_ch <= 'z') return in_ch - 'a' + 26;
if (in_ch >= '0' && in_ch <= '9') return in_ch - '0' + 52;
if (in_ch == '-') return 62;
if (in_ch == '_') return 63;
// arbitrary delimiter not in Base64 encoded alphabet, do not pick 0
return '?';
}
}
@@ -75,10 +102,13 @@ std::string b2a_hex(const std::string& byte) {
byte.length());
}
// Filename-friendly base64 encoding (RFC4648).
// Filename-friendly base64 encoding (RFC4648), commonly referred as
// Base64WebSafeEncode.
// This is the encoding required by GooglePlay for certain
// license server transactions. It is also used for logging
// certain strings.
// The difference between web safe encoding vs regular encoding is that
// the web safe version replaces '+' with '-' and '/' with '_'.
std::string Base64SafeEncode(const std::vector<uint8_t>& bin_input) {
static const char kBase64Chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -87,9 +117,13 @@ std::string Base64SafeEncode(const std::vector<uint8_t>& bin_input) {
if (bin_input.empty()) {
return std::string();
}
int in_size = bin_input.size();
int rup = ((in_size % 3) != 0) ? 1 : 0;
int out_size = ((in_size * 4) / 3) + rup;
int final_quantum_in_bytes = in_size % 3;
int full_in_chunks = in_size / 3;
int out_size = full_in_chunks * 4;
if (final_quantum_in_bytes) out_size += 4;
std::string b64_output(out_size, '\0');
int in_index = 0;
int out_index = 0;
@@ -98,7 +132,7 @@ std::string Base64SafeEncode(const std::vector<uint8_t>& bin_input) {
static const unsigned long kInMask = 0xff;
static const unsigned long kOutMask = 0x3f;
while (in_index < in_size) {
for (int i = 0; i < full_in_chunks; ++i) {
// up to 3 bytes (0..255) in
buffer = (bin_input.at(in_index) & kInMask);
buffer <<= 8;
@@ -106,6 +140,7 @@ std::string Base64SafeEncode(const std::vector<uint8_t>& bin_input) {
buffer <<= 8;
buffer |= (++in_index >= in_size) ? 0 : (bin_input.at(in_index) & kInMask);
++in_index;
// up to 4 bytes (0..63) out
out_cc = (buffer >> 18) & kOutMask;
b64_output.at(out_index) = kBase64Chars[out_cc];
@@ -123,10 +158,49 @@ std::string Base64SafeEncode(const std::vector<uint8_t>& bin_input) {
b64_output.at(out_index) = kBase64Chars[out_cc];
++out_index;
}
if (final_quantum_in_bytes) {
switch(final_quantum_in_bytes) {
case 1: {
// reads 24-bits data, which is made up of one 8-bits char
buffer = (bin_input.at(in_index++) & kInMask);
buffer <<= 16;
// writes two 6-bits chars followed by two '=' padding char
out_cc = (buffer >> 18) & kOutMask;
b64_output.at(out_index++) = kBase64Chars[out_cc];
out_cc = (buffer >> 12) & kOutMask;
b64_output.at(out_index++) = kBase64Chars[out_cc];
b64_output.at(out_index++) = '=';
b64_output.at(out_index) = '=';
break;
}
case 2: {
// reads 24-bits data, which is made up of two 8-bits chars
buffer = (bin_input.at(in_index++) & kInMask);
buffer <<= 8;
buffer |= (bin_input.at(in_index++) & kInMask);
buffer <<= 8;
// writes three 6-bits chars followed by one '=' padding char
out_cc = (buffer >> 18) & kOutMask;
b64_output.at(out_index++) = kBase64Chars[out_cc];
out_cc = (buffer >> 12) & kOutMask;
b64_output.at(out_index++) = kBase64Chars[out_cc];
out_cc = (buffer >> 6) & kOutMask;
b64_output.at(out_index++) = kBase64Chars[out_cc];
b64_output.at(out_index) = '=';
break;
}
default:
break;
}
}
return b64_output;
}
// Decode for Filename-friendly base64 encoding (RFC4648).
// Decode for Filename-friendly base64 encoding (RFC4648), commonly referred
// as Base64WebSafeDecode.
// This is the encoding required by GooglePlay for certain
// license server transactions. It is also used for logging
// certain strings.
@@ -134,9 +208,9 @@ std::vector<uint8_t> Base64SafeDecode(const std::string& b64_input) {
if (b64_input.empty()) {
return std::vector<uint8_t>();
}
int in_size = b64_input.size();
// out_size should be an integral number of bytes, assuming correct encode
int out_size = ((in_size * 3) / 4);
int out_size = in_size;
std::vector<uint8_t> bin_output(out_size, '\0');
int in_index = 0;
int out_index = 0;
@@ -144,7 +218,14 @@ std::vector<uint8_t> Base64SafeDecode(const std::string& b64_input) {
unsigned char out_cc;
static const unsigned long kOutMask = 0xff;
while (in_index < in_size) {
int counter = 0;
size_t delimiter_pos = b64_input.rfind('=');
if (delimiter_pos != std::string::npos) {
// Special case for partial last quantum indicated by '='
// at the end of encoded input.
counter = 1;
}
for (; counter < (in_size / 4); ++counter) {
// up to 4 bytes (0..63) in
buffer = B64ToBin(b64_input.at(in_index));
buffer <<= 6;
@@ -167,6 +248,37 @@ std::vector<uint8_t> Base64SafeDecode(const std::string& b64_input) {
bin_output.at(out_index) = out_cc;
++out_index;
}
if (delimiter_pos != std::string::npos) {
// it is either 2 chars plus 2 '=' or 3 chars plus one '='
buffer = B64ToBin(b64_input.at(in_index++));
buffer <<= 6;
buffer |= B64ToBin(b64_input.at(in_index++));
buffer <<= 6;
char special_char = b64_input.at(in_index++);
if ('=' == special_char) {
// we have 2 chars and 2 '='
buffer <<= 6;
out_cc = (buffer >> 16) & kOutMask;
bin_output.at(out_index++) = out_cc;
out_cc = (buffer >> 8) & kOutMask;
bin_output.at(out_index) = out_cc;
} else {
// we have 3 chars and 1 '='
buffer |= B64ToBin(special_char);
buffer <<= 6;
buffer |= B64ToBin(b64_input.at(in_index));
out_cc = (buffer >> 16) & kOutMask;
bin_output.at(out_index++) = out_cc;
out_cc = (buffer >> 8) & kOutMask;
bin_output.at(out_index++) = out_cc;
out_cc = buffer & kOutMask;
bin_output.at(out_index) = out_cc;
}
}
// adjust vector to reflect true size
bin_output.resize(out_index);
return bin_output;
}