Export provisioning sdk

Change-Id: I4d47d80444c9507f84896767dc676112ca11e901
This commit is contained in:
Kongqun Yang
2017-01-24 20:06:25 -08:00
parent d2903a4951
commit 8d17e4549a
110 changed files with 10187 additions and 0 deletions

4
LICENSE Normal file
View File

@@ -0,0 +1,4 @@
Copyright 2017 Google, Inc.
This software is licensed under the terms defined in the Widevine Master License Agreement.
For a copy of this agreement, please contact widevine-licensing@google.com.

77
WORKSPACE Normal file
View File

@@ -0,0 +1,77 @@
workspace(name = "provisioning_sdk")
git_repository(
name = "protobuf_repo",
remote = "https://github.com/google/protobuf.git",
tag = "v3.0.0",
)
git_repository(
name = "boringssl_repo",
commit = "bbcaa15b0647816b9a1a9b9e0d209cd6712f0105", # 2016-07-11
remote = "https://github.com/google/boringssl.git",
)
git_repository(
name = "gflags_repo",
commit = "fe57e5af4db74ab298523f06d2c43aa895ba9f98", # 2016-07-20
remote = "https://github.com/gflags/gflags.git",
)
new_git_repository(
name = "googletest_repo",
build_file = "gtest.BUILD",
commit = "ec44c6c1675c25b9827aacd08c02433cccde7780", # 2016-07-26
remote = "https://github.com/google/googletest.git",
)
new_git_repository(
name = "glog_repo",
build_file = "glog.BUILD",
commit = "0472b91c5defdf90cff7292e3bf7bd86770a9a0a", # 2016-07-13
remote = "https://github.com/google/glog.git",
)
# py_proto_library depends on six indirectly (py_proto_library uses
# protobuf_python as its default runtime which depends on six).
new_http_archive(
name = "six_archive",
build_file = "@protobuf_repo//:six.BUILD",
sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
url = "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55",
)
bind(
name = "six",
actual = "@six_archive//:six",
)
bind(
name = "protobuf",
actual = "@protobuf_repo//:protobuf",
)
bind(
name = "openssl",
actual = "@boringssl_repo//:crypto",
)
bind(
name = "gflags",
actual = "@gflags_repo//:gflags",
)
bind(
name = "gtest",
actual = "@googletest_repo//:gtest",
)
bind(
name = "gtest_main",
actual = "@googletest_repo//:gtest_main",
)
bind(
name = "glog",
actual = "@glog_repo//:glog",
)

24
base/BUILD Normal file
View File

@@ -0,0 +1,24 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
package(
default_visibility = ["//visibility:public"],
)
cc_library(
name = "base",
hdrs = [
"macros.h",
"mutex.h",
"thread_annotations.h",
],
deps = [
"//external:gflags",
"//external:glog",
],
)

113
base/macros.h Normal file
View File

@@ -0,0 +1,113 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef BASE_MACROS_H_
#define BASE_MACROS_H_
#include <stddef.h> // For size_t
// DISALLOW_COPY_AND_ASSIGN disallows the copy constructor and copy assignment
// operator. DISALLOW_IMPLICIT_CONSTRUCTORS is like DISALLOW_COPY_AND_ASSIGN,
// but also disallows the default constructor, intended to help make a
// class uninstantiable.
//
// These must be placed in the private: declarations for a class.
//
// Note: New code should prefer static_assert over COMPILE_ASSERT.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
TypeName& operator=(const TypeName&) = delete
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName() = delete; \
DISALLOW_COPY_AND_ASSIGN(TypeName)
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
//
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
// That gcc wants both of these prototypes seems mysterious. VC, for
// its part, can't decide which to use (another mystery). Matching of
// template overloads: the final frontier.
#ifndef COMPILER_MSVC
template <typename T, size_t N>
char (&ArraySizeHelper(const T (&array)[N]))[N];
#endif
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
// A macro to turn a symbol into a std::string
#define AS_STRING(x) AS_STRING_INTERNAL(x)
#define AS_STRING_INTERNAL(x) #x
// The following enum should be used only as a constructor argument to indicate
// that the variable has static storage class, and that the constructor should
// do nothing to its state. It indicates to the reader that it is legal to
// declare a static instance of the class, provided the constructor is given
// the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declare a
// static variable that has a constructor or a destructor because invocation
// order is undefined. However, IF the type can be initialized by filling with
// zeroes (which the loader does for static variables), AND the type's
// destructor does nothing to the storage, then a constructor for static
// initialization can be declared as
// explicit MyClass(base::LinkerInitialized x) {}
// and invoked as
// static MyClass my_variable_name(base::LINKER_INITIALIZED);
namespace base {
enum LinkerInitialized { LINKER_INITIALIZED };
}
// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
// between switch labels:
// switch (x) {
// case 40:
// case 41:
// if (truth_is_out_there) {
// ++x;
// FALLTHROUGH_INTENDED; // Use instead of/along with annotations in
// // comments.
// } else {
// return x;
// }
// case 42:
// ...
//
// As shown in the example above, the FALLTHROUGH_INTENDED macro should be
// followed by a semicolon. It is designed to mimic control-flow statements
// like 'break;', so it can be placed in most places where 'break;' can, but
// only if there are no statements on the execution path between it and the
// next switch label.
//
// When compiled with clang in C++11 mode, the FALLTHROUGH_INTENDED macro is
// expanded to [[clang::fallthrough]] attribute, which is analysed when
// performing switch labels fall-through diagnostic ('-Wimplicit-fallthrough').
// See clang documentation on language extensions for details:
// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
//
// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
// effect on diagnostics.
//
// In either case this macro has no effect on runtime behavior and performance
// of code.
#if defined(__clang__) && defined(LANG_CXX11) && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
#endif
#endif
#ifndef FALLTHROUGH_INTENDED
#define FALLTHROUGH_INTENDED do { } while (0)
#endif
#endif // BASE_MACROS_H_

91
base/mutex.h Normal file
View File

@@ -0,0 +1,91 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef BASE_MUTEX_H_
#define BASE_MUTEX_H_
#include <stdlib.h>
#include <pthread.h>
#include "glog/logging.h"
#include "base/macros.h"
#include "base/thread_annotations.h"
// Basic mutex wrapper around a pthread RW lock.
class LOCKABLE Mutex {
public:
inline Mutex() { CHECK_EQ(pthread_rwlock_init(&lock_, nullptr), 0); }
inline Mutex(base::LinkerInitialized) { // NOLINT
CHECK_EQ(pthread_rwlock_init(&lock_, nullptr), 0);
}
inline ~Mutex() { CHECK_EQ(pthread_rwlock_destroy(&lock_), 0); }
inline void Lock() EXCLUSIVE_LOCK_FUNCTION() { WriterLock(); }
inline void Unlock() UNLOCK_FUNCTION() { WriterUnlock(); }
inline void ReaderLock() SHARED_LOCK_FUNCTION() {
CHECK_EQ(pthread_rwlock_rdlock(&lock_), 0);
}
inline void ReaderUnlock() UNLOCK_FUNCTION() {
CHECK_EQ(pthread_rwlock_unlock(&lock_), 0);
}
inline void WriterLock() EXCLUSIVE_LOCK_FUNCTION() {
CHECK_EQ(pthread_rwlock_wrlock(&lock_), 0);
}
inline void WriterUnlock() UNLOCK_FUNCTION() {
CHECK_EQ(pthread_rwlock_unlock(&lock_), 0);
}
private:
pthread_rwlock_t lock_;
DISALLOW_COPY_AND_ASSIGN(Mutex);
};
// -----------------------------------------------------------------------------
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
class SCOPED_LOCKABLE MutexLock {
public:
explicit MutexLock(Mutex* mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
this->mu_->Lock();
}
~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); }
private:
Mutex* const mu_;
DISALLOW_COPY_AND_ASSIGN(MutexLock);
};
// The ReaderMutexLock and WriterMutexLock classes work like MutexLock
// to acquire/release read and write locks on reader/writer locks.
class SCOPED_LOCKABLE ReaderMutexLock {
public:
explicit ReaderMutexLock(Mutex* mu) SHARED_LOCK_FUNCTION(mu) : mu_(mu) {
mu->ReaderLock();
}
~ReaderMutexLock() UNLOCK_FUNCTION() { this->mu_->ReaderUnlock(); }
private:
Mutex* const mu_;
DISALLOW_COPY_AND_ASSIGN(ReaderMutexLock);
};
class SCOPED_LOCKABLE WriterMutexLock {
public:
explicit WriterMutexLock(Mutex* mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
mu->WriterLock();
}
~WriterMutexLock() UNLOCK_FUNCTION() { this->mu_->WriterUnlock(); }
private:
Mutex* const mu_;
DISALLOW_COPY_AND_ASSIGN(WriterMutexLock);
};
#endif // BASE_MUTEX_H_

212
base/thread_annotations.h Normal file
View File

@@ -0,0 +1,212 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// This header file contains the macro definitions for thread safety
// annotations that allow the developers to document the locking policies
// of their multi-threaded code. The annotations can also help program
// analysis tools to identify potential thread safety issues.
//
//
// The annotations are implemented using GCC's "attributes" extension.
// Using the macros defined here instead of the raw GCC attributes allows
// for portability and future compatibility.
//
#ifndef BASE_THREAD_ANNOTATIONS_H_
#define BASE_THREAD_ANNOTATIONS_H_
#if defined(__GNUC__) && defined(__SUPPORT_TS_ANNOTATION__) && !defined(SWIG)
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
#if defined(__GNUC__) && !defined(__clang__)
// Document if a shared variable/field needs to be protected by a lock.
// GUARDED_BY allows the user to specify a particular lock that should be
// held when accessing the annotated variable, while GUARDED_VAR only
// indicates a shared variable should be guarded (by any lock). GUARDED_VAR
// is primarily used when the client cannot express the name of the lock.
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded)
// Document if the memory location pointed to by a pointer should be guarded
// by a lock when dereferencing the pointer. Similar to GUARDED_VAR,
// PT_GUARDED_VAR is primarily used when the client cannot express the name
// of the lock. Note that a pointer variable to a shared memory location
// could itself be a shared variable. For example, if a shared global pointer
// q, which is guarded by mu1, points to a shared memory location that is
// guarded by mu2, q should be annotated as follows:
// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
#define PT_GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded_by(x))
#define PT_GUARDED_VAR \
THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded)
// Document the acquisition order between locks that can be held
// simultaneously by a thread. For any two locks that need to be annotated
// to establish an acquisition order, only one of them needs the annotation.
// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
// and ACQUIRED_BEFORE.)
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
// The following three annotations document the lock requirements for
// functions/methods.
// Document if a function expects certain locks to be held before it is called
#define EXCLUSIVE_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
#define SHARED_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
// Document the locks acquired in the body of the function. These locks
// non-reentrant).
#define LOCKS_EXCLUDED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
// Document the lock the annotated function returns without acquiring it.
#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
// Document if a class/type is a lockable type (such as the Mutex class).
#define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable)
// Document if a class is a scoped lockable type (such as the MutexLock class).
#define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
// The following annotations specify lock and unlock primitives.
#define EXCLUSIVE_LOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock(__VA_ARGS__))
#define SHARED_LOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_lock(__VA_ARGS__))
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock(__VA_ARGS__))
#define SHARED_TRYLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock(__VA_ARGS__))
#define UNLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(unlock(__VA_ARGS__))
// An escape hatch for thread safety analysis to ignore the annotated function.
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
// Used to mark functions that need to be fixed, because they are producing
// thread safety warnings. This macro is intended primarily for use by the
// compiler team; it allows new thread safety warnings to be rolled out
// without breaking existing code. Code which triggers the new warnings are
// marked with a FIXME, and referred back to the code owners to fix.
#define NO_THREAD_SAFETY_ANALYSIS_FIXME \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
// NO_THREAD_SAFETY_ANALYSIS_OPT turns off thread-safety checking in the
// annotated function in opt (NDEBUG) mode. It is for use specifically when
// the thread-safety checker is failing in opt mode on an otherwise correct
// piece of code.
#ifdef NDEBUG
#define NO_THREAD_SAFETY_ANALYSIS_OPT NO_THREAD_SAFETY_ANALYSIS
#else
#define NO_THREAD_SAFETY_ANALYSIS_OPT
#endif
// TS_UNCHECKED should be placed around lock expressions that are not valid
// C++ syntax, but which are present for documentation purposes. The
// expressions are passed unchanged to gcc, which will usually treat them
// as the universal lock.
#define TS_UNCHECKED(x) x
// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
// This annotation should eventually be either fixed, or changed to
// TS_UNCHECKED.
#define TS_FIXME(x) x
// This is used to pass different annotations to gcc and clang, in cases where
// gcc would reject a lock expression (e.g. &MyClass::mu_) that is accepted
// by clang. This is seldom needed, since GCC usually ignores invalid lock
// expressions except in certain cases, such as LOCK_RETURNED.
#define TS_CLANG_ONLY(CLANG_EXPR, GCC_EXPR) GCC_EXPR
// Clang Attributes
// The names of attributes in the clang analysis are slightly different
#else
#define GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define GUARDED_VAR \
THREAD_ANNOTATION_ATTRIBUTE__(guarded)
#define PT_GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
#define PT_GUARDED_VAR \
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded)
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
#define EXCLUSIVE_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
#define SHARED_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
#define LOCKS_EXCLUDED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
#define LOCK_RETURNED(x) \
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
#define LOCKABLE \
THREAD_ANNOTATION_ATTRIBUTE__(lockable)
#define SCOPED_LOCKABLE \
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
#define EXCLUSIVE_LOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
#define SHARED_LOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
#define SHARED_TRYLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
#define UNLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
#define NO_THREAD_SAFETY_ANALYSIS_OPT
#define NO_THREAD_SAFETY_ANALYSIS_FIXME \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
#define TS_UNCHECKED(x) ""
#define TS_FIXME(x) ""
#define TS_CLANG_ONLY(CLANG_EXPR, GCC_EXPR) CLANG_EXPR
#endif // defined(__clang__)
#endif // BASE_THREAD_ANNOTATIONS_H_

164
common/BUILD Normal file
View File

@@ -0,0 +1,164 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
#
# Description:
# Build file for code common to multiple Widevine services.
package(default_visibility = ["//visibility:public"])
cc_library(
name = "rsa_util",
srcs = ["rsa_util.cc"],
hdrs = ["rsa_util.h"],
deps = [
"//base",
"//external:openssl",
],
)
cc_test(
name = "rsa_util_test",
size = "medium",
timeout = "short",
srcs = ["rsa_util_test.cc"],
deps = [
":rsa_test_keys",
":rsa_util",
"//external:gtest",
"//external:gtest_main",
],
)
cc_library(
name = "openssl_util",
hdrs = ["openssl_util.h"],
deps = [
"//external:openssl",
],
)
cc_library(
name = "rsa_key",
srcs = ["rsa_key.cc"],
hdrs = ["rsa_key.h"],
deps = [
":rsa_util",
":sha_util",
"//base",
"//external:openssl",
],
)
cc_test(
name = "rsa_key_test",
size = "medium",
timeout = "short",
srcs = ["rsa_key_test.cc"],
deps = [
":rsa_key",
":rsa_test_keys",
"//external:gtest",
"//external:gtest_main",
],
)
cc_library(
name = "rsa_test_keys",
testonly = 1,
srcs = ["rsa_test_keys.cc"],
hdrs = ["rsa_test_keys.h"],
deps = [
"//base",
],
)
cc_library(
name = "mock_rsa_key",
testonly = 1,
hdrs = ["mock_rsa_key.h"],
deps = [
":rsa_key",
"//external:gtest",
],
)
cc_library(
name = "aes_cbc_util",
srcs = ["aes_cbc_util.cc"],
hdrs = ["aes_cbc_util.h"],
visibility = ["//visibility:public"],
deps = [
"//base",
"//external:openssl",
],
)
cc_test(
name = "aes_cbc_util_test",
srcs = ["aes_cbc_util_test.cc"],
deps = [
":aes_cbc_util",
"//external:gtest_main",
],
)
cc_library(
name = "random_util",
srcs = ["random_util.cc"],
hdrs = ["random_util.h"],
deps = [
"//base",
"//external:openssl",
],
)
cc_test(
name = "random_util_test",
srcs = ["random_util_test.cc"],
deps = [
":random_util",
"//external:gtest_main",
],
)
cc_library(
name = "sha_util",
srcs = ["sha_util.cc"],
hdrs = ["sha_util.h"],
deps = [
"//external:openssl",
],
)
cc_test(
name = "sha_util_test",
srcs = ["sha_util_test.cc"],
deps = [
":sha_util",
"//external:gtest_main",
],
)
cc_library(
name = "file_util",
srcs = ["file_util.cc"],
hdrs = ["file_util.h"],
deps = [
"//base",
],
)
cc_test(
name = "file_util_test",
srcs = ["file_util_test.cc"],
deps = [
":file_util",
"//external:gtest_main",
],
)

93
common/aes_cbc_util.cc Normal file
View File

@@ -0,0 +1,93 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/aes_cbc_util.h"
#include <vector>
#include "glog/logging.h"
#include "openssl/aes.h"
namespace widevine {
namespace crypto_util {
// Encrypts the provided plantext std::string using AES-CBC encryption.
std::string EncryptAesCbc(const std::string& key, const std::string& iv,
const std::string& plaintext) {
if (iv.size() != AES_BLOCK_SIZE) return "";
const size_t num_padding_bytes =
AES_BLOCK_SIZE - (plaintext.size() % AES_BLOCK_SIZE);
std::string padded_text = plaintext;
padded_text.append(num_padding_bytes, static_cast<char>(num_padding_bytes));
AES_KEY aes_key;
if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(&key[0]),
key.size() * 8, &aes_key) != 0) {
return "";
}
std::string encrypted(padded_text);
std::vector<uint8_t> local_iv(iv.begin(), iv.end());
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(padded_text.data()),
reinterpret_cast<uint8_t*>(&encrypted[0]), padded_text.size(),
&aes_key, &local_iv[0], AES_ENCRYPT);
return encrypted;
}
// Decrypts the AES-CBC encrypted text. Returns an empty std::string on error or
// the plaintext on success.
std::string DecryptAesCbc(const std::string& key, const std::string& iv,
const std::string& ciphertext) {
if (ciphertext.empty()) return "";
if (iv.size() != AES_BLOCK_SIZE) return "";
if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) return "";
AES_KEY aes_key;
if (AES_set_decrypt_key(reinterpret_cast<const uint8_t*>(&key[0]),
key.size() * 8, &aes_key) != 0) {
return "";
}
std::string cleartext(ciphertext);
std::vector<uint8_t> local_iv(iv.begin(), iv.end());
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(ciphertext.data()),
reinterpret_cast<uint8_t*>(&cleartext[0]), ciphertext.size(),
&aes_key, &local_iv[0], AES_DECRYPT);
const uint8_t num_padding_bytes = cleartext[cleartext.size() - 1];
if (num_padding_bytes > AES_BLOCK_SIZE) return "";
for (uint8_t i = 0; i < num_padding_bytes; ++i) {
if (cleartext[cleartext.size() - 1 - i] != num_padding_bytes) return "";
}
cleartext.resize(cleartext.size() - num_padding_bytes);
return cleartext;
}
std::string DecryptAesCbcNoPad(const std::string& key, const std::string& iv,
const std::string& ciphertext) {
std::vector<uint8_t> local_iv(iv.begin(), iv.end());
if (local_iv.empty()) local_iv.resize(AES_BLOCK_SIZE, '\0');
else if (local_iv.size() != AES_BLOCK_SIZE) return "";
if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) return "";
AES_KEY aes_key;
if (AES_set_decrypt_key(reinterpret_cast<const uint8_t*>(&key[0]),
key.size() * 8, &aes_key) != 0) {
return "";
}
std::string cleartext(ciphertext);
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(ciphertext.data()),
reinterpret_cast<uint8_t*>(&cleartext[0]), ciphertext.size(),
&aes_key, &local_iv[0], AES_DECRYPT);
return cleartext;
}
} // namespace crypto_util
} // namespace widevine

38
common/aes_cbc_util.h Normal file
View File

@@ -0,0 +1,38 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_AES_CBC_UTIL_H_
#define COMMON_AES_CBC_UTIL_H_
#include <string>
namespace widevine {
namespace crypto_util {
// Helper for wrapping AES CBC encryption. Uses PKCS5 padding.
std::string EncryptAesCbc(const std::string& key, const std::string& iv,
const std::string& plaintext);
// Helper for common Keybox decrypt operations; wraps AES-CBC. Returns an
// empty std::string on error or the plaintext on success. Uses PKCS5 padding.
std::string DecryptAesCbc(const std::string& key, const std::string& iv,
const std::string& ciphertext);
// Helper for common Keybox decrypt operations; wraps AES-CBC. Returns an
// empty std::string on error or the plaintext on success.
// Uses no padding; fails if the ciphertext is not a multiple of 16 bytes.
// This is used to decrypt the encrypted blob in the WVM keyboxes, with
// a zero iv.
std::string DecryptAesCbcNoPad(const std::string& key, const std::string& iv,
const std::string& ciphertext);
} // namespace crypto_util
} // namespace widevine
#endif // COMMON_AES_CBC_UTIL_H_

137
common/aes_cbc_util_test.cc Normal file
View File

@@ -0,0 +1,137 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/aes_cbc_util.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace {
const uint8_t kKey[] = {
0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82, 0x32, 0x9e,
0x6b, 0x3b, 0x4e, 0x29, 0xfa, 0x3b, 0x00, 0x4b,
};
const uint8_t kIv[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
};
} // namespace
namespace widevine {
namespace crypto_util {
TEST(CryptoUtilTest, EncryptAndDecryptAesCbc) {
std::string plain_text("Foo");
std::string ciphertext = EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), plain_text);
std::string expected_ciphertext(
"\xCF\x1A\x3\x1C\x9C\x8C\xB9Z\xEC\xC0\x17\xDCRxX\xD7");
ASSERT_EQ(0, ciphertext.size() % 16);
ASSERT_GT(ciphertext.size(), plain_text.size());
ASSERT_EQ(expected_ciphertext, ciphertext);
std::string decrypted = DecryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), ciphertext);
ASSERT_EQ(plain_text, decrypted);
}
TEST(CryptoUtilTest, DecryptAesCbcNoPad) {
const uint8_t kKey[] = {
0xdd, 0x71, 0x39, 0xea, 0xfa, 0xce, 0xed, 0x7c,
0xda, 0x9f, 0x25, 0xda, 0x8a, 0xa9, 0x15, 0xea,
};
const uint8_t kIv[] = {
0x5d, 0x16, 0x44, 0xea, 0xec, 0x11, 0xf9, 0x83,
0x14, 0x75, 0x41, 0xe4, 0x6e, 0xeb, 0x27, 0x74,
};
const uint8_t kCiphertext[] = {
0x6d, 0xa6, 0xda, 0xe4, 0xee, 0x40, 0x09, 0x17,
0x54, 0x7b, 0xba, 0xa5, 0x27, 0xb8, 0x82, 0x1b,
};
const uint8_t kExpectedPlaintext[] = {
0xb3, 0x49, 0xd4, 0x80, 0x9e, 0x91, 0x06, 0x87,
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10,
};
const uint8_t kExpectedPlaintextEmptyIv[] = {
0xee, 0x5f, 0x90, 0x6a, 0x72, 0x80, 0xff, 0x04,
0x14, 0x75, 0x41, 0xa4, 0x6e, 0xeb, 0x27, 0x64,
};
std::string decrypted = DecryptAesCbcNoPad(
std::string(kKey, kKey + sizeof(kKey)), std::string(kIv, kIv + sizeof(kIv)),
std::string(kCiphertext, kCiphertext + sizeof(kCiphertext)));
ASSERT_EQ(std::string(kExpectedPlaintext,
kExpectedPlaintext + sizeof(kExpectedPlaintext)),
decrypted);
std::string dummy_iv;
decrypted = DecryptAesCbcNoPad(
std::string(kKey, kKey + sizeof(kKey)), dummy_iv,
std::string(kCiphertext, kCiphertext + sizeof(kCiphertext)));
ASSERT_EQ(
std::string(kExpectedPlaintextEmptyIv,
kExpectedPlaintextEmptyIv + sizeof(kExpectedPlaintextEmptyIv)),
decrypted);
}
TEST(CryptoUtilTest, TestFailedEncrypt) {
// Test with bogus initialization vector.
std::string plain_text("Foo");
std::string bogus_iv("bogus");
std::string ciphertext =
EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), bogus_iv, plain_text);
ASSERT_EQ(ciphertext.size(), 0);
// Test with bogus key.
std::string bogus_key("bogus");
ciphertext =
EncryptAesCbc(bogus_key, std::string(kIv, kIv + sizeof(kIv)), plain_text);
ASSERT_EQ(ciphertext.size(), 0);
}
TEST(CryptoUtilTest, TestFailedDecrypt) {
// First, encrypt the data.
std::string plain_text("Foo");
std::string ciphertext = EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), plain_text);
ASSERT_NE(ciphertext.size(), 0);
// Test Decrypt with bogus iv.
std::string bogus_iv("bogus");
plain_text =
DecryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), bogus_iv, ciphertext);
ASSERT_EQ(plain_text.size(), 0);
// Test Decrypt with bogus key.
std::string bogus_key("bogus");
plain_text =
DecryptAesCbc(bogus_key, std::string(kIv, kIv + sizeof(kIv)), ciphertext);
ASSERT_EQ(plain_text.size(), 0);
}
TEST(CryptoUtilTest, TestEmptyEncrypt) {
EXPECT_EQ("\xDBx\xD9\x91\xE8\x1D\xD9\x19\x80r\x12\x89\xD7Kp\xEB",
EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), ""));
}
TEST(CryptoUtilTest, TestEmptyDecryptAesCbc) {
EXPECT_EQ("", DecryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), ""));
}
TEST(CryptoUtilTest, TestEmptyDecryptAesCbcNoPad) {
EXPECT_EQ("", DecryptAesCbcNoPad(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), ""));
}
} // namespace crypto_util
} // namespace widevine

63
common/file_util.cc Normal file
View File

@@ -0,0 +1,63 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/file_util.h"
#include <stddef.h>
#include <stdio.h>
#include "glog/logging.h"
namespace widevine {
bool GetContents(const std::string& file_name, std::string* contents) {
if (file_name.empty()) {
LOG(WARNING) << "File name is empty.";
return false;
}
FILE* file = fopen(file_name.c_str(), "r");
if (!file) {
LOG(WARNING) << "Unable to open file " << file_name;
return false;
}
contents->clear();
const size_t kReadSize = 0x1000;
char buffer[kReadSize];
while (true) {
size_t size_read = fread(buffer, sizeof(char), kReadSize, file);
if (size_read == 0) break;
contents->append(buffer, size_read);
}
const bool eof = feof(file);
fclose(file);
if (!eof) {
LOG(WARNING) << "Failed to read all file contents.";
return false;
}
return true;;
}
bool SetContents(const std::string& file_name, const std::string& contents) {
if (file_name.empty()) {
LOG(WARNING) << "File name is empty.";
return false;
}
FILE* file = fopen(file_name.c_str(), "w");
if (!file) {
LOG(WARNING) << "Unable to open file " << file_name;
return false;
}
const size_t size_written =
fwrite(contents.data(), sizeof(char), contents.size(), file);
if (size_written != contents.size())
LOG(WARNING) << "Failed to write to " << file_name;
fclose(file);
return size_written == contents.size();
}
} // namespace widevine

27
common/file_util.h Normal file
View File

@@ -0,0 +1,27 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// File util wrapper to be used in partner sdks. Implemented using generic file
// apis.
#ifndef COMMON_FILE_UTIL_H_
#define COMMON_FILE_UTIL_H_
#include <string>
namespace widevine {
// Read file to string.
bool GetContents(const std::string& file_name, std::string* contents);
// Write file.
bool SetContents(const std::string& file_name, const std::string& contents);
} // namespace widevine
#endif // COMMON_FILE_UTIL_H_

29
common/file_util_test.cc Normal file
View File

@@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/file_util.h"
#include "gtest/gtest.h"
namespace widevine {
TEST(FileUtilTest, EmptyFileName) {
std::string contents;
EXPECT_FALSE(GetContents("", &contents));
EXPECT_FALSE(SetContents("", "test content"));
}
TEST(FileUtilTest, BasicTest) {
const std::string file_path = FLAGS_test_tmpdir + "/file_util_test";
EXPECT_TRUE(SetContents(file_path, "test content"));
std::string contents;
EXPECT_TRUE(GetContents(file_path, &contents));
EXPECT_EQ("test content", contents);
}
} // namespace widevine

71
common/mock_rsa_key.h Normal file
View File

@@ -0,0 +1,71 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_MOCK_RSA_KEY_H_
#define COMMON_MOCK_RSA_KEY_H_
#include "common/rsa_key.h"
namespace widevine {
class MockRsaPrivateKey : public RsaPrivateKey {
public:
MockRsaPrivateKey() : RsaPrivateKey(RSA_new()) {}
~MockRsaPrivateKey() override {}
MOCK_CONST_METHOD2(Decrypt, bool(const std::string& encrypted_message,
std::string* decrypted_message));
MOCK_CONST_METHOD2(GenerateSignature,
bool(const std::string& message, std::string* signature));
MOCK_CONST_METHOD1(MatchesPrivateKey, bool(const RsaPrivateKey& private_key));
MOCK_CONST_METHOD1(MatchesPublicKey, bool(const RsaPublicKey& public_key));
private:
MockRsaPrivateKey(const MockRsaPrivateKey&) = delete;
MockRsaPrivateKey& operator=(const MockRsaPrivateKey&) = delete;
};
class MockRsaPublicKey : public RsaPublicKey {
public:
MockRsaPublicKey() : RsaPublicKey(RSA_new()) {}
~MockRsaPublicKey() override {}
MOCK_CONST_METHOD2(Encrypt, bool(const std::string& clear_message,
std::string* encrypted_message));
MOCK_CONST_METHOD2(VerifySignature, bool(const std::string& message,
const std::string& signature));
MOCK_CONST_METHOD1(MatchesPrivateKey, bool(const RsaPrivateKey& private_key));
MOCK_CONST_METHOD1(MatchesPublicKey, bool(const RsaPublicKey& public_key));
private:
MockRsaPublicKey(const MockRsaPublicKey&) = delete;
MockRsaPublicKey& operator=(const MockRsaPublicKey&) = delete;
};
class MockRsaKeyFactory : public RsaKeyFactory{
public:
MockRsaKeyFactory() {}
~MockRsaKeyFactory() override {}
MOCK_METHOD1(CreateFromPkcs1PrivateKey,
std::unique_ptr<RsaPrivateKey>(const std::string& private_key));
MOCK_METHOD2(
CreateFromPkcs8PrivateKey,
std::unique_ptr<RsaPrivateKey>(const std::string& private_key,
const std::string& private_key_passphrase));
MOCK_METHOD1(CreateFromPkcs1PublicKey,
std::unique_ptr<RsaPublicKey>(const std::string& public_key));
private:
MockRsaKeyFactory(const MockRsaKeyFactory&) = delete;
MockRsaKeyFactory& operator=(const MockRsaKeyFactory&) = delete;
};
} // namespace widevine
#endif // COMMON_MOCK_RSA_KEY_H_

70
common/openssl_util.h Normal file
View File

@@ -0,0 +1,70 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_OPENSSL_UTIL_H__
#define COMMON_OPENSSL_UTIL_H__
#include "openssl/bio.h"
#include "openssl/evp.h"
#include "openssl/rsa.h"
#include "openssl/x509v3.h"
template <typename T, void (*func)(T *)>
struct OpenSSLDeleter {
void operator()(T *obj) { func(obj); }
};
template <typename StackType, typename T, void (*func)(T *)>
struct OpenSSLStackDeleter {
void operator()(StackType *obj) {
sk_pop_free(reinterpret_cast<_STACK *>(obj),
reinterpret_cast<void (*)(void *)>(func));
}
};
template <typename StackType>
struct OpenSSLStackOnlyDeleter {
void operator()(StackType *obj) { sk_free(reinterpret_cast<_STACK *>(obj)); }
};
template <typename T, void (*func)(T *)>
using ScopedOpenSSLType = std::unique_ptr<T, OpenSSLDeleter<T, func>>;
template <typename StackType, typename T, void (*func)(T *)>
using ScopedOpenSSLStack =
std::unique_ptr<StackType, OpenSSLStackDeleter<StackType, T, func>>;
template <typename StackType>
using ScopedOpenSSLStackOnly =
std::unique_ptr<StackType, OpenSSLStackOnlyDeleter<StackType>>;
using ScopedBIO = ScopedOpenSSLType<BIO, BIO_vfree>;
using ScopedPKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
using ScopedX509 = ScopedOpenSSLType<X509, X509_free>;
using ScopedX509Extension =
ScopedOpenSSLType<X509_EXTENSION, X509_EXTENSION_free>;
using ScopedX509Name = ScopedOpenSSLType<X509_NAME, X509_NAME_free>;
using ScopedX509NameEntry =
ScopedOpenSSLType<X509_NAME_ENTRY, X509_NAME_ENTRY_free>;
using ScopedX509Store = ScopedOpenSSLType<X509_STORE, X509_STORE_free>;
using ScopedX509StoreCtx =
ScopedOpenSSLType<X509_STORE_CTX, X509_STORE_CTX_free>;
using ScopedAsn1UtcTime = ScopedOpenSSLType<ASN1_UTCTIME, ASN1_UTCTIME_free>;
using ScopedAsn1Utc8String =
ScopedOpenSSLType<ASN1_UTF8STRING, ASN1_UTF8STRING_free>;
using ScopedAsn1Integer = ScopedOpenSSLType<ASN1_INTEGER, ASN1_INTEGER_free>;
// XxxStack deallocates the stack and its members while XxxStackOnly deallocates
// the stack only.
using ScopedX509Stack = ScopedOpenSSLStack<STACK_OF(X509), X509, X509_free>;
using ScopedX509StackOnly = ScopedOpenSSLStackOnly<STACK_OF(X509)>;
using ScopedX509InfoStack =
ScopedOpenSSLStack<STACK_OF(X509_INFO), X509_INFO, X509_INFO_free>;
using ScopedX509InfoStackOnly = ScopedOpenSSLStackOnly<STACK_OF(X509_INFO)>;
#endif // COMMON_OPENSSL_UTIL_H__

22
common/random_util.cc Normal file
View File

@@ -0,0 +1,22 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/random_util.h"
#include "glog/logging.h"
#include "openssl/rand.h"
namespace widevine {
bool RandomBytes(size_t num_bytes, std::string* output) {
DCHECK(output);
output->resize(num_bytes);
return RAND_bytes(reinterpret_cast<uint8_t*>(&(*output)[0]), num_bytes);
}
} // namespace widevine

22
common/random_util.h Normal file
View File

@@ -0,0 +1,22 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_RANDOM_UTIL_H_
#define COMMON_RANDOM_UTIL_H_
#include <string>
namespace widevine {
// Generates a random string.
// Return true on success, false otherwise.
bool RandomBytes(size_t num_bytes, std::string* output);
} // namespace widevine
#endif // COMMON_RANDOM_UTIL_H_

View File

@@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/random_util.h"
#include "gtest/gtest.h"
namespace widevine {
TEST(RandomUtilTest, Test) {
std::string output;
ASSERT_TRUE(RandomBytes(16u, &output));
EXPECT_EQ(16u, output.size());
std::string output2;
ASSERT_TRUE(RandomBytes(16u, &output2));
EXPECT_EQ(16u, output2.size());
EXPECT_NE(output, output2);
ASSERT_TRUE(RandomBytes(10u, &output2));
EXPECT_EQ(10u, output2.size());
}
} // namespace widevine

296
common/rsa_key.cc Normal file
View File

@@ -0,0 +1,296 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Definition of classes representing RSA private and public keys used
// for message signing, signature verification, encryption and decryption.
//
// RSA signature details:
// Algorithm: RSASSA-PSS
// Hash algorithm: SHA1
// Mask generation function: mgf1SHA1
// Salt length: 20 bytes
// Trailer field: 0xbc
//
// RSA encryption details:
// Algorithm: RSA-OAEP
// Mask generation function: mgf1SHA1
// Label (encoding paramter): empty std::string
#include "common/rsa_key.h"
#include "glog/logging.h"
#include "openssl/bn.h"
#include "openssl/err.h"
#include "openssl/evp.h"
#include "openssl/rsa.h"
#include "openssl/sha.h"
#include "common/rsa_util.h"
#include "common/sha_util.h"
static const int kPssSaltLength = 20;
namespace {
// Check if two RSA keys match. If matches, they are either a public-private key
// pair or the same public key or the same private key.
bool RsaKeyMatch(const RSA* key1, const RSA* key2) {
if (!key1 || !key2) return false;
return BN_cmp(key1->n, key2->n) == 0;
}
} // namespace
namespace widevine {
RsaPrivateKey::RsaPrivateKey(RSA* key) : key_(CHECK_NOTNULL(key)) {}
RsaPrivateKey::~RsaPrivateKey() { RSA_free(key_); }
RsaPrivateKey* RsaPrivateKey::Create(const std::string& serialized_key) {
RSA* key;
if (!rsa_util::DeserializeRsaPrivateKey(serialized_key, &key)) return nullptr;
if (RSA_check_key(key) != 1) {
LOG(ERROR) << "Invalid private RSA key: "
<< ERR_error_string(ERR_get_error(), nullptr);
RSA_free(key);
}
return new RsaPrivateKey(key);
}
bool RsaPrivateKey::Decrypt(const std::string& encrypted_message,
std::string* decrypted_message) const {
DCHECK(decrypted_message);
size_t rsa_size = RSA_size(key_);
if (encrypted_message.size() != rsa_size) {
LOG(ERROR) << "Encrypted RSA message has the wrong size (expected "
<< rsa_size << ", actual " << encrypted_message.size() << ")";
return false;
}
decrypted_message->assign(rsa_size, 0);
int decrypted_size = RSA_private_decrypt(
rsa_size,
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(encrypted_message.data())),
reinterpret_cast<unsigned char*>(&(*decrypted_message)[0]), key_,
RSA_PKCS1_OAEP_PADDING);
if (decrypted_size == -1) {
LOG(ERROR) << "RSA private decrypt failure: "
<< ERR_error_string(ERR_get_error(), nullptr);
return false;
}
decrypted_message->resize(decrypted_size);
return true;
}
bool RsaPrivateKey::GenerateSignature(const std::string& message,
std::string* signature) const {
DCHECK(signature);
if (message.empty()) {
LOG(ERROR) << "Message to be signed is empty";
return false;
}
// Hash the message using SHA1.
std::string message_digest = Sha1_Hash(message);
// Add PSS padding.
size_t rsa_size = RSA_size(key_);
std::string padded_digest(rsa_size, 0);
if (!RSA_padding_add_PKCS1_PSS_mgf1(
key_, reinterpret_cast<unsigned char*>(&padded_digest[0]),
reinterpret_cast<unsigned char*>(&message_digest[0]), EVP_sha1(),
EVP_sha1(), kPssSaltLength)) {
LOG(ERROR) << "RSA padding failure: "
<< ERR_error_string(ERR_get_error(), nullptr);
return false;
}
// Encrypt PSS padded digest.
signature->assign(rsa_size, 0);
if (RSA_private_encrypt(padded_digest.size(),
reinterpret_cast<unsigned char*>(&padded_digest[0]),
reinterpret_cast<unsigned char*>(&(*signature)[0]),
key_, RSA_NO_PADDING) !=
static_cast<int>(signature->size())) {
LOG(ERROR) << "RSA private encrypt failure: "
<< ERR_error_string(ERR_get_error(), nullptr);
return false;
}
return true;
}
bool RsaPrivateKey::GenerateSignatureSha256Pkcs7(const std::string& message,
std::string* signature) const {
DCHECK(signature);
if (message.empty()) {
LOG(ERROR) << "Empty signature verification message";
return false;
}
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(message.data()),
message.size(),
digest);
unsigned int sig_len = RSA_size(key_);
signature->resize(sig_len);
return RSA_sign(NID_sha256,
digest,
sizeof(digest),
reinterpret_cast<unsigned char*>(&(*signature)[0]),
&sig_len,
key_) == 1;
}
bool RsaPrivateKey::MatchesPrivateKey(const RsaPrivateKey& private_key) const {
return RsaKeyMatch(key(), private_key.key());
}
bool RsaPrivateKey::MatchesPublicKey(const RsaPublicKey& public_key) const {
return RsaKeyMatch(key(), public_key.key());
}
RsaPublicKey::RsaPublicKey(RSA* key) : key_(CHECK_NOTNULL(key)) {}
RsaPublicKey::~RsaPublicKey() { RSA_free(key_); }
RsaPublicKey* RsaPublicKey::Create(const std::string& serialized_key) {
RSA* key;
if (!rsa_util::DeserializeRsaPublicKey(serialized_key, &key)) return nullptr;
if (RSA_size(key) == 0) {
LOG(ERROR) << "Invalid public RSA key: "
<< ERR_error_string(ERR_get_error(), nullptr);
RSA_free(key);
}
return new RsaPublicKey(key);
}
bool RsaPublicKey::Encrypt(const std::string& clear_message,
std::string* encrypted_message) const {
DCHECK(encrypted_message);
if (clear_message.empty()) {
LOG(ERROR) << "Message to be encrypted is empty";
return false;
}
size_t rsa_size = RSA_size(key_);
encrypted_message->assign(rsa_size, 0);
if (RSA_public_encrypt(
clear_message.size(),
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(clear_message.data())),
reinterpret_cast<unsigned char*>(&(*encrypted_message)[0]), key_,
RSA_PKCS1_OAEP_PADDING) != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA public encrypt failure: "
<< ERR_error_string(ERR_get_error(), nullptr);
return false;
}
return true;
}
bool RsaPublicKey::VerifySignature(const std::string& message,
const std::string& signature) const {
if (message.empty()) {
LOG(ERROR) << "Signed message is empty";
return false;
}
size_t rsa_size = RSA_size(key_);
if (signature.size() != rsa_size) {
LOG(ERROR) << "Message signature is of the wrong size (expected "
<< rsa_size << ", actual " << signature.size() << ")";
return false;
}
// Decrypt the signature.
std::string padded_digest(signature.size(), 0);
if (RSA_public_decrypt(
signature.size(),
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(signature.data())),
reinterpret_cast<unsigned char*>(&padded_digest[0]), key_,
RSA_NO_PADDING) != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA public decrypt failure: "
<< ERR_error_string(ERR_get_error(), nullptr);
return false;
}
// Hash the message using SHA1.
std::string message_digest = Sha1_Hash(message);
// Verify PSS padding.
return RSA_verify_PKCS1_PSS_mgf1(
key_, reinterpret_cast<unsigned char*>(&message_digest[0]),
EVP_sha1(), EVP_sha1(),
reinterpret_cast<unsigned char*>(&padded_digest[0]),
kPssSaltLength) != 0;
}
bool RsaPublicKey::VerifySignatureSha256Pkcs7(
const std::string& message, const std::string& signature) const {
if (message.empty()) {
LOG(ERROR) << "Empty signature verification message";
return false;
}
if (signature.empty()) {
LOG(ERROR) << "Empty signature";
return false;
}
if (signature.size() != RSA_size(key_)) {
LOG(ERROR) << "RSA signature has the wrong size";
return false;
}
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(message.data()),
message.size(),
digest);
return RSA_verify(NID_sha256,
digest,
sizeof(digest),
reinterpret_cast<const unsigned char*>(signature.data()),
signature.size(),
key_) == 1;
}
bool RsaPublicKey::MatchesPrivateKey(const RsaPrivateKey& private_key) const {
return RsaKeyMatch(key(), private_key.key());
}
bool RsaPublicKey::MatchesPublicKey(const RsaPublicKey& public_key) const {
return RsaKeyMatch(key(), public_key.key());
}
RsaKeyFactory::RsaKeyFactory() {}
RsaKeyFactory::~RsaKeyFactory() {}
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs1PrivateKey(
const std::string& private_key) {
return std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key));
}
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs8PrivateKey(
const std::string& private_key, const std::string& private_key_passphrase) {
std::string pkcs1_key;
const bool result =
private_key_passphrase.empty()
? rsa_util::PrivateKeyInfoToRsaPrivateKey(private_key, &pkcs1_key)
: rsa_util::EncryptedPrivateKeyInfoToRsaPrivateKey(
private_key, private_key_passphrase, &pkcs1_key);
if (!result) {
LOG(WARNING) << "Failed to get pkcs1_key.";
return std::unique_ptr<RsaPrivateKey>();
}
return std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(pkcs1_key));
}
std::unique_ptr<RsaPublicKey> RsaKeyFactory::CreateFromPkcs1PublicKey(
const std::string& public_key) {
return std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key));
}
} // namespace widevine

131
common/rsa_key.h Normal file
View File

@@ -0,0 +1,131 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Declaration of classes representing RSA private and public keys used
// for message signing, signature verification, encryption and decryption.
#ifndef COMMON_RSA_KEY_H_
#define COMMON_RSA_KEY_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "openssl/rsa.h"
namespace widevine {
class RsaPublicKey;
class RsaPrivateKey {
public:
explicit RsaPrivateKey(RSA* key);
virtual ~RsaPrivateKey();
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
// Returns NULL on failure.
static RsaPrivateKey* Create(const std::string& serialized_key);
// Decrypt a message using RSA-OAEP. Caller retains ownership of all
// parameters. Returns true if successful, false otherwise.
virtual bool Decrypt(const std::string& encrypted_message,
std::string* decrypted_message) const;
// Generate RSSASSA-PSS signature. Caller retains ownership of all parameters.
// Returns true if successful, false otherwise.
virtual bool GenerateSignature(const std::string& message,
std::string* signature) const;
// Generate SHA256 digest, PKCS#7 padded signature. Caller retains ownership
// of all parameters. Returns true if successful, false otherwise.
virtual bool GenerateSignatureSha256Pkcs7(const std::string& message,
std::string* signature) const;
// Return true if the underlying key matches with |private_key|.
virtual bool MatchesPrivateKey(const RsaPrivateKey& private_key) const;
// Return true if the underlying key is a public-private key pair with
// |public_key|.
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
const RSA* key() const { return key_; }
private:
RSA* key_;
DISALLOW_COPY_AND_ASSIGN(RsaPrivateKey);
};
class RsaPublicKey {
public:
explicit RsaPublicKey(RSA* key);
virtual ~RsaPublicKey();
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
// Returns NULL on failure.
static RsaPublicKey* Create(const std::string& serialized_key);
// Encrypt a message using RSA-OAEP. Caller retains ownership of all
// parameters. Returns true if successful, false otherwise.
virtual bool Encrypt(const std::string& clear_message,
std::string* encrypted_message) const;
// Verify RSSASSA-PSS signature. Caller retains ownership of all parameters.
// Returns true if validation succeeds, false otherwise.
virtual bool VerifySignature(const std::string& message,
const std::string& signature) const;
// Verify a signature. This method takes two parameters: |message| which is a
// std::string containing the data which was signed, and |signature| which is a
// std::string containing the message SHA256 digest signature with PKCS#7
// padding. Returns true if verification succeeds, false otherwise.
virtual bool VerifySignatureSha256Pkcs7(const std::string& message,
const std::string& signature) const;
// Return true if the underlying key is a public-private key pair with
// |private_key|.
virtual bool MatchesPrivateKey(const RsaPrivateKey& private_key) const;
// Return true if the underlying key matches with |public_key|.
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
const RSA* key() const { return key_; }
private:
RSA* key_;
DISALLOW_COPY_AND_ASSIGN(RsaPublicKey);
};
class RsaKeyFactory {
public:
RsaKeyFactory();
virtual ~RsaKeyFactory();
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs1PrivateKey(
const std::string& private_key);
// Create an RsaPrivateKey object using an encrypted PKCS#8 RSAPrivateKey.
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs8PrivateKey(
const std::string& private_key, const std::string& private_key_passphrase);
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
virtual std::unique_ptr<RsaPublicKey> CreateFromPkcs1PublicKey(
const std::string& public_key);
private:
DISALLOW_COPY_AND_ASSIGN(RsaKeyFactory);
};
} // namespace widevine
#endif // COMMON_RSA_KEY_H_

227
common/rsa_key_test.cc Normal file
View File

@@ -0,0 +1,227 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit test for rsa_key RSA encryption and signing.
#include <memory>
#include "gtest/gtest.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
#include "common/rsa_util.h"
namespace widevine {
static const char kTestMessage[] =
"A fool thinks himself to be wise, but a wise man knows himself to be a "
"fool.";
class RsaKeyTest : public ::testing::Test {
protected:
void TestEncryption(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key);
void TestSigning(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key);
void TestSigningSha256Pkcs7(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key);
RsaTestKeys test_keys_;
RsaKeyFactory factory_;
};
void RsaKeyTest::TestEncryption(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key) {
ASSERT_TRUE(private_key);
ASSERT_TRUE(public_key);
std::string encrypted_message;
EXPECT_TRUE(public_key->Encrypt(kTestMessage, &encrypted_message));
std::string decrypted_message;
EXPECT_TRUE(private_key->Decrypt(encrypted_message, &decrypted_message));
EXPECT_EQ(kTestMessage, decrypted_message);
// Add a byte to the encrypted message.
std::string bad_enc_message(encrypted_message);
bad_enc_message += '\0';
EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message));
// Remove a byte from the encrypted message.
bad_enc_message = encrypted_message.substr(0, encrypted_message.size() - 1);
EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message));
// Change a byte in the encrypted message.
bad_enc_message = encrypted_message;
bad_enc_message[128] ^= 0x55;
EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message));
}
void RsaKeyTest::TestSigning(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key) {
ASSERT_TRUE(private_key);
ASSERT_TRUE(public_key);
std::string signature;
EXPECT_TRUE(private_key->GenerateSignature(kTestMessage, &signature));
EXPECT_TRUE(public_key->VerifySignature(kTestMessage, signature));
// Add a byte to the signature.
std::string bad_signature(signature);
bad_signature += '\0';
EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature));
// Remove a byte from the signature.
bad_signature = signature.substr(0, signature.size() - 1);
EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature));
// Change a byte in the signature.
bad_signature = signature;
bad_signature[32] ^= 0x55;
EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature));
}
void RsaKeyTest::TestSigningSha256Pkcs7(
std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key) {
ASSERT_TRUE(private_key);
ASSERT_TRUE(public_key);
std::string signature;
EXPECT_TRUE(
private_key->GenerateSignatureSha256Pkcs7(kTestMessage, &signature));
EXPECT_TRUE(public_key->VerifySignatureSha256Pkcs7(kTestMessage, signature));
// Add a byte to the signature.
std::string bad_signature(signature);
bad_signature += '\0';
EXPECT_FALSE(
public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature));
// Remove a byte from the signature.
bad_signature = signature.substr(0, signature.size() - 1);
EXPECT_FALSE(
public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature));
// Change a byte in the signature.
bad_signature = signature;
bad_signature[32] ^= 0x55;
EXPECT_FALSE(
public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature));
}
TEST_F(RsaKeyTest, BadKey) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create("bad_private_key"));
EXPECT_TRUE(!private_key);
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create("bad_public_key"));
EXPECT_TRUE(!public_key);
}
TEST_F(RsaKeyTest, EncryptAndDecrypt_3072) {
const std::string& private_key = test_keys_.private_test_key_1_3072_bits();
const std::string& public_key = test_keys_.public_test_key_1_3072_bits();
TestEncryption(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
TestEncryption(factory_.CreateFromPkcs1PrivateKey(private_key),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, EncryptAndDecrypt_2048) {
const std::string& private_key = test_keys_.private_test_key_2_2048_bits();
const std::string& public_key = test_keys_.public_test_key_2_2048_bits();
TestEncryption(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
std::string pkcs8_key;
std::string passphrase("passphrase");
ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
private_key, passphrase, &pkcs8_key));
TestEncryption(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase),
factory_.CreateFromPkcs1PublicKey(public_key));
ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key));
TestEncryption(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerify_3072) {
const std::string& private_key = test_keys_.private_test_key_1_3072_bits();
const std::string& public_key = test_keys_.public_test_key_1_3072_bits();
TestSigning(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
TestSigning(factory_.CreateFromPkcs1PrivateKey(private_key),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerify_2048) {
const std::string& private_key = test_keys_.private_test_key_2_2048_bits();
const std::string& public_key = test_keys_.public_test_key_2_2048_bits();
TestSigning(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
std::string pkcs8_key;
std::string passphrase("passphrase");
ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
private_key, passphrase, &pkcs8_key));
TestSigning(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase),
factory_.CreateFromPkcs1PublicKey(public_key));
ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key));
TestSigning(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_3072) {
const std::string& private_key = test_keys_.private_test_key_1_3072_bits();
const std::string& public_key = test_keys_.public_test_key_1_3072_bits();
TestSigningSha256Pkcs7(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
TestSigningSha256Pkcs7(factory_.CreateFromPkcs1PrivateKey(private_key),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_2048) {
const std::string& private_key = test_keys_.private_test_key_2_2048_bits();
const std::string& public_key = test_keys_.public_test_key_2_2048_bits();
TestSigningSha256Pkcs7(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
std::string pkcs8_key;
std::string passphrase("passphrase");
ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
private_key, passphrase, &pkcs8_key));
TestSigningSha256Pkcs7(
factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase),
factory_.CreateFromPkcs1PublicKey(public_key));
ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key));
TestSigningSha256Pkcs7(
factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, RsaKeyMatch) {
std::unique_ptr<RsaPrivateKey> private_key2(
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
std::unique_ptr<RsaPrivateKey> private_key3(
RsaPrivateKey::Create(test_keys_.private_test_key_3_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key2(
RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key3(
RsaPublicKey::Create(test_keys_.public_test_key_3_2048_bits()));
EXPECT_TRUE(public_key2->MatchesPublicKey(*public_key2));
EXPECT_FALSE(public_key2->MatchesPublicKey(*public_key3));
EXPECT_TRUE(public_key2->MatchesPrivateKey(*private_key2));
EXPECT_FALSE(public_key2->MatchesPrivateKey(*private_key3));
EXPECT_TRUE(private_key2->MatchesPublicKey(*public_key2));
EXPECT_FALSE(private_key2->MatchesPublicKey(*public_key3));
EXPECT_TRUE(private_key2->MatchesPrivateKey(*private_key2));
EXPECT_FALSE(private_key2->MatchesPrivateKey(*private_key3));
}
} // namespace widevine

682
common/rsa_test_keys.cc Normal file
View File

@@ -0,0 +1,682 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA keys generated using fake_prng for purposes of testing.
#include "common/rsa_test_keys.h"
namespace widevine {
static const unsigned char kTestRsaPrivateKey1_3072[] = {
0x30, 0x82, 0x06, 0xe3, 0x02, 0x01, 0x00, 0x02,
0x82, 0x01, 0x81, 0x00, 0xa5, 0x62, 0x07, 0xdf,
0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0,
0x78, 0x76, 0xbe, 0x13, 0x3b, 0xe6, 0x2c, 0x09,
0x9d, 0x35, 0x3f, 0xf3, 0x0f, 0xe9, 0x61, 0x96,
0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2,
0xca, 0xe4, 0xdd, 0xd5, 0x96, 0xaf, 0x9a, 0xd7,
0x08, 0x47, 0xe4, 0x55, 0x1b, 0x83, 0xbe, 0x10,
0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29,
0x46, 0xc2, 0x65, 0x97, 0xa6, 0xcc, 0x4b, 0xa4,
0x08, 0xc3, 0x04, 0x17, 0x01, 0xb5, 0x11, 0x53,
0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37,
0x5c, 0xb4, 0x7a, 0x1d, 0x5d, 0x6c, 0x58, 0xc2,
0x82, 0xa0, 0x92, 0xf1, 0x14, 0xf1, 0x22, 0xff,
0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86,
0xcd, 0xa0, 0x0a, 0x63, 0x08, 0xdd, 0x60, 0x5d,
0xfd, 0xa4, 0x01, 0xe3, 0xb6, 0x0e, 0x85, 0xe4,
0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4,
0xde, 0xf2, 0x59, 0x11, 0xe3, 0x5b, 0x02, 0x9f,
0x24, 0xb9, 0xb0, 0xbb, 0x31, 0xa0, 0xee, 0x6a,
0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee,
0x3a, 0xae, 0xb2, 0x2e, 0x84, 0xa0, 0x47, 0x42,
0x51, 0xbb, 0xfa, 0xbb, 0x90, 0x97, 0x2c, 0x77,
0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca,
0x49, 0x94, 0x53, 0x5d, 0x37, 0xaf, 0x86, 0x47,
0xda, 0xe2, 0xbd, 0xf0, 0x5f, 0x07, 0x53, 0x8a,
0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6,
0xda, 0xea, 0x1e, 0x2e, 0x54, 0xec, 0x44, 0xde,
0x3a, 0xe1, 0xc8, 0xdb, 0x17, 0xe8, 0xc9, 0x3a,
0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab,
0x30, 0xb7, 0xf5, 0x1b, 0x03, 0x86, 0x21, 0xa9,
0xf5, 0xca, 0x15, 0x26, 0xaf, 0x39, 0xf3, 0x5d,
0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10,
0x16, 0x9c, 0xee, 0xc3, 0xbd, 0xcc, 0xdb, 0x02,
0x82, 0xd0, 0x60, 0x0b, 0x42, 0x72, 0x85, 0xec,
0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21,
0xf9, 0xa6, 0x82, 0x40, 0xd3, 0xc5, 0xc9, 0xf9,
0x6b, 0xc9, 0x12, 0x64, 0xe4, 0x3a, 0x3b, 0xc9,
0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05,
0x4a, 0xe9, 0x4c, 0x46, 0x2b, 0xb6, 0xe1, 0xed,
0x82, 0xb2, 0xf0, 0xd1, 0x72, 0x71, 0x04, 0x35,
0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab,
0xde, 0x8f, 0xe1, 0xc1, 0x49, 0x68, 0x0c, 0xc8,
0xce, 0x6d, 0x87, 0x50, 0x04, 0xb5, 0xd7, 0x24,
0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85,
0x1b, 0x38, 0xff, 0x2f, 0x71, 0xf5, 0x30, 0x18,
0x1e, 0x6f, 0xd7, 0xf0, 0x33, 0x61, 0x53, 0x7e,
0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b,
0x67, 0xd5, 0xf0, 0x2e, 0x23, 0x23, 0x60, 0x0b,
0x83, 0x9c, 0xc2, 0x87, 0x02, 0x03, 0x01, 0x00,
0x01, 0x02, 0x82, 0x01, 0x80, 0x5a, 0x09, 0x3f,
0x9e, 0x2e, 0x4d, 0x26, 0x50, 0x7b, 0x70, 0x21,
0xb0, 0x0c, 0x25, 0x21, 0x1f, 0xd9, 0x89, 0x5a,
0xca, 0x35, 0x23, 0x0b, 0x58, 0xa9, 0x7d, 0xf6,
0x19, 0xc4, 0x29, 0x87, 0xc7, 0xd4, 0x94, 0x85,
0xb4, 0x2c, 0xaf, 0x62, 0xb1, 0xe8, 0x62, 0x5b,
0xda, 0xdb, 0x70, 0x40, 0x37, 0xb1, 0x4e, 0x0c,
0xc8, 0x62, 0xee, 0xa2, 0xfc, 0x3c, 0xd2, 0x39,
0x90, 0x15, 0x2c, 0xba, 0x20, 0x50, 0xb7, 0x82,
0x2a, 0xa0, 0x76, 0x83, 0x20, 0x7f, 0x56, 0x73,
0x43, 0x8a, 0x9b, 0xa7, 0x6c, 0x63, 0xb6, 0xad,
0x56, 0xb2, 0x8a, 0xb2, 0xbc, 0x8f, 0xe2, 0xef,
0x83, 0x9d, 0x98, 0x0b, 0xc7, 0x62, 0x0e, 0x51,
0x6e, 0x57, 0x1d, 0x1b, 0x0e, 0x3a, 0xea, 0x3b,
0x76, 0x63, 0x35, 0xd0, 0xd1, 0xcf, 0xbe, 0xad,
0xbb, 0x1d, 0xde, 0x0f, 0x05, 0x48, 0x55, 0x29,
0xc1, 0xbc, 0x21, 0xc7, 0x87, 0xf2, 0x75, 0x12,
0x7d, 0x92, 0x9e, 0xbf, 0xad, 0x04, 0x68, 0xc4,
0xc9, 0x9d, 0x35, 0xd6, 0xa8, 0x62, 0xc1, 0x69,
0x6a, 0xb6, 0x41, 0xb7, 0x37, 0x66, 0xdf, 0xb2,
0xb9, 0x8c, 0x8b, 0x15, 0x08, 0x4c, 0x3d, 0xf1,
0xed, 0x82, 0x0f, 0xe3, 0xd5, 0xff, 0x46, 0xbd,
0xf7, 0x85, 0x43, 0xc0, 0x8b, 0xba, 0x47, 0xf1,
0x41, 0x57, 0xc3, 0x7f, 0x8b, 0x0d, 0x48, 0xea,
0xc2, 0xed, 0xc0, 0x69, 0x84, 0xb6, 0x32, 0x08,
0x49, 0x74, 0x14, 0x84, 0xa4, 0x1b, 0x48, 0x5b,
0xec, 0xd3, 0x0b, 0x12, 0x2b, 0x4c, 0x9e, 0x5c,
0x01, 0x60, 0xad, 0xef, 0xcb, 0x2b, 0x56, 0x84,
0x07, 0xfa, 0x62, 0xc6, 0x08, 0x92, 0x98, 0x70,
0xc9, 0x5b, 0x18, 0xc8, 0xfa, 0x27, 0x0c, 0xe2,
0xbd, 0xfb, 0x3e, 0x43, 0xa5, 0xb7, 0x06, 0x2c,
0x4e, 0xf1, 0x07, 0x5d, 0x8d, 0xdd, 0x53, 0xc5,
0x8c, 0x4a, 0xf2, 0x2f, 0x8e, 0x80, 0x96, 0x16,
0xc0, 0xfc, 0xf9, 0x20, 0x4f, 0x35, 0xc7, 0x53,
0x8b, 0x2d, 0x37, 0x43, 0x93, 0x3d, 0x74, 0x3f,
0x63, 0xf7, 0x0b, 0xbd, 0x46, 0xe4, 0x51, 0x67,
0x33, 0x57, 0x15, 0xf5, 0x59, 0x27, 0x66, 0xe8,
0xe2, 0x4b, 0xa3, 0x93, 0x03, 0x8a, 0x9c, 0x05,
0x13, 0xf2, 0xcb, 0xf7, 0x9c, 0x68, 0xe7, 0x16,
0x4b, 0x8e, 0x59, 0x71, 0x2b, 0x73, 0x9b, 0xb9,
0xae, 0x50, 0xfa, 0xd7, 0xd3, 0x34, 0x17, 0x1d,
0x62, 0x88, 0xbd, 0x8c, 0xba, 0x5a, 0x6b, 0x6a,
0x5e, 0xb3, 0xa5, 0x80, 0xca, 0xbb, 0xb9, 0xb5,
0xa8, 0x2e, 0xb1, 0x61, 0x6e, 0xd5, 0xd6, 0x62,
0x98, 0x4a, 0xb0, 0xb8, 0x76, 0xa9, 0x19, 0x5c,
0xe2, 0xbe, 0xb3, 0x9b, 0x4a, 0x39, 0xf5, 0xe6,
0xbb, 0x11, 0x6e, 0x13, 0x13, 0x38, 0xb8, 0x1f,
0x21, 0x19, 0xf5, 0xa7, 0x76, 0x93, 0xb3, 0x56,
0xfa, 0xcc, 0x74, 0xbc, 0x19, 0x02, 0x81, 0xc1,
0x00, 0xd1, 0xd1, 0x72, 0x57, 0xe5, 0xb0, 0x1c,
0x09, 0x05, 0xbb, 0x55, 0x89, 0x3c, 0x4a, 0x81,
0x90, 0x9a, 0xf9, 0x32, 0x63, 0x41, 0xad, 0x6a,
0x5f, 0x65, 0x94, 0x92, 0xcc, 0xf7, 0xc7, 0x53,
0x93, 0xa0, 0xf7, 0xbe, 0x48, 0x82, 0x63, 0x31,
0x7b, 0xd0, 0x82, 0x09, 0xbb, 0x0a, 0xbc, 0x60,
0xc9, 0x4d, 0x83, 0xe4, 0x5d, 0x50, 0xe6, 0x5f,
0x8b, 0x47, 0x07, 0xa3, 0x3a, 0x36, 0x97, 0xaa,
0x21, 0x70, 0x7f, 0xd5, 0x6c, 0xb0, 0x56, 0xf5,
0x5c, 0x48, 0x74, 0x2a, 0xdd, 0xfe, 0x94, 0x83,
0x05, 0xe0, 0x3d, 0x5d, 0xdd, 0x5a, 0x05, 0xcb,
0x47, 0xd7, 0xf9, 0x89, 0x55, 0xaa, 0x0b, 0x21,
0xc0, 0x71, 0x5d, 0xe1, 0x4c, 0x6a, 0x45, 0x86,
0x86, 0xf2, 0xb9, 0x38, 0x6a, 0x56, 0x51, 0x0d,
0x7d, 0xac, 0x30, 0x31, 0xca, 0x2d, 0xaa, 0xaa,
0xba, 0xcc, 0x12, 0x40, 0xc1, 0x0d, 0xa6, 0xc1,
0x7d, 0x22, 0xec, 0xb6, 0x51, 0x45, 0xfe, 0x4e,
0xbb, 0x4a, 0xd2, 0xba, 0x9b, 0xa2, 0xcc, 0x28,
0x2b, 0x01, 0x53, 0x53, 0xf3, 0xa9, 0x5a, 0x8f,
0xeb, 0xb7, 0xb8, 0x62, 0x6b, 0x8a, 0x79, 0x24,
0xcc, 0x86, 0x34, 0x45, 0xe2, 0xad, 0x1d, 0xd0,
0x4c, 0xc9, 0x77, 0x2a, 0xf9, 0x1a, 0xe8, 0x58,
0x78, 0x51, 0x8a, 0xea, 0x3f, 0x90, 0x36, 0x46,
0x2a, 0xc0, 0x71, 0x41, 0x83, 0x2c, 0x48, 0xee,
0xc5, 0x02, 0x81, 0xc1, 0x00, 0xc9, 0xc8, 0xce,
0xc4, 0x50, 0xb2, 0x26, 0xcb, 0x35, 0x78, 0x55,
0x3c, 0xcc, 0xf0, 0x7e, 0xba, 0xad, 0xeb, 0x58,
0xe9, 0xb5, 0x78, 0x2f, 0x43, 0x5f, 0x07, 0x47,
0x56, 0x05, 0x41, 0x38, 0x71, 0xe1, 0x58, 0x62,
0xb1, 0x8e, 0xbc, 0xf9, 0x80, 0x04, 0x22, 0x39,
0x22, 0x24, 0x28, 0x86, 0x9c, 0x00, 0x44, 0x5f,
0xc4, 0x97, 0xe6, 0x71, 0x5f, 0x1f, 0x58, 0xea,
0x75, 0x18, 0x0c, 0x23, 0x63, 0x09, 0xc5, 0x98,
0xc4, 0x6d, 0x23, 0xc2, 0x2c, 0x93, 0x6a, 0x26,
0xe4, 0x3d, 0x8d, 0xa1, 0x39, 0x70, 0x34, 0x25,
0xcd, 0xbc, 0x82, 0x78, 0x2b, 0xf3, 0x7e, 0x81,
0xb6, 0x5f, 0xc5, 0x69, 0xd0, 0x81, 0x69, 0x50,
0x2f, 0x17, 0x0c, 0x17, 0x3c, 0x0b, 0x45, 0x38,
0xce, 0xe3, 0xbf, 0x8a, 0x50, 0x0a, 0x00, 0x74,
0x7e, 0x7a, 0xd8, 0x55, 0x52, 0x6b, 0x82, 0xfb,
0x34, 0x15, 0x73, 0x6a, 0xf4, 0x51, 0x9b, 0x9f,
0xa0, 0x45, 0xb9, 0x76, 0xe5, 0xd3, 0xd5, 0xf4,
0xa9, 0xa4, 0xcd, 0x42, 0x2f, 0x29, 0x89, 0xec,
0x28, 0x5f, 0x03, 0x45, 0x27, 0xaf, 0x8c, 0x39,
0x3e, 0x59, 0x9d, 0xaf, 0x27, 0x5d, 0x17, 0x53,
0x17, 0xeb, 0x8d, 0x7f, 0x3d, 0xb8, 0x2a, 0x50,
0x1e, 0xb5, 0xc5, 0x04, 0xab, 0x9c, 0xa7, 0xaa,
0x86, 0x41, 0xb9, 0x36, 0x29, 0x9e, 0xd2, 0xd8,
0xde, 0x5f, 0xde, 0x80, 0xdb, 0x02, 0x81, 0xc0,
0x03, 0xf3, 0x5f, 0xa5, 0xcc, 0x0b, 0x5e, 0xdb,
0xc4, 0xa1, 0xdc, 0x60, 0x73, 0x24, 0x2c, 0x00,
0x5f, 0x0a, 0xa6, 0x2a, 0x3c, 0x48, 0x59, 0xa2,
0x66, 0x35, 0x3f, 0xf6, 0x60, 0x0b, 0xfe, 0xc4,
0xde, 0xd9, 0x0b, 0x5a, 0x2e, 0x2a, 0x53, 0xfa,
0x32, 0xd8, 0xdf, 0xfa, 0x07, 0x9f, 0xb8, 0x6a,
0xd1, 0xec, 0xd3, 0xd5, 0xf5, 0xfa, 0x00, 0x7e,
0x8c, 0xdd, 0xd5, 0xf2, 0xf8, 0xa8, 0x2e, 0x69,
0xe6, 0xc6, 0x61, 0x6c, 0x64, 0x7d, 0x9e, 0xad,
0x18, 0x28, 0x27, 0xce, 0x7a, 0x46, 0xad, 0x98,
0xe4, 0xba, 0x03, 0x14, 0x71, 0xe7, 0x7e, 0x06,
0x62, 0x48, 0xae, 0x8f, 0x50, 0x5e, 0x59, 0x4a,
0x58, 0x58, 0x1e, 0x2f, 0xe4, 0x28, 0x5e, 0xfa,
0x17, 0x83, 0xe9, 0x4e, 0x07, 0x46, 0x0b, 0x6c,
0xfc, 0x5b, 0x03, 0xf4, 0xfc, 0x9b, 0x24, 0x0f,
0xd4, 0x5b, 0xdb, 0xa0, 0x46, 0xf3, 0x86, 0xdd,
0x26, 0x55, 0x32, 0xb1, 0xa1, 0x11, 0xc2, 0xc5,
0xc0, 0x08, 0xeb, 0xbe, 0x96, 0x78, 0x25, 0xa1,
0x79, 0xaa, 0xe9, 0xff, 0xc2, 0x86, 0x94, 0x03,
0x2a, 0x38, 0x6c, 0x91, 0xfd, 0xcf, 0x7e, 0x23,
0xe3, 0xbb, 0x04, 0x3d, 0xda, 0x68, 0x9f, 0x4d,
0x72, 0xd5, 0xad, 0x97, 0x77, 0x2c, 0x3c, 0xce,
0x37, 0x2a, 0xd8, 0x72, 0x4d, 0xf2, 0xd7, 0xab,
0x62, 0x68, 0x3f, 0x85, 0x8a, 0xc5, 0xec, 0xc9,
0x02, 0x81, 0xc1, 0x00, 0x92, 0x43, 0x0c, 0x1d,
0x20, 0xa1, 0x01, 0x9d, 0xaa, 0x54, 0x5e, 0xf4,
0x83, 0x58, 0x8f, 0x83, 0xa1, 0x2d, 0x46, 0x75,
0xa1, 0x24, 0x4c, 0x9d, 0xf8, 0xf3, 0xbd, 0xb1,
0x8c, 0x7d, 0x89, 0xfc, 0x81, 0xeb, 0x1f, 0x1e,
0xb4, 0xe8, 0x25, 0xb1, 0xb5, 0x4d, 0x59, 0x3c,
0x76, 0x19, 0x29, 0xf9, 0x49, 0xf8, 0x45, 0xb2,
0xaa, 0xa8, 0x4e, 0xe5, 0x34, 0x43, 0xaf, 0x2e,
0xd1, 0x0f, 0x7b, 0x56, 0xfe, 0x6e, 0x4c, 0x1d,
0x95, 0x3e, 0xa6, 0x30, 0xc9, 0x69, 0xd8, 0x66,
0xf8, 0x77, 0x00, 0xb6, 0x31, 0xae, 0x9a, 0xf8,
0x55, 0xfb, 0xfc, 0x3f, 0x5f, 0x70, 0x03, 0x75,
0xbe, 0x55, 0xca, 0x2d, 0x68, 0xa0, 0x7d, 0x8e,
0xa4, 0x96, 0x0f, 0x01, 0x66, 0xe9, 0xf6, 0x13,
0x80, 0xe2, 0x05, 0xcf, 0x9e, 0x70, 0x56, 0x00,
0x97, 0xea, 0xd7, 0x6d, 0xb6, 0xa0, 0x6a, 0x95,
0x86, 0x36, 0xf2, 0xff, 0xc5, 0x67, 0x98, 0x7d,
0x04, 0x0d, 0x3b, 0x31, 0xbc, 0x2b, 0x09, 0xfd,
0x2d, 0x87, 0xda, 0xc1, 0x74, 0xca, 0x94, 0x73,
0x6e, 0xeb, 0x5f, 0xe5, 0x34, 0x49, 0xdf, 0xf4,
0x61, 0xe0, 0xfa, 0x64, 0xfe, 0x05, 0x3a, 0x25,
0xcc, 0x87, 0xf4, 0x03, 0x38, 0xca, 0xf2, 0xe8,
0x4f, 0xb9, 0x4f, 0x79, 0x55, 0x43, 0xf3, 0x46,
0xfd, 0xbc, 0xd2, 0x95, 0xb8, 0x99, 0xfc, 0xb8,
0xb3, 0xa5, 0x04, 0xa1, 0x02, 0x81, 0xc0, 0x47,
0xc6, 0x9c, 0x18, 0x54, 0xe5, 0xbb, 0xf9, 0xf4,
0x38, 0xd2, 0xc0, 0xd1, 0x1a, 0xcc, 0xdb, 0x06,
0x87, 0x75, 0x1f, 0x13, 0xa2, 0x7f, 0x8b, 0x45,
0x54, 0xcb, 0x43, 0xf8, 0xbb, 0x94, 0xd6, 0x2e,
0x56, 0x5c, 0x69, 0x6d, 0x83, 0xb5, 0x45, 0x46,
0x68, 0x5c, 0x76, 0x1e, 0x6c, 0x0c, 0x53, 0x59,
0xcc, 0x19, 0xc7, 0x81, 0x62, 0x66, 0x92, 0x02,
0x8f, 0xa6, 0xdb, 0x50, 0x1c, 0x67, 0xfc, 0x82,
0x56, 0x2b, 0x4b, 0x1f, 0x97, 0x87, 0xc4, 0x7d,
0x20, 0xda, 0xd3, 0x3f, 0x28, 0xf9, 0x55, 0xfe,
0x84, 0x50, 0xc5, 0x3b, 0xd4, 0xaf, 0xf5, 0x3d,
0x43, 0xce, 0xdc, 0x55, 0x11, 0x87, 0xdb, 0x72,
0x66, 0xcc, 0x83, 0xc4, 0x8b, 0x20, 0xae, 0x59,
0x4d, 0xeb, 0xac, 0xb5, 0x4a, 0xec, 0x66, 0x09,
0x37, 0x55, 0x14, 0x21, 0x57, 0xff, 0x0a, 0xac,
0xda, 0xb1, 0xae, 0x31, 0xab, 0x41, 0x30, 0x65,
0x02, 0x83, 0xd1, 0xdb, 0x65, 0xb7, 0x52, 0xa7,
0x21, 0x9f, 0x1f, 0x8f, 0x69, 0x23, 0x3b, 0xb8,
0xf9, 0x6d, 0xe7, 0xc1, 0x53, 0x9f, 0x8f, 0x67,
0xfc, 0x6e, 0x20, 0x18, 0x31, 0x89, 0xe7, 0xbb,
0xd4, 0xc1, 0x03, 0x67, 0xd6, 0xa5, 0x76, 0xc9,
0xea, 0x97, 0x93, 0x02, 0xca, 0x44, 0x52, 0x55,
0x0f, 0xed, 0x55, 0xb5, 0x49, 0xd6, 0x94, 0x59,
0xee, 0xcc, 0x1b, 0x5a, 0x00, 0x3d, 0xcd };
static const unsigned char kTestRsaPublicKey1_3072[] = {
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81,
0x00, 0xa5, 0x62, 0x07, 0xdf, 0xc8, 0x84, 0x74,
0xe1, 0x2a, 0xb7, 0xbb, 0xc0, 0x78, 0x76, 0xbe,
0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f,
0xf3, 0x0f, 0xe9, 0x61, 0x96, 0x20, 0x53, 0x6e,
0x78, 0x62, 0xe0, 0x10, 0xd2, 0xca, 0xe4, 0xdd,
0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4,
0x55, 0x1b, 0x83, 0xbe, 0x10, 0x66, 0x74, 0x08,
0xf2, 0x49, 0x79, 0xea, 0x29, 0x46, 0xc2, 0x65,
0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04,
0x17, 0x01, 0xb5, 0x11, 0x53, 0xe9, 0x68, 0x34,
0x3c, 0x26, 0x56, 0x44, 0x37, 0x5c, 0xb4, 0x7a,
0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92,
0xf1, 0x14, 0xf1, 0x22, 0xff, 0x64, 0xde, 0xdf,
0xb3, 0x3d, 0x9d, 0xa5, 0x86, 0xcd, 0xa0, 0x0a,
0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01,
0xe3, 0xb6, 0x0e, 0x85, 0xe4, 0xc3, 0x37, 0x61,
0xd0, 0xe7, 0x12, 0xe9, 0xc4, 0xde, 0xf2, 0x59,
0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0,
0xbb, 0x31, 0xa0, 0xee, 0x6a, 0x2c, 0xb4, 0x30,
0xff, 0xe0, 0xf0, 0x93, 0xee, 0x3a, 0xae, 0xb2,
0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa,
0xbb, 0x90, 0x97, 0x2c, 0x77, 0x45, 0xee, 0x2c,
0xfb, 0xec, 0x5d, 0xd8, 0xca, 0x49, 0x94, 0x53,
0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd,
0xf0, 0x5f, 0x07, 0x53, 0x8a, 0x10, 0xd0, 0x9a,
0xd0, 0x7f, 0xe9, 0xef, 0xf6, 0xda, 0xea, 0x1e,
0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8,
0xdb, 0x17, 0xe8, 0xc9, 0x3a, 0x81, 0x11, 0x4d,
0xb7, 0x2d, 0x09, 0x83, 0xab, 0x30, 0xb7, 0xf5,
0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15,
0x26, 0xaf, 0x39, 0xf3, 0x5d, 0x01, 0x7d, 0xe3,
0x19, 0x54, 0xd1, 0x2e, 0x10, 0x16, 0x9c, 0xee,
0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60,
0x0b, 0x42, 0x72, 0x85, 0xec, 0xdc, 0x41, 0x7c,
0xf1, 0x34, 0xd8, 0x27, 0x21, 0xf9, 0xa6, 0x82,
0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12,
0x64, 0xe4, 0x3a, 0x3b, 0xc9, 0x8f, 0x3c, 0xd0,
0x2c, 0xb8, 0xb8, 0xf3, 0x05, 0x4a, 0xe9, 0x4c,
0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0,
0xd1, 0x72, 0x71, 0x04, 0x35, 0x19, 0xc1, 0x16,
0x17, 0xd6, 0x75, 0xe0, 0xab, 0xde, 0x8f, 0xe1,
0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87,
0x50, 0x04, 0xb5, 0xd7, 0x24, 0xf4, 0x2e, 0x0c,
0x11, 0x35, 0xb2, 0x67, 0x85, 0x1b, 0x38, 0xff,
0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7,
0xf0, 0x33, 0x61, 0x53, 0x7e, 0x55, 0x7f, 0x0d,
0x60, 0x83, 0xf3, 0x8a, 0x2b, 0x67, 0xd5, 0xf0,
0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2,
0x87, 0x02, 0x03, 0x01, 0x00, 0x01 };
static const unsigned char kTestRsaPrivateKey2_2048[] = {
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 };
static const unsigned char kTestRsaPublicKey2_2048[] = {
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 };
static const unsigned char kTestRsaPrivateKey3_2048[] = {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02,
0x82, 0x01, 0x01, 0x00, 0xa5, 0xd0, 0xd7, 0x3e,
0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40,
0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51,
0x3d, 0x0e, 0x83, 0xa7, 0xe0, 0xa5, 0x41, 0x04,
0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44,
0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c,
0x32, 0x3c, 0x9a, 0x91, 0x00, 0x50, 0xa8, 0x1d,
0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08,
0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78,
0xa3, 0x9d, 0x74, 0x10, 0xc6, 0x24, 0xb1, 0x7f,
0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d,
0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34,
0xbc, 0x95, 0x47, 0x94, 0x40, 0x70, 0xac, 0x99,
0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d,
0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57,
0x99, 0xee, 0x03, 0x68, 0x16, 0x31, 0xaa, 0xc3,
0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55,
0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a,
0xb6, 0xde, 0x6c, 0xe8, 0x49, 0x5d, 0xaf, 0xa8,
0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7,
0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3,
0x44, 0xab, 0xe0, 0x35, 0x52, 0x7c, 0x66, 0x85,
0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06,
0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d,
0xea, 0x70, 0x2a, 0x21, 0xe6, 0x82, 0xfd, 0xa4,
0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae,
0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf,
0x94, 0x1d, 0x87, 0x3c, 0x37, 0xc5, 0x89, 0xe8,
0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84,
0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa,
0x16, 0xa6, 0x8f, 0x87, 0x7f, 0xcb, 0xc1, 0xd6,
0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b,
0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00,
0x01, 0x02, 0x82, 0x01, 0x00, 0x43, 0x8f, 0x19,
0x83, 0xb1, 0x27, 0x4e, 0xee, 0x98, 0xba, 0xcb,
0x54, 0xa0, 0x77, 0x11, 0x6d, 0xd4, 0x25, 0x31,
0x8c, 0xb0, 0x01, 0xcf, 0xe6, 0x80, 0x83, 0x14,
0x40, 0x67, 0x39, 0x33, 0x67, 0x03, 0x1e, 0xa0,
0x8b, 0xd1, 0x1d, 0xfd, 0x80, 0xa4, 0xb9, 0xe7,
0x57, 0x5e, 0xc8, 0x8e, 0x79, 0x71, 0xd5, 0x6b,
0x09, 0xe9, 0x2b, 0x41, 0xa0, 0x33, 0x64, 0xc9,
0x66, 0x33, 0xa1, 0xb1, 0x55, 0x07, 0x55, 0x98,
0x53, 0x10, 0xe6, 0xc0, 0x39, 0x6d, 0x61, 0xd9,
0xe8, 0x16, 0x52, 0x28, 0xe4, 0x2b, 0xda, 0x27,
0x01, 0xaf, 0x21, 0x4a, 0xe8, 0x55, 0x1d, 0x0b,
0xd1, 0x1c, 0xdc, 0xfd, 0xb3, 0x0b, 0xa6, 0x5c,
0xcc, 0x6e, 0x77, 0xb8, 0xe0, 0xd1, 0x4e, 0x0a,
0xd7, 0x7a, 0x5e, 0x18, 0xc3, 0xfb, 0xe9, 0xa1,
0x9c, 0xc3, 0x9c, 0xd4, 0x4a, 0x7e, 0x70, 0x72,
0x11, 0x18, 0x24, 0x56, 0x24, 0xdf, 0xf8, 0xba,
0xac, 0x5b, 0x54, 0xd3, 0xc4, 0x65, 0x69, 0xc8,
0x79, 0x94, 0x16, 0x88, 0x9a, 0x68, 0x1c, 0xbc,
0xd4, 0xca, 0xec, 0x5e, 0x07, 0x4a, 0xc9, 0x54,
0x7a, 0x4b, 0xdb, 0x19, 0x88, 0xf6, 0xbe, 0x50,
0x9d, 0x9e, 0x9d, 0x88, 0x5b, 0x4a, 0x23, 0x86,
0x2b, 0xa9, 0xa6, 0x6c, 0x70, 0x7d, 0xe1, 0x11,
0xba, 0xbf, 0x03, 0x2e, 0xf1, 0x46, 0x7e, 0x1b,
0xed, 0x06, 0x11, 0x57, 0xad, 0x4a, 0xcb, 0xe5,
0xb1, 0x11, 0x05, 0x0a, 0x30, 0xb1, 0x73, 0x79,
0xcd, 0x7a, 0x04, 0xcc, 0x70, 0xe9, 0x95, 0xe4,
0x27, 0xc2, 0xd5, 0x2d, 0x92, 0x44, 0xdf, 0xb4,
0x94, 0xa8, 0x73, 0xa1, 0x4a, 0xc3, 0xcc, 0xc4,
0x0e, 0x8d, 0xa1, 0x6a, 0xc2, 0xd8, 0x03, 0x7f,
0xfa, 0xa7, 0x76, 0x0d, 0xad, 0x87, 0x88, 0xa0,
0x77, 0xaf, 0x3b, 0x23, 0xd1, 0x66, 0x0b, 0x31,
0x2b, 0xaf, 0xef, 0xd5, 0x41, 0x02, 0x81, 0x81,
0x00, 0xdb, 0xc1, 0xe7, 0xdd, 0xba, 0x3c, 0x1f,
0x9c, 0x64, 0xca, 0xa0, 0x63, 0xdb, 0xd2, 0x47,
0x5c, 0x6e, 0x8a, 0xa3, 0x16, 0xd5, 0xda, 0xc2,
0x25, 0x64, 0x0a, 0x02, 0xbc, 0x7d, 0x7f, 0x50,
0xab, 0xe0, 0x66, 0x03, 0x53, 0x7d, 0x77, 0x6d,
0x6c, 0x61, 0x58, 0x09, 0x73, 0xcd, 0x18, 0xe9,
0x53, 0x0b, 0x5c, 0xa2, 0x71, 0x14, 0x02, 0xfd,
0x55, 0xda, 0xe9, 0x77, 0x24, 0x7c, 0x2a, 0x4e,
0xb9, 0xd9, 0x5d, 0x58, 0xf6, 0x26, 0xd0, 0xd8,
0x3d, 0xcf, 0x8c, 0x89, 0x65, 0x6c, 0x35, 0x19,
0xb6, 0x63, 0xff, 0xa0, 0x71, 0x49, 0xcd, 0x6d,
0x5b, 0x3d, 0x8f, 0xea, 0x6f, 0xa9, 0xba, 0x43,
0xe5, 0xdd, 0x39, 0x3a, 0x78, 0x8f, 0x07, 0xb8,
0xab, 0x58, 0x07, 0xb7, 0xd2, 0xf8, 0x07, 0x02,
0x9b, 0x79, 0x26, 0x32, 0x22, 0x38, 0x91, 0x01,
0x90, 0x81, 0x29, 0x94, 0xad, 0x77, 0xeb, 0x86,
0xb9, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x29, 0x88,
0xbd, 0x96, 0x31, 0x33, 0x7b, 0x77, 0x5d, 0x32,
0x12, 0x5e, 0xdf, 0x28, 0x0c, 0x96, 0x0d, 0xa8,
0x22, 0xdf, 0xd3, 0x35, 0xd7, 0xb0, 0x41, 0xcb,
0xe7, 0x94, 0x8a, 0xa4, 0xed, 0xd2, 0xfb, 0xd2,
0xf3, 0xf2, 0x95, 0xff, 0xd8, 0x33, 0x3f, 0x8c,
0xd7, 0x65, 0xe4, 0x0c, 0xcc, 0xfe, 0x32, 0x66,
0xfa, 0x50, 0xe2, 0xcf, 0xf0, 0xbe, 0x05, 0xb1,
0xbc, 0xbe, 0x44, 0x09, 0xb4, 0xfe, 0x95, 0x06,
0x18, 0xd7, 0x59, 0xc6, 0xef, 0x2d, 0x22, 0xa0,
0x73, 0x5e, 0x77, 0xdf, 0x8d, 0x09, 0x2c, 0xb8,
0xcc, 0xeb, 0x10, 0x4d, 0xa7, 0xd0, 0x4b, 0x46,
0xba, 0x7d, 0x8b, 0x6a, 0x55, 0x47, 0x55, 0xd3,
0xd7, 0xb1, 0x88, 0xfd, 0x27, 0x3e, 0xf9, 0x5b,
0x7b, 0xae, 0x6d, 0x08, 0x9f, 0x0c, 0x2a, 0xe1,
0xdd, 0xb9, 0xe3, 0x55, 0x13, 0x55, 0xa3, 0x6d,
0x06, 0xbb, 0xe0, 0x1e, 0x55, 0x02, 0x81, 0x80,
0x61, 0x73, 0x3d, 0x64, 0xff, 0xdf, 0x05, 0x8d,
0x8e, 0xcc, 0xa4, 0x0f, 0x64, 0x3d, 0x7d, 0x53,
0xa9, 0xd9, 0x64, 0xb5, 0x0d, 0xa4, 0x72, 0x8f,
0xae, 0x2b, 0x1a, 0x47, 0x87, 0xc7, 0x5b, 0x78,
0xbc, 0x8b, 0xc0, 0x51, 0xd7, 0xc3, 0x8c, 0x0c,
0x91, 0xa6, 0x3e, 0x9a, 0xd1, 0x8a, 0x88, 0x7d,
0x40, 0xfe, 0x95, 0x32, 0x5b, 0xd3, 0x6f, 0x90,
0x11, 0x01, 0x92, 0xc9, 0xe5, 0x1d, 0xc5, 0xc7,
0x78, 0x72, 0x82, 0xae, 0xb5, 0x4b, 0xcb, 0x78,
0xad, 0x7e, 0xfe, 0xb6, 0xb1, 0x23, 0x63, 0x01,
0x94, 0x9a, 0x99, 0x05, 0x63, 0xda, 0xea, 0xf1,
0x98, 0xfd, 0x26, 0xd2, 0xd9, 0x8b, 0x35, 0xec,
0xcb, 0x0b, 0x43, 0xb8, 0x8e, 0x84, 0xb8, 0x09,
0x93, 0x81, 0xe8, 0xac, 0x6f, 0x3c, 0x7c, 0x95,
0x81, 0x45, 0xc4, 0xd9, 0x94, 0x08, 0x09, 0x8f,
0x91, 0x17, 0x65, 0x4c, 0xff, 0x6e, 0xbc, 0x51,
0x02, 0x81, 0x81, 0x00, 0xc1, 0x0d, 0x9d, 0xd8,
0xbd, 0xaf, 0x56, 0xe0, 0xe3, 0x1f, 0x85, 0xd7,
0xce, 0x72, 0x02, 0x38, 0xf2, 0x0f, 0x9c, 0x27,
0x9e, 0xc4, 0x1d, 0x60, 0x00, 0x8d, 0x02, 0x19,
0xe5, 0xdf, 0xdb, 0x8e, 0xc5, 0xfb, 0x61, 0x8e,
0xe6, 0xb8, 0xfc, 0x07, 0x3c, 0xd1, 0x1b, 0x16,
0x7c, 0x83, 0x3c, 0x37, 0xf5, 0x26, 0xb2, 0xbd,
0x22, 0xf2, 0x4d, 0x19, 0x33, 0x11, 0xc5, 0xdd,
0xf9, 0xdb, 0x4e, 0x48, 0x52, 0xd8, 0xe6, 0x4b,
0x15, 0x90, 0x68, 0xbe, 0xca, 0xc1, 0x7c, 0xd3,
0x51, 0x6b, 0x45, 0x46, 0x54, 0x11, 0x1a, 0x71,
0xd3, 0xcd, 0x6b, 0x8f, 0x79, 0x22, 0x83, 0x02,
0x08, 0x4f, 0xba, 0x6a, 0x98, 0xed, 0x32, 0xd8,
0xb4, 0x5b, 0x51, 0x88, 0x53, 0xec, 0x2c, 0x7e,
0xa4, 0x89, 0xdc, 0xbf, 0xf9, 0x0d, 0x32, 0xc8,
0xc3, 0xec, 0x6d, 0x2e, 0xf1, 0xbc, 0x70, 0x4e,
0xf6, 0x9e, 0xbc, 0x31, 0x02, 0x81, 0x81, 0x00,
0xd3, 0x35, 0x1b, 0x19, 0x75, 0x3f, 0x61, 0xf2,
0x55, 0x03, 0xce, 0x25, 0xa9, 0xdf, 0x0c, 0x0a,
0x3b, 0x47, 0x42, 0xdc, 0x38, 0x4b, 0x13, 0x4d,
0x1f, 0x86, 0x58, 0x4f, 0xd8, 0xee, 0xfa, 0x76,
0x15, 0xfb, 0x6e, 0x55, 0x31, 0xf2, 0xd2, 0x62,
0x32, 0xa5, 0xc4, 0x23, 0x5e, 0x08, 0xa9, 0x83,
0x07, 0xac, 0x8c, 0xa3, 0x7e, 0x18, 0xc0, 0x1c,
0x57, 0x63, 0x8d, 0x05, 0x17, 0x47, 0x1b, 0xd3,
0x74, 0x73, 0x20, 0x04, 0xfb, 0xc8, 0x1a, 0x43,
0x04, 0x36, 0xc8, 0x19, 0xbe, 0xdc, 0xa6, 0xe5,
0x0f, 0x25, 0x62, 0x24, 0x96, 0x92, 0xb6, 0xb3,
0x97, 0xad, 0x57, 0x9a, 0x90, 0x37, 0x4e, 0x31,
0x44, 0x74, 0xfa, 0x7c, 0xb4, 0xea, 0xfc, 0x15,
0xa7, 0xb0, 0x51, 0xcc, 0xee, 0x1e, 0xed, 0x5b,
0x98, 0x18, 0x0e, 0x65, 0xb6, 0x4b, 0x69, 0x0b,
0x21, 0xdc, 0x86, 0x17, 0x6e, 0xc8, 0xee, 0x24 };
static const unsigned char kTestRsaPublicKey3_2048[] = {
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
0x00, 0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb,
0x43, 0x51, 0x99, 0xea, 0x40, 0x1e, 0x2d, 0x89,
0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83,
0xa7, 0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5,
0xa7, 0x5c, 0x61, 0x36, 0x44, 0xb3, 0x08, 0x05,
0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a,
0x91, 0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f,
0x35, 0xb7, 0xc2, 0x75, 0x08, 0x32, 0x8b, 0x10,
0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74,
0x10, 0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f,
0xc2, 0xd7, 0x15, 0xa3, 0x1d, 0xe0, 0x15, 0x6b,
0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47,
0x94, 0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e,
0x56, 0x93, 0x36, 0x2b, 0x6d, 0x04, 0xe7, 0x95,
0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03,
0x68, 0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75,
0x53, 0xfc, 0xf6, 0x20, 0x55, 0x44, 0xf8, 0xd4,
0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c,
0xe8, 0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c,
0xe2, 0x6a, 0x4c, 0xd5, 0xe7, 0x8c, 0x8f, 0x0b,
0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0,
0x35, 0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7,
0x20, 0xec, 0x24, 0x05, 0x06, 0xd9, 0x84, 0x51,
0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a,
0x21, 0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f,
0x59, 0x6e, 0x29, 0x3d, 0xae, 0xb8, 0x8e, 0xee,
0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87,
0x3c, 0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3,
0xbc, 0xe8, 0x62, 0x6a, 0x84, 0x7f, 0xfe, 0x9a,
0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f,
0x87, 0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b,
0xa7, 0xdd, 0x49, 0x98, 0x7b, 0x6f, 0xdd, 0x69,
0x6d, 0x02, 0x03, 0x01, 0x00, 0x01 };
RsaTestKeys::RsaTestKeys() :
private_key_1_3072_bits_(kTestRsaPrivateKey1_3072, kTestRsaPrivateKey1_3072
+ sizeof(kTestRsaPrivateKey1_3072)),
public_key_1_3072_bits_(kTestRsaPublicKey1_3072, kTestRsaPublicKey1_3072
+ sizeof(kTestRsaPublicKey1_3072)),
private_key_2_2048_bits_(kTestRsaPrivateKey2_2048, kTestRsaPrivateKey2_2048
+ sizeof(kTestRsaPrivateKey2_2048)),
public_key_2_2048_bits_(kTestRsaPublicKey2_2048, kTestRsaPublicKey2_2048
+ sizeof(kTestRsaPublicKey2_2048)),
private_key_3_2048_bits_(kTestRsaPrivateKey3_2048, kTestRsaPrivateKey3_2048
+ sizeof(kTestRsaPrivateKey3_2048)),
public_key_3_2048_bits_(kTestRsaPublicKey3_2048, kTestRsaPublicKey3_2048
+ sizeof(kTestRsaPublicKey3_2048)) {
}
} // namespace widevine

64
common/rsa_test_keys.h Normal file
View File

@@ -0,0 +1,64 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA keys generated using fake_prng for purposes of testing.
#ifndef COMMON_RSA_TEST_KEYS_H_
#define COMMON_RSA_TEST_KEYS_H_
#include <string>
namespace widevine {
// Container for test RSA keys
class RsaTestKeys {
public:
RsaTestKeys();
// Returns 3072-bit private RSA test key 1
const std::string& private_test_key_1_3072_bits() const {
return private_key_1_3072_bits_;
}
// Returns 3072-bit public RSA test key 1
const std::string& public_test_key_1_3072_bits() const {
return public_key_1_3072_bits_;
}
// Returns 2048-bit private RSA test key 2
const std::string& private_test_key_2_2048_bits() const {
return private_key_2_2048_bits_;
}
// Returns 2048-bit public RSA test key 2
const std::string& public_test_key_2_2048_bits() const {
return public_key_2_2048_bits_;
}
// Returns 2048-bit private RSA test key 3
const std::string& private_test_key_3_2048_bits() const {
return private_key_3_2048_bits_;
}
// Returns 2048-bit public RSA test key 3
const std::string& public_test_key_3_2048_bits() const {
return public_key_3_2048_bits_;
}
private:
RsaTestKeys(const RsaTestKeys&) = delete;
RsaTestKeys& operator=(const RsaTestKeys&) = delete;
std::string private_key_1_3072_bits_;
std::string public_key_1_3072_bits_;
std::string private_key_2_2048_bits_;
std::string public_key_2_2048_bits_;
std::string private_key_3_2048_bits_;
std::string public_key_3_2048_bits_;
};
} // namespace widevine
#endif // COMMON_RSA_TEST_KEYS_H_

386
common/rsa_util.cc Normal file
View File

@@ -0,0 +1,386 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA utility functions for serializing and deserializing RSA keys,
// encryption, and signing.
#include "common/rsa_util.h"
#include <cstring>
#include "glog/logging.h"
#include "openssl/bio.h"
#include "openssl/evp.h"
#include "openssl/pem.h"
#include "openssl/x509.h"
namespace widevine {
namespace rsa_util {
static bool SerializeRsaKey(const RSA* key, std::string* serialized_key,
bool serialize_private_key) {
if (key == NULL) {
LOG(ERROR) << (serialize_private_key ? "Private" : "Public")
<< " RSA key is NULL.";
return false;
}
if (serialized_key == NULL) {
LOG(ERROR) << "Pointer to hold serialized RSA" << (serialize_private_key ?
"Private" : "Public") << "Key is NULL.";
return false;
}
BIO* bio = BIO_new(BIO_s_mem());
if (bio == NULL) {
LOG(ERROR) << "BIO_new returned NULL";
return false;
}
bool success = false;
if ((serialize_private_key ?
i2d_RSAPrivateKey_bio(bio, const_cast<RSA*>(key)) :
i2d_RSAPublicKey_bio(bio, const_cast<RSA*>(key))) != 0) {
int serialized_size = BIO_pending(bio);
serialized_key->assign(serialized_size, 0);
if (BIO_read(bio, &(*serialized_key)[0], serialized_size) ==
serialized_size) {
success = true;
} else {
LOG(ERROR) << "BIO_read failure";
}
} else {
LOG(ERROR) << (serialize_private_key ? "Private" : "Public") <<
" key serialization failure";
}
BIO_free(bio);
return success;
}
static bool DeserializeRsaKey(const std::string& serialized_key, RSA** key,
bool deserialize_private_key) {
if (serialized_key.empty()) {
LOG(ERROR) << "Serialized RSA" << (deserialize_private_key ?
"Private" : "Public") << "Key is empty.";
return false;
}
if (key == NULL) {
LOG(ERROR) << "Pointer to hold new RSA " << (deserialize_private_key ?
"private" : "public") << " key is NULL.";
return false;
}
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_key.data()),
serialized_key.size());
if (bio == NULL) {
LOG(ERROR) << "BIO_new_mem_buf returned NULL";
return false;
}
*key = deserialize_private_key ? d2i_RSAPrivateKey_bio(bio, NULL) :
d2i_RSAPublicKey_bio(bio, NULL);
BIO_free(bio);
if (*key == NULL) {
LOG(ERROR) << (deserialize_private_key ? "Private" : "Public") <<
" RSA key deserialization failure";
}
return *key != NULL;
}
bool SerializeRsaPrivateKey(const RSA* private_key,
std::string* serialized_private_key) {
return SerializeRsaKey(private_key, serialized_private_key, true);
}
bool DeserializeRsaPrivateKey(const std::string& serialized_private_key,
RSA** private_key) {
return DeserializeRsaKey(serialized_private_key, private_key, true);
}
bool SerializeRsaPublicKey(const RSA* public_key,
std::string* serialized_public_key) {
return SerializeRsaKey(public_key, serialized_public_key, false);
}
bool DeserializeRsaPublicKey(const std::string& serialized_public_key,
RSA** public_key) {
return DeserializeRsaKey(serialized_public_key, public_key, false);
}
bool SerializePrivateKeyInfo(const RSA* private_key,
std::string* serialized_private_key) {
if (private_key == NULL) {
LOG(ERROR) << "Private RSA key is NULL.";
return false;
}
if (serialized_private_key == NULL) {
LOG(ERROR) << "Pointer to hold serialized PrivateKeyInfo is NULL.";
return false;
}
// The following method of serializing a PKCS#8 PrivateKeyInfo object
// was obtained from analyzing the openssl utility code, as the official
// mechanism via i2d_PKCS8PrivateKey_bio is broken in the current openssl
// version (1.0.0c). Please refer to b/8560683.
EVP_PKEY* evp = EVP_PKEY_new();
if (evp == NULL) {
LOG(ERROR) << "EVP_PKEY_new returned NULL.";
return false;
}
bool success = false;
PKCS8_PRIV_KEY_INFO *pkcs8_pki = NULL;
BIO* bio = NULL;
if (EVP_PKEY_set1_RSA(evp, const_cast<RSA*>(private_key)) == 0) {
LOG(ERROR) << "EVP_PKEY_set1_RSA failed.";
goto cleanup;
}
pkcs8_pki = EVP_PKEY2PKCS8(evp);
if (pkcs8_pki == NULL) {
LOG(ERROR) << "EVP_PKEY2PKCS8 returned NULL.";
goto cleanup;
}
bio = BIO_new(BIO_s_mem());
if (bio == NULL) {
LOG(ERROR) << "BIO_new returned NULL.";
goto cleanup;
}
if (i2d_PKCS8_PRIV_KEY_INFO_bio(bio, pkcs8_pki) == 0) {
LOG(ERROR) << "i2d_PKCS8_PRIV_KEY_INFO_bio failed.";
goto cleanup;
}
{
int serialized_size = BIO_pending(bio);
serialized_private_key->assign(serialized_size, 0);
if (BIO_read(bio, &(*serialized_private_key)[0], serialized_size) !=
serialized_size) {
LOG(ERROR) << "BIO_read failed.";
goto cleanup;
}
}
success = true;
cleanup:
if (bio != NULL) {
BIO_free(bio);
}
if (pkcs8_pki != NULL) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
EVP_PKEY_free(evp);
return success;
}
bool DeserializePrivateKeyInfo(const std::string& serialized_private_key,
RSA** private_key) {
if (serialized_private_key.empty()) {
LOG(ERROR) << "Serialized PrivateKeyInfo is empty.";
return false;
}
if (private_key == NULL) {
LOG(ERROR) << "Pointer to hold new RSA private key is NULL.";
return false;
}
// The following method of deserializing a PKCS#8 PrivateKeyInfo object
// was obtained from analyzing the openssl utility code, as the official
// mechanism via d2i_PKCS8PrivateKey_bio is broken in the current openssl
// version (1.0.0c). Please refer to b/8560683.
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_private_key.data()),
serialized_private_key.size());
if (bio == NULL) {
LOG(ERROR) << "BIO_new_mem_buf returned NULL";
return false;
}
bool success = false;
EVP_PKEY* evp = NULL;
PKCS8_PRIV_KEY_INFO *pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
if (pkcs8_pki == NULL) {
LOG(ERROR) << "d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL.";
goto cleanup;
}
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == NULL) {
LOG(ERROR) << "EVP_PKCS82PKEY returned NULL.";
goto cleanup;
}
*private_key = EVP_PKEY_get1_RSA(evp);
if (*private_key == NULL) {
LOG(ERROR) << "PrivateKeyInfo did not contain an RSA key.";
goto cleanup;
}
success = true;
cleanup:
if (evp != NULL) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != NULL) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
return success;
}
bool RsaPrivateKeyToPrivateKeyInfo(const std::string& rsa_private_key,
std::string* private_key_info) {
RSA* key = NULL;
if (DeserializeRsaPrivateKey(rsa_private_key, &key)) {
bool success = SerializePrivateKeyInfo(key, private_key_info);
RSA_free(key);
return success;
}
return false;
}
bool PrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
std::string* rsa_private_key) {
RSA* key = NULL;
if (DeserializePrivateKeyInfo(private_key_info, &key)) {
bool success = SerializeRsaPrivateKey(key, rsa_private_key);
RSA_free(key);
return success;
}
return false;
}
bool SerializeEncryptedPrivateKeyInfo(const RSA* private_key,
const std::string& passphrase,
std::string* serialized_private_key) {
if (private_key == NULL) {
LOG(ERROR) << "Private RSA key is NULL.";
return false;
}
if (passphrase.empty()) {
LOG(ERROR) << "Passphrase for RSA key encryption is empty.";
return false;
}
if (serialized_private_key == NULL) {
LOG(ERROR) << "Pointer to hold serialized EncryptedPrivateKeyInfo is NULL.";
return false;
}
EVP_PKEY* evp = EVP_PKEY_new();
if (evp == NULL) {
LOG(ERROR) << "EVP_PKEY_new returned NULL.";
return false;
}
bool success = false;
BIO* bio = NULL;
if (EVP_PKEY_set1_RSA(evp, const_cast<RSA*>(private_key)) == 0) {
LOG(ERROR) << "EVP_PKEY_set1_RSA failed.";
goto cleanup;
}
bio = BIO_new(BIO_s_mem());
if (bio == NULL) {
LOG(ERROR) << "BIO_new returned NULL.";
goto cleanup;
}
if (i2d_PKCS8PrivateKey_bio(bio, evp, EVP_aes_256_cbc(),
const_cast<char*>(passphrase.data()),
passphrase.size(), NULL, NULL) == 0) {
LOG(ERROR) << "i2d_PKCS8PrivateKey_bio failed.";
goto cleanup;
}
{
int serialized_size = BIO_pending(bio);
serialized_private_key->assign(serialized_size, 0);
if (BIO_read(bio, &(*serialized_private_key)[0], serialized_size) !=
serialized_size) {
LOG(ERROR) << "BIO_read failed.";
goto cleanup;
}
}
success = true;
cleanup:
if (bio != NULL) {
BIO_free(bio);
}
EVP_PKEY_free(evp);
return success;
}
namespace {
// Password retrieval function used by DeserializeEncryptedPrivateKeyInfo below.
int get_password(char *buf, int size, int rwflag, void *u) {
CHECK(buf);
CHECK(u);
const std::string* pass(static_cast<const std::string*>(u));
if (!pass->empty() && size >= static_cast<int>(pass->size())) {
memcpy(buf, pass->data(), pass->size());
return pass->size();
}
return 0;
}
} // namespace
bool DeserializeEncryptedPrivateKeyInfo(const std::string& serialized_private_key,
const std::string& passphrase,
RSA** private_key) {
if (serialized_private_key.empty()) {
LOG(ERROR) << "Serialized RSAEncryptedPrivateKeyInfo is empty.";
return false;
}
if (passphrase.empty()) {
LOG(ERROR) << "Passphrase for RSA key decryption is empty.";
return false;
}
if (private_key == NULL) {
LOG(ERROR) << "Pointer to hold new RSA private key is NULL.";
return false;
}
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_private_key.data()),
serialized_private_key.size());
if (bio == NULL) {
LOG(ERROR) << "BIO_new_mem_buf returned NULL";
return false;
}
bool success = false;
EVP_PKEY* evp = d2i_PKCS8PrivateKey_bio(bio, NULL, get_password,
const_cast<std::string*>(&passphrase));
if (evp == NULL) {
LOG(ERROR) << "d2i_PKCS8PrivateKey_bio returned NULL.";
goto cleanup;
}
*private_key = EVP_PKEY_get1_RSA(evp);
if (*private_key == NULL) {
LOG(ERROR) << "EncryptedPrivateKeyInfo did not contain an RSA key.";
goto cleanup;
}
success = true;
cleanup:
if (evp != NULL) {
EVP_PKEY_free(evp);
}
BIO_free(bio);
return success;
}
bool RsaPrivateKeyToEncryptedPrivateKeyInfo(const std::string& rsa_private_key,
const std::string& passphrase,
std::string* private_key_info) {
RSA* key = NULL;
if (DeserializeRsaPrivateKey(rsa_private_key, &key)) {
bool success = SerializeEncryptedPrivateKeyInfo(key,
passphrase,
private_key_info);
RSA_free(key);
return success;
}
return false;
}
bool EncryptedPrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
const std::string& passphrase,
std::string* rsa_private_key) {
RSA* key = NULL;
if (DeserializeEncryptedPrivateKeyInfo(private_key_info, passphrase, &key)) {
bool success = SerializeRsaPrivateKey(key, rsa_private_key);
RSA_free(key);
return success;
}
return false;
}
} // namespace rsa_util
} // namespace widevine

153
common/rsa_util.h Normal file
View File

@@ -0,0 +1,153 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA utility functions for serializing and deserializing RSA keys,
// encryption, and signing.
#ifndef COMMON_RSA_UTIL_H_
#define COMMON_RSA_UTIL_H_
#include <string>
#include "openssl/rsa.h"
namespace widevine {
namespace rsa_util {
// Serialize RSA private key into DER encoded PKCS#1 RSAPrivateKey.
// - private_key is the RSA key to be serialized, which must not be NULL.
// - serialized_private_key is a pointer to the std::string to hold the serialized
// PKCS#1 RSAPrivateKey object. Caller retains ownership of the string. This
// parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializeRsaPrivateKey(const RSA* private_key,
std::string* serialized_private_key);
// Deserialize RSA private key from DER encoded PKCS#1 RSAPrivateKey.
// - serialized_private_key is the DER-encoded PKCS#1 RSAPrivateKey to be
// deserialized.
// - private_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializeRsaPrivateKey(const std::string& serialized_private_key,
RSA** private_key);
// Serialize RSA key into DER encoded PKCS#1 RSAPublicKey.
// - public_key is the RSA key to be serialized, which must not be NULL.
// - serialized_public_key is a pointer to the std::string to hold the serialized
// PKCS#1 RSAPublicKey object. Caller retains ownership of the string. This
// parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializeRsaPublicKey(const RSA* public_key,
std::string* serialized_public_key);
// Deserialize RSA public key from DER encoded PKCS#1 RSAPublicKey.
// - serialized_public_key is the DER-encoded PKCS#1 RSAPublicKey to be
// deserialized.
// - public_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializeRsaPublicKey(const std::string& serialized_public_key,
RSA** public_key);
// Serialize RSA private key into DER encoded PKCS#8 PrivateKeyInfo.
// - private_key is the RSA key to be serialized, which must not be NULL.
// - serialized_private_key is a pointer to the std::string to hold the serialized
// PKCS#8 PrivateKeyInfo object. Caller retains ownership of the string. This
// parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializePrivateKeyInfo(const RSA* private_key,
std::string* serialized_private_key);
// Deserialize RSA private key from DER encoded PKCS#8 PrivateKeyInfo.
// - serialized_private_key is the DER-encoded PKCS#8 PrivateKeyInfo to be
// deserialized.
// - private_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializePrivateKeyInfo(const std::string& serialized_private_key,
RSA** private_key);
// Convert DER-encoded PKCS#1 RSAPrivateKey to DER-encoded PKCS#8
// PrivateKeyInfo.
// - rsa_private_key is the PKCS#1 RSAPrivateKey to be converted.
// - private_key_info is a pointer to std::string to hold the PKCS#8 PrivateKeyInfo.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool RsaPrivateKeyToPrivateKeyInfo(const std::string& rsa_private_key,
std::string* private_key_info);
// Convert DER-encoded PKCS#8 PrivateKeyInfo to DER-encoded PKCS#1
// RSAPrivateKey.
// - private_key_info is the PKCS#8 PrivateKeyInfo to be converted.
// - rsa_private_key is a pointer to std::string to hold the PKCS#1 RSAPrivateKey.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool PrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
std::string* rsa_private_key);
// Serialize RSA private key into DER encoded PKCS#8 EncryptedPrivateKeyInfo.
// - private_key is the RSA key to be serialized, which must not be NULL.
// - passphrase is the password to use for PKCS#5 v2.0 3DES encryption.
// - serialized_private_key is a pointer to the std::string to hold the serialized
// PKCS#8 EncryptedPrivateKeyInfo object. Caller retains ownership of the
// string. This parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializeEncryptedPrivateKeyInfo(const RSA* private_key,
const std::string& passphrase,
std::string* serialized_private_key);
// Deserialize RSA private key from DER encoded PKCS#8 EncryptedPrivateKeyInfo.
// - serialized_private_key is the DER-encoded PKCS#8 EncryptedPrivateKeyInfo to
// be deserialized.
// - passphrase is the password to use for key decryption.
// - private_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializeEncryptedPrivateKeyInfo(const std::string& serialized_private_key,
const std::string& passphrase,
RSA** private_key);
// Convert DER-encoded PKCS#1 RSAPrivateKey to DER-encoded PKCS#8
// EncryptedPrivateKeyInfo.
// - rsa_private_key is the PKCS#1 RSAPrivateKey to be converted.
// - passphrase is the password to use for PKCS#5 v2.1 AES-256-CBC encryption.
// - private_key_info is a pointer to std::string to hold the PKCS#8
// EncryptedPrivateKeyInfo.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool RsaPrivateKeyToEncryptedPrivateKeyInfo(const std::string& rsa_private_key,
const std::string& passphrase,
std::string* private_key_info);
// Convert DER-encoded PKCS#8 EncryptedPrivateKeyInfo to DER-encoded PKCS#1
// RSAPrivateKey.
// - private_key_info is the PKCS#8 EncryptedPrivateKeyInfo to be converted.
// - passphrase is the password to use for key decryption.
// - rsa_private_key is a pointer to std::string to hold the PKCS#1 RSAPrivateKey.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool EncryptedPrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
const std::string& passphrase,
std::string* rsa_private_key);
} // namespace rsa_util
} // namespace widevine
#endif // COMMON_RSA_UTIL_H_

225
common/rsa_util_test.cc Normal file
View File

@@ -0,0 +1,225 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit test for rsa_util RSA utilties library.
#include "gtest/gtest.h"
#include "testing/base/public/test_utils.h"
#include "common/rsa_test_keys.h"
#include "common/rsa_util.h"
namespace widevine {
namespace rsa_util {
class RsaUtilTest : public ::testing::Test {
protected:
RsaTestKeys test_keys_;
};
TEST_F(RsaUtilTest, SerializeDeserializePrivateKey) {
RSA* private_key;
std::string serialized_private_key;
// Key 1
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_1_3072_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key));
EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_1_3072_bits());
EXPECT_EQ(RSA_check_key(private_key), 1);
RSA_free(private_key);
// Key 2
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key));
EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_2_2048_bits());
EXPECT_EQ(RSA_check_key(private_key), 1);
RSA_free(private_key);
// Key 3
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_3_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key));
EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_3_2048_bits());
EXPECT_EQ(RSA_check_key(private_key), 1);
RSA_free(private_key);
// Invalid key
EXPECT_FALSE(DeserializeRsaPrivateKey("this is a bad key", &private_key));
}
TEST_F(RsaUtilTest, SerializeDeserializePublicKey) {
RSA* public_key;
std::string serialized_public_key;
// Key 1
EXPECT_TRUE(DeserializeRsaPublicKey(
test_keys_.public_test_key_1_3072_bits(), &public_key));
ASSERT_TRUE(public_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_3072_bits());
RSA_free(public_key);
// Key 2
EXPECT_TRUE(DeserializeRsaPublicKey(
test_keys_.public_test_key_2_2048_bits(), &public_key));
ASSERT_TRUE(public_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_2_2048_bits());
RSA_free(public_key);
// Key 3
EXPECT_TRUE(DeserializeRsaPublicKey(
test_keys_.public_test_key_3_2048_bits(), &public_key));
ASSERT_TRUE(public_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_3_2048_bits());
RSA_free(public_key);
// Invalid key
EXPECT_FALSE(DeserializeRsaPublicKey("this is a bad key", &public_key));
}
TEST_F(RsaUtilTest, PublicKeyExtraction) {
RSA* private_key;
std::string serialized_public_key;
// Key 1
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_1_3072_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_3072_bits());
RSA_free(private_key);
// Key 2
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_2_2048_bits());
RSA_free(private_key);
// Key 3
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_3_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_3_2048_bits());
RSA_free(private_key);
}
TEST_F(RsaUtilTest, Pkcs8PrivateKeyInfo) {
// The PKCS#1 <-> PKCS#8 conversion routines exercise all the PKCS#8
// serialization/deserialization functionality , so we test those.
std::string serialized_pkcs8;
std::string serialized_pkcs1;
// Key 1
EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo(
test_keys_.private_test_key_1_3072_bits(), &serialized_pkcs8));
EXPECT_TRUE(PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_1_3072_bits(), serialized_pkcs1);
// Key 2
EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), &serialized_pkcs8));
EXPECT_TRUE(PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), serialized_pkcs1);
// Key 3
EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo(
test_keys_.private_test_key_3_2048_bits(), &serialized_pkcs8));
EXPECT_TRUE(PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_3_2048_bits(), serialized_pkcs1);
}
TEST_F(RsaUtilTest, Pkcs8EncryptedPrivateKeyInfo) {
// The PKCS#1 <-> PKCS#8 conversion routines exercise all the PKCS#8
// serialization/deserialization functionality , so we test those.
std::string serialized_pkcs8;
std::string serialized_pkcs1;
std::string passphrase("passphrase");
// Key 1
EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_1_3072_bits(), passphrase,
&serialized_pkcs8));
EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
passphrase,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_1_3072_bits(), serialized_pkcs1);
// Key 2
EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), passphrase,
&serialized_pkcs8));
EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
passphrase,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), serialized_pkcs1);
// Key 3
EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_3_2048_bits(), passphrase,
&serialized_pkcs8));
EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
passphrase,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_3_2048_bits(), serialized_pkcs1);
}
TEST_F(RsaUtilTest, FailOnInvalidParams) {
RSA* test_input_key = NULL;
RSA* test_output_key = NULL;
std::string test_string;
std::string pass("password");
ASSERT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &test_input_key));
ASSERT_TRUE(test_input_key != NULL);
EXPECT_FALSE(SerializeRsaPrivateKey(NULL, &test_string));
EXPECT_FALSE(SerializeRsaPrivateKey(test_input_key, NULL));
EXPECT_FALSE(SerializeRsaPublicKey(NULL, &test_string));
EXPECT_FALSE(SerializeRsaPublicKey(test_input_key, NULL));
EXPECT_FALSE(SerializePrivateKeyInfo(NULL, &test_string));
EXPECT_FALSE(SerializePrivateKeyInfo(test_input_key, NULL));
EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(NULL, pass, &test_string));
EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(test_input_key, pass, NULL));
EXPECT_FALSE(DeserializeRsaPrivateKey("", &test_output_key));
EXPECT_FALSE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), NULL));
EXPECT_FALSE(DeserializeRsaPublicKey("", &test_output_key));
EXPECT_FALSE(DeserializeRsaPublicKey(
test_keys_.public_test_key_2_2048_bits(), NULL));
EXPECT_FALSE(DeserializePrivateKeyInfo("", &test_output_key));
EXPECT_FALSE(DeserializePrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), NULL));
EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo("", pass, &test_output_key));
EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), pass, NULL));
RSA_free(test_input_key);
}
TEST_F(RsaUtilTest, Pkcs8FailOnInvalidPassword) {
RSA* test_input_key = NULL;
RSA* test_output_key = NULL;
std::string serialized_pkcs8;
std::string pass("password");
ASSERT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &test_input_key));
EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(test_input_key, "",
&serialized_pkcs8));
ASSERT_TRUE(SerializeEncryptedPrivateKeyInfo(test_input_key, pass,
&serialized_pkcs8));
EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo(serialized_pkcs8, pass + "a",
&test_output_key));
EXPECT_TRUE(DeserializeEncryptedPrivateKeyInfo(serialized_pkcs8, pass,
&test_output_key));
RSA_free(test_input_key);
RSA_free(test_output_key);
}
} // namespace rsa_util
} // namespace widevine

29
common/sha_util.cc Normal file
View File

@@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/sha_util.h"
#include "openssl/sha.h"
namespace widevine {
std::string Sha1_Hash(const std::string& message) {
return std::string(reinterpret_cast<char*>(
SHA1(reinterpret_cast<const uint8_t*>(message.data()),
message.size(), nullptr)),
SHA_DIGEST_LENGTH);
}
std::string Sha256_Hash(const std::string& message) {
return std::string(reinterpret_cast<char*>(
SHA256(reinterpret_cast<const uint8_t*>(message.data()),
message.size(), nullptr)),
SHA256_DIGEST_LENGTH);
}
} // namespace widevine

24
common/sha_util.h Normal file
View File

@@ -0,0 +1,24 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_SHA_UTIL_H_
#define COMMON_SHA_UTIL_H_
#include <string>
namespace widevine {
// Calculates SHA1 hash.
std::string Sha1_Hash(const std::string& message);
// Calculates SHA256 hash.
std::string Sha256_Hash(const std::string& message);
} // namespace widevine
#endif // COMMON_SHA_UTIL_H_

51
common/sha_util_test.cc Normal file
View File

@@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/sha_util.h"
#include "gtest/gtest.h"
namespace widevine {
TEST(ShaUtilTest, Sha1Empty) {
const uint8_t kExpected[] = {
0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)), Sha1_Hash(""));
}
TEST(ShaUtilTest, Sha256Empty) {
const uint8_t kExpected[] = {
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)), Sha256_Hash(""));
}
TEST(ShaUtilTest, Sha1) {
const uint8_t kExpected[] = {
0x5f, 0xfd, 0x3b, 0x85, 0x2c, 0xcd, 0xd4, 0x48, 0x80, 0x9a,
0xbb, 0x17, 0x2e, 0x19, 0xbb, 0xb9, 0xc0, 0x1a, 0x43, 0xa4,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha1_Hash("random std::string"));
}
TEST(ShaUtilTest, Sha256) {
const uint8_t kExpected[] = {
0xa8, 0x2a, 0xf4, 0xe9, 0x6b, 0x5b, 0x8d, 0x82, 0x5a, 0x69, 0x10,
0xb9, 0x08, 0xec, 0xcd, 0xc4, 0x40, 0x1a, 0xf1, 0xe6, 0x63, 0xdb,
0x5e, 0xdf, 0x2d, 0x7d, 0xfb, 0x71, 0x2d, 0xb9, 0x65, 0x29,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha256_Hash("random std::string"));
}
} // namespace widevine

40
example/BUILD Normal file
View File

@@ -0,0 +1,40 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
# Build file for the example code.
package(
default_visibility = ["//visibility:public"],
)
filegroup(
name = "example_data",
srcs = glob(["example_data/*"]),
)
cc_binary(
name = "provisioning_example",
srcs = ["provisioning_example.cc"],
deps = [
"//provisioning_sdk/public:libprovisioning_sdk",
],
)
cc_binary(
name = "provisioning_message_generator",
srcs = ["provisioning_message_generator.cc"],
deps = [
"//base",
"//common:aes_cbc_util",
"//common:file_util",
"//common:random_util",
"//common:rsa_key",
"//protos/public:certificate_provisioning_proto",
"//protos/public:client_identification_proto",
],
)

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
intermediate_passphrase

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
provider_passphrase

View File

@@ -0,0 +1,4 @@
Twas bryllyg, and ye slythy toves
Did gyre and gymble in ye wabe:
All mimsy were ye borogoves;
And ye mome raths outgrabe.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
service_passphrase

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,113 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include <stddef.h>
#include <stdio.h>
#include <iostream>
#include <memory>
#include <string>
#include "provisioning_sdk/public/certificate_type.h"
#include "provisioning_sdk/public/provisioning_engine.h"
#include "provisioning_sdk/public/provisioning_session.h"
#include "provisioning_sdk/public/provisioning_status.h"
using widevine::OK;
using widevine::ProvisioningEngine;
using widevine::ProvisioningSession;
using widevine::kCertTesting;
std::string GetContents(const std::string& file_name) {
if (file_name.empty()) {
std::cout << "File name is empty." << std::endl;
return "";
}
FILE* file = fopen(file_name.c_str(), "r");
if (!file) {
std::cout << "Unable to open file " << file_name << std::endl;
return "";
}
std::string contents;
const size_t kReadSize = 0x1000;
char buffer[kReadSize];
while (true) {
size_t size_read = fread(buffer, sizeof(char), kReadSize, file);
if (size_read == 0) break;
contents.append(buffer, size_read);
}
if (!feof(file)) std::cout << "Failed to read all file contents.";
fclose(file);
return contents;;
}
int main(int argc, char** argv) {
ProvisioningEngine engine;
// Call Initialize to setup the engine.
if (engine.Initialize(
kCertTesting, GetContents("example_data/service.cert"),
GetContents("example_data/service.encrypted.private"),
GetContents("example_data/service.passphrase"),
GetContents("example_data/provisioner.cert"),
GetContents("example_data/provisioner.encrypted.private"),
GetContents("example_data/provisioner.passphrase"),
GetContents("example_data/provisioner.spoid_secret")) != OK) {
std::cout << "Failed to initialize." << std::endl;
return 1;
}
// Certificate status list should be updated periodically. In this example,
// we'll just set it once. Note that in practice, the expiration should not be
// 10 years long.
if (engine.SetCertificateStatusList(
GetContents("example_data/certificate_list"),
10 * 365 * 24 * 3600 /* 10 years */) != OK) {
std::cout << "Failed to set certificate status list." << std::endl;
return 1;
}
// Before being able to process provisioning request for a specific type of
// device, we need to generate the intermediate certificate and add it to the
// engine first. This only needs to be done once for every new type of device.
const int kSystemId = 2001;
std::string certificate;
if (engine.GenerateDrmIntermediateCertificate(
kSystemId, GetContents("example_data/intermediate.public"),
&certificate) != OK) {
std::cout << "Failed to generate intermediate certificate." << std::endl;
return 1;
}
if (engine.AddDrmIntermediateCertificate(
certificate,
GetContents("example_data/intermediate.encrypted.private"),
GetContents("example_data/intermediate.passphrase")) != OK) {
std::cout << "Failed to add intermediate certificate." << std::endl;
return 1;
}
// In order to process provisioning request, we need to create a session. The
// public/private key pairs should be unique - they cannot be reused if the
// message is processed successfully; if ProcessMessage fails, they can be
// reused on another session.
std::unique_ptr<ProvisioningSession> session;
if (engine.NewProvisioningSession(GetContents("example_data/user.public"),
GetContents("example_data/user.private"),
&session) != OK) {
std::cout << "Failed to create session." << std::endl;
return 1;
}
std::string response;
bool done;
if (session->ProcessMessage(GetContents("example_data/message"), &response,
&done) != OK) {
std::cout << "Failed to process message." << std::endl;
return 1;
}
std::cout << "Message processed successfully.";
return 0;
}

View File

@@ -0,0 +1,95 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include <memory>
#include <string>
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "common/aes_cbc_util.h"
#include "common/file_util.h"
#include "common/random_util.h"
#include "common/rsa_key.h"
#include "protos/public/certificate_provisioning.pb.h"
#include "protos/public/client_identification.pb.h"
DEFINE_string(service_public_key_path, "example_data/service.public",
"Indicates the file path to service public key. If omitted, the "
"token is not encrypted.");
DEFINE_string(
certificate_path, "",
"Indicates the file path to the certificate chain. Should not be empty.");
DEFINE_string(certificate_private_key_path, "",
"Indicaets the file path to the certificate private key. Should "
"not be empty.");
DEFINE_string(
output_path, "",
"Specifies where to write the output message. Should not be empty.");
namespace widevine {
bool GenerateProvisioningMessage(const std::string& service_public_key,
const std::string& certificate,
const std::string& private_key, std::string* message) {
ClientIdentification client_id;
client_id.set_token(certificate);
client_id.set_type(ClientIdentification::OEM_DEVICE_CERTIFICATE);
ProvisioningRequest request;
if (service_public_key.empty()) {
*request.mutable_client_id() = client_id;
} else {
auto encrypted_id = request.mutable_encrypted_client_id();
CHECK(RandomBytes(16, encrypted_id->mutable_encrypted_client_id_iv()));
std::string privacy_key;
CHECK(RandomBytes(16, &privacy_key));
encrypted_id->set_encrypted_client_id(crypto_util::EncryptAesCbc(
privacy_key, encrypted_id->encrypted_client_id_iv(),
client_id.SerializeAsString()));
std::unique_ptr<RsaPublicKey> service_key(
RsaPublicKey::Create(service_public_key));
if (!service_key) return false;
CHECK(service_key->Encrypt(privacy_key,
encrypted_id->mutable_encrypted_privacy_key()));
}
CHECK(RandomBytes(4, request.mutable_nonce()));
SignedProvisioningMessage signed_message;
signed_message.set_message(request.SerializeAsString());
std::unique_ptr<RsaPrivateKey> signer(RsaPrivateKey::Create(private_key));
CHECK(signer->GenerateSignature(signed_message.message(),
signed_message.mutable_signature()));
*message = signed_message.SerializeAsString();
return true;
}
} // namespace widevine
using widevine::GetContents;
using widevine::SetContents;
using widevine::GenerateProvisioningMessage;
int main(int argc, char** argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
std::string service_public_key;
if (!FLAGS_service_public_key_path.empty()) {
if (!GetContents(FLAGS_service_public_key_path, &service_public_key))
return 1;
}
std::string certificate;
if (!GetContents(FLAGS_certificate_path, &certificate)) return 1;
std::string private_key;
if (!GetContents(FLAGS_certificate_private_key_path, &private_key)) return 1;
std::string message;
if (!GenerateProvisioningMessage(service_public_key, certificate, private_key,
&message))
return 1;
if (!SetContents(FLAGS_output_path, message)) return 1;
return 0;
}

183
glog.BUILD Normal file
View File

@@ -0,0 +1,183 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
# Bazel build file for glog.
licenses(["notice"])
# Common options required by all library targets.
glog_copts = [
"-Isrc",
"-D_START_GOOGLE_NAMESPACE_='namespace google {'",
"-D_END_GOOGLE_NAMESPACE_=}",
"-DGOOGLE_NAMESPACE=google",
"-DGOOGLE_GLOG_DLL_DECL=",
"-DHAVE_LIB_GFLAGS",
"-DHAVE_PTHREAD",
"-DHAVE_RWLOCK",
"-DHAVE_PREAD",
"-DHAVE_PWRITE",
"-DHAVE_SYS_TIME_H",
"-DHAVE_SYS_UTSNAME_H",
"-DHAVE_UNISTD_H",
"-DHAVE_GLOB_H",
"-DHAVE___ATTRIBUTE__",
"-D__NR_gettid",
"-Wno-sign-compare",
]
cc_library(
name = "glog",
srcs = [
"src/base/commandlineflags.h",
"src/base/googleinit.h",
"src/base/mutex.h",
"src/demangle.cc",
"src/demangle.h",
"src/glog/log_severity.h",
"src/logging.cc",
"src/raw_logging.cc",
"src/signalhandler.cc",
"src/stacktrace.h",
"src/stacktrace_generic-inl.h",
"src/stacktrace_libunwind-inl.h",
"src/stacktrace_powerpc-inl.h",
"src/stacktrace_x86-inl.h",
"src/stacktrace_x86_64-inl.h",
"src/symbolize.cc",
"src/symbolize.h",
"src/utilities.cc",
"src/utilities.h",
"src/vlog_is_on.cc",
":config_h",
":logging_h",
":raw_logging_h",
":stl_logging_h",
":vlog_is_on_h",
],
hdrs = glob(["glog/*.h"]),
copts = glog_copts,
includes = ["src/"],
linkopts = ["-pthread"],
visibility = ["//visibility:public"],
deps = ["//external:gflags"],
)
genrule(
name = "config_h",
srcs = ["src/config.h.cmake.in"],
outs = ["config.h"],
cmd = "awk '{ gsub(/^#cmakedefine/, \"//cmakedefine\"); print; }' $(<) > $(@)",
)
sub_cmd = ("awk '{ " +
"gsub(/@ac_google_start_namespace@/, \"namespace google {\"); " +
"gsub(/@ac_google_end_namespace@/, \"} // namespace google\"); " +
"gsub(/@ac_google_namespace@/, \"google\"); " +
("gsub(/@(ac_cv_have_stdint_h|ac_cv_have_uint16_t|" +
"ac_cv_have_libgflags|ac_cv_have_unistd_h|" +
"ac_cv_have___builtin_expect|" +
"ac_cv_cxx_using_operator)@/, \"1\"); ") +
"gsub(/@ac_cv___attribute___noreturn@/, \"__attribute__ ((noreturn))\"); " +
"gsub(/@ac_cv___attribute___noinline@/, \"__attribute__ ((noinline))\"); " +
"gsub(/@(ac_cv___attribute___[a-z0-9_]+)@/, \"\"); " +
"gsub(/@([a-z0-9_]+)@/, \"0\"); " +
"print; }' $(<) > $(@)")
genrule(
name = "logging_h",
srcs = ["src/glog/logging.h.in"],
outs = ["glog/logging.h"],
cmd = sub_cmd,
)
genrule(
name = "raw_logging_h",
srcs = ["src/glog/raw_logging.h.in"],
outs = ["glog/raw_logging.h"],
cmd = sub_cmd,
)
genrule(
name = "stl_logging_h",
srcs = ["src/glog/stl_logging.h.in"],
outs = ["glog/stl_logging.h"],
cmd = sub_cmd,
)
genrule(
name = "vlog_is_on_h",
srcs = ["src/glog/vlog_is_on.h.in"],
outs = ["glog/vlog_is_on.h"],
cmd = sub_cmd,
)
cc_library(
name = "test_hdrs",
hdrs = [
"src/config_for_unittests.h",
"src/googletest.h",
],
)
cc_test(
name = "demangle_unittest",
size = "small",
srcs = ["src/demangle_unittest.cc"],
copts = glog_copts,
data = ["src/demangle_unittest.txt"],
deps = [
":glog",
":test_hdrs",
],
)
cc_test(
name = "logging_unittest",
size = "small",
srcs = ["src/logging_unittest.cc"],
copts = glog_copts,
data = ["src/logging_unittest.err"],
deps = [
":glog",
":test_hdrs",
],
)
cc_test(
name = "stacktrace_unittest",
size = "small",
srcs = ["src/stacktrace_unittest.cc"],
copts = glog_copts,
deps = [
":glog",
":test_hdrs",
],
)
cc_test(
name = "symbolize_unittest",
size = "small",
srcs = ["src/symbolize_unittest.cc"],
copts = glog_copts,
deps = [
":glog",
":test_hdrs",
],
)
cc_test(
name = "utilities_unittest",
size = "small",
srcs = ["src/utilities_unittest.cc"],
copts = glog_copts,
deps = [
":glog",
":test_hdrs",
],
)

37
gtest.BUILD Normal file
View File

@@ -0,0 +1,37 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
cc_library(
name = "gtest",
srcs = [
"googlemock/src/gmock-all.cc",
"googletest/src/gtest-all.cc",
],
hdrs = glob([
"googlemock/**/*.h",
"googlemock/src/*.cc",
"googletest/**/*.h",
"googletest/src/*.cc",
]),
includes = [
"googlemock",
"googlemock/include",
"googletest",
"googletest/include",
],
linkopts = ["-pthread"],
visibility = ["//visibility:public"],
)
cc_library(
name = "gtest_main",
srcs = ["googlemock/src/gmock_main.cc"],
linkopts = ["-pthread"],
visibility = ["//visibility:public"],
deps = [":gtest"],
)

View File

@@ -0,0 +1,24 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
# Build file for OEM certificate generation tool.
package(default_visibility = ["//visibility:public"])
py_binary(
name = "oem_certificate",
srcs = ["oem_certificate.py"],
)
py_test(
name = "oem_certificate_test",
srcs = ["oem_certificate_test.py"],
deps = [
":oem_certificate",
],
)

View File

@@ -0,0 +1,492 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
"""OEM certificate generation tool.
Supports:
- Generating CSR (certificate signing request)
- Generating OEM intermediate certificate
- Generating OEM leaf certificate chain
- Erasing file securely
- Getting CSR/certificate/certificate chain information
Prerequirements (if running the script directly):
- Install pip: https://pip.pypa.io/en/stable/installing/
- Install python cryptography: https://cryptography.io/en/latest/installation/
Run 'python oem_certificate.py --help' to see available commands.
The arguments can be partially or fully loaded from a configuration file, for
example, if file "location.cfg" is,
-C=US
-ST=CA
-L=Kirkland
-O=Some Company
-OU=Some Unit
A command of
"python oem_certificate.py generate_csr @location.cfg "
"--output_csr_file=csr.pem --output_private_key_file=key.der",
is equivalent to
"python oem_certificate.py generate_csr -C=US -ST=CA -L=Kirkland "
"-O='Some Company' -OU='Some Unit' --output_csr_file=csr.pem "
"--output_private_key_file=key.der".
Note that (1) the arguments in the config file must be one per line; (2) the
arguments should not be quoted in the config file.
The script uses a default configuration file 'oem_certificate.cfg', which will
be loaded automatically if exists.
"""
import argparse
import datetime
import os
import sys
from cryptography import utils
from cryptography import x509
from cryptography.hazmat import backends
from cryptography.hazmat.backends import openssl
from cryptography.hazmat.backends.openssl import backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509 import oid
from pyasn1.codec.der import decoder
from pyasn1.codec.der import encoder
from pyasn1.type import univ
import six
class WidevineSystemId(x509.UnrecognizedExtension):
"""Implement WidevineSystemId x509 extension."""
# oid of Widevine system id.
oid = oid.ObjectIdentifier('1.3.6.1.4.1.11129.4.1.1')
def __init__(self, value):
"""Inits from raw bytes."""
super(WidevineSystemId, self).__init__(WidevineSystemId.oid, value)
@classmethod
def from_int_value(cls, int_value):
"""Construct from integer system id value."""
return cls(encoder.encode(univ.Integer(int_value)))
def int_value(self):
"""Return the integer value of the system id."""
return int(decoder.decode(self.value)[0])
class X509CertificateChain(object):
"""Implement x509 certificate chain object.
cryptography does not support certificate chain (pkcs7 container) right
now, so we have to implement it using low level functions directly.
"""
# Disable pylint on protected-access in class X509CertificateChain.
# pylint: disable=protected-access
def __init__(self, certificates):
"""Inits from certificate list."""
self._certificates = certificates
def __iter__(self):
"""Iterates through certificates."""
return self._certificates.__iter__()
@classmethod
def load_der(cls, certificate_chain_data):
"""Load from DER formatted data."""
bio = backend._bytes_to_bio(certificate_chain_data)
pkcs7 = backend._lib.d2i_PKCS7_bio(bio.bio, backend._ffi.NULL)
if pkcs7 == backend._ffi.NULL:
raise ValueError('Unable to load certificate chain')
pkcs7 = backend._ffi.gc(pkcs7, backend._lib.PKCS7_free)
if not backend._lib.PKCS7_type_is_signed(pkcs7):
raise ValueError('Invalid certificate chain')
x509_stack = pkcs7.d.sign.cert
certificates = []
for i in xrange(backend._lib.sk_X509_num(x509_stack)):
x509_value = backend._ffi.gc(
backend._lib.X509_dup(backend._lib.sk_X509_value(x509_stack, i)),
backend._lib.X509_free)
certificates.append(openssl.x509._Certificate(backend, x509_value))
return cls(certificates)
def der_bytes(self):
"""Return DER formatted bytes."""
x509_stack = backend._ffi.gc(backend._lib.sk_X509_new_null(),
backend._lib.sk_X509_free)
for certificate in self._certificates:
backend._lib.sk_X509_push(x509_stack, certificate._x509)
pkcs7_partial = 0x4000
p7 = backend._lib.PKCS7_sign(backend._ffi.NULL, backend._ffi.NULL,
x509_stack, backend._ffi.NULL, pkcs7_partial)
p7 = backend._ffi.gc(p7, backend._lib.PKCS7_free)
bio = backend._create_mem_bio_gc()
backend.openssl_assert(backend._lib.i2d_PKCS7_bio(bio, p7) == 1)
return backend._read_mem_bio(bio)
def _multiple_of_1024(key_size_str):
"""argparse custom type function for key size."""
key_size = int(key_size_str)
if key_size % 1024:
msg = '%r is not multiple of 1024' % key_size_str
raise argparse.ArgumentTypeError(msg)
return key_size
def _valid_date(date_str):
"""argparse custom type function dates."""
return datetime.datetime.strptime(date_str, '%Y-%m-%d')
def _get_encryption_algorithm(passphrase):
"""Convenient function to get the encryption algorithm."""
if passphrase:
return serialization.BestAvailableEncryption(passphrase)
else:
return serialization.NoEncryption()
def generate_csr(args):
"""Subparser handler for generating certificate signing request."""
key = rsa.generate_private_key(
public_exponent=65537,
key_size=args.key_size,
backend=backends.default_backend())
args.output_private_key_file.write(
key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=_get_encryption_algorithm(args.passphrase)))
csr = x509.CertificateSigningRequestBuilder().subject_name(
x509.Name([
# Provide various details about who we are.
x509.NameAttribute(oid.NameOID.COUNTRY_NAME,
six.text_type(args.country_name)),
x509.NameAttribute(oid.NameOID.STATE_OR_PROVINCE_NAME,
six.text_type(args.state_or_province_name)),
x509.NameAttribute(oid.NameOID.LOCALITY_NAME,
six.text_type(args.locality_name)),
x509.NameAttribute(oid.NameOID.ORGANIZATION_NAME,
six.text_type(args.organization_name)),
x509.NameAttribute(oid.NameOID.ORGANIZATIONAL_UNIT_NAME,
six.text_type(args.organizational_unit_name)),
])).sign(key, hashes.SHA256(), backends.default_backend())
args.output_csr_file.write(csr.public_bytes(serialization.Encoding.PEM))
def _random_serial_number():
"""Utility function to generate random serial number."""
return utils.int_from_bytes(os.urandom(16), byteorder='big')
def _build_certificate(subject_name, issuer_name, system_id, not_valid_before,
valid_duration, public_key, signing_key, ca):
"""Utility function to build certificate."""
builder = x509.CertificateBuilder()
builder = builder.subject_name(subject_name).issuer_name(issuer_name)
if ca:
builder = builder.add_extension(
x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False)
builder = builder.add_extension(
x509.AuthorityKeyIdentifier.from_issuer_public_key(
signing_key.public_key()),
critical=False)
builder = builder.add_extension(
x509.BasicConstraints(True, 0), critical=True)
if system_id:
builder = builder.add_extension(
WidevineSystemId.from_int_value(system_id), critical=False)
builder = builder.not_valid_before(not_valid_before).not_valid_after(
not_valid_before + datetime.timedelta(valid_duration)).serial_number(
_random_serial_number()).public_key(public_key)
return builder.sign(
private_key=signing_key,
algorithm=hashes.SHA256(),
backend=backends.default_backend())
def generate_intermediate_certificate(args):
"""Subparser handler for generating intermediate certificate."""
root_cert = x509.load_der_x509_certificate(args.root_certificate_file.read(),
backends.default_backend())
root_private_key = serialization.load_der_private_key(
args.root_private_key_file.read(),
password=args.root_private_key_passphrase,
backend=backends.default_backend())
if (root_private_key.public_key().public_numbers() !=
root_cert.public_key().public_numbers()):
raise ValueError('Root certificate does not match with root private key')
csr = x509.load_pem_x509_csr(args.csr_file.read(), backends.default_backend())
certificate = _build_certificate(csr.subject, root_cert.subject,
args.system_id, args.not_valid_before,
args.valid_duration,
csr.public_key(), root_private_key, True)
args.output_certificate_file.write(
certificate.public_bytes(serialization.Encoding.DER))
def generate_leaf_certificate(args):
"""Subparser handler for generating leaf certificate."""
intermediate_cert_bytes = args.intermediate_certificate_file.read()
intermediate_cert = x509.load_der_x509_certificate(intermediate_cert_bytes,
backends.default_backend())
intermediate_private_key = serialization.load_der_private_key(
args.intermediate_private_key_file.read(),
password=args.intermediate_private_key_passphrase,
backend=backends.default_backend())
if (intermediate_private_key.public_key().public_numbers() !=
intermediate_cert.public_key().public_numbers()):
raise ValueError(
'Intermediate certificate does not match with intermediate private key')
system_id_raw_bytes = intermediate_cert.extensions.get_extension_for_oid(
WidevineSystemId.oid).value.value
system_id = WidevineSystemId(system_id_raw_bytes).int_value()
name_attributes = [
x509.NameAttribute(oid.NameOID.COMMON_NAME, u'{0}-leaf'.format(system_id))
]
name_attributes.extend([
attribute for attribute in intermediate_cert.subject
if attribute.oid != oid.NameOID.COMMON_NAME
])
subject_name = x509.Name(name_attributes)
leaf_private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=args.key_size,
backend=backends.default_backend())
args.output_private_key_file.write(
leaf_private_key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=_get_encryption_algorithm(args.passphrase)))
certificate = _build_certificate(subject_name, intermediate_cert.subject,
system_id, args.not_valid_before,
args.valid_duration,
leaf_private_key.public_key(),
intermediate_private_key, False)
args.output_certificate_file.write(
X509CertificateChain([certificate, intermediate_cert]).der_bytes())
def secure_erase(args):
"""Subparser handler for secure erasing of a file."""
length = args.file.tell()
for _ in xrange(args.passes):
args.file.seek(0)
for _ in xrange(length):
args.file.write(os.urandom(1))
args.file.close()
os.remove(args.file.name)
def _certificate_as_string(cert):
"""Utility function to format certificate as string."""
lines = ['Certificate Subject Name:']
lines.extend([' {0}'.format(attribute) for attribute in cert.subject])
lines.append('Issuer Name:')
lines.extend([' {0}'.format(attribute) for attribute in cert.issuer])
lines.append('Key Size: {0.key_size}'.format(cert.public_key()))
try:
system_id_raw_bytes = cert.extensions.get_extension_for_oid(
WidevineSystemId.oid).value.value
lines.append('Widevine System Id: {0}'.format(
WidevineSystemId(system_id_raw_bytes).int_value()))
except x509.ExtensionNotFound:
pass
lines.append('Not valid before: {0.not_valid_before}'.format(cert))
lines.append('Not valid after: {0.not_valid_after}'.format(cert))
return '\n'.join(lines)
def _csr_as_string(csr):
"""Utility function to format csr as string."""
lines = ['CSR Subject Name:']
lines.extend([' {0}'.format(attribute) for attribute in csr.subject])
lines.append('Key Size: {0.key_size}'.format(csr.public_key()))
return '\n'.join(lines)
def _handle_csr(data):
"""Utility function for get_info to parse csr."""
return _csr_as_string(
x509.load_pem_x509_csr(data, backends.default_backend()))
def _handle_certificate(data):
"""Utility function for get_info to parse certificate."""
return _certificate_as_string(
x509.load_der_x509_certificate(data, backends.default_backend()))
def _handle_certificate_chain(data):
"""Utility function for get_info to parse certificate chain."""
return '\n\n'.join([
_certificate_as_string(certificate)
for certificate in X509CertificateChain.load_der(data)
])
def get_info(args, out=sys.stdout):
"""Subparser handler to get csr or certificate information."""
# The input is either a CSR or a certificate, or a certificate chain.
# Loop through the corresponding handlers one by one.
data = args.file.read()
for handler in [_handle_csr, _handle_certificate, _handle_certificate_chain]:
try:
out.write(handler(data))
return
except ValueError:
pass
print('Error occurred. The input file is not a valid CSR, nor certificate, '
'nor certificate chain.')
def create_parser():
"""Command line parsing."""
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
subparsers = parser.add_subparsers()
# Subparser for certificate signing request generation.
parser_csr = subparsers.add_parser(
'generate_csr', help='generate certificate signing request')
parser_csr.add_argument(
'--key_size',
type=_multiple_of_1024,
default=3072,
help='specify RSA key size.')
parser_csr.add_argument('-C', '--country_name', required=True)
parser_csr.add_argument('-ST', '--state_or_province_name', required=True)
parser_csr.add_argument('-L', '--locality_name', required=True)
parser_csr.add_argument('-O', '--organization_name', required=True)
parser_csr.add_argument('-OU', '--organizational_unit_name', required=True)
parser_csr.add_argument(
'--output_csr_file', type=argparse.FileType('wb'), required=True)
parser_csr.add_argument(
'--output_private_key_file', type=argparse.FileType('wb'), required=True)
parser_csr.add_argument(
'--passphrase',
help=('specify an optional passphrase to encrypt the private key. The '
'private key is not encrypted if omitted.'))
parser_csr.set_defaults(func=generate_csr)
# Subparser for intermediate certificate generation.
parser_intermediate_cert = subparsers.add_parser(
'generate_intermediate_certificate',
help=('generate intermediate certificate from csr. This should only be '
'used for testing.'))
parser_intermediate_cert.add_argument(
'--not_valid_before',
type=_valid_date,
default=datetime.datetime.today(),
help='certificate validity start date - format YYYY-MM-DD')
parser_intermediate_cert.add_argument(
'--valid_duration',
type=int,
default=3650,
help='the certificate will expire after the specified number of days.')
parser_intermediate_cert.add_argument('--system_id', type=int, required=True)
parser_intermediate_cert.add_argument(
'--csr_file', type=argparse.FileType('rb'), required=True)
parser_intermediate_cert.add_argument(
'--root_certificate_file', type=argparse.FileType('rb'), required=True)
parser_intermediate_cert.add_argument(
'--root_private_key_file', type=argparse.FileType('rb'), required=True)
parser_intermediate_cert.add_argument('--root_private_key_passphrase')
parser_intermediate_cert.add_argument(
'--output_certificate_file', type=argparse.FileType('wb'), required=True)
parser_intermediate_cert.set_defaults(func=generate_intermediate_certificate)
# Subparser for leaf certificate generation.
parser_leaf_cert = subparsers.add_parser(
'generate_leaf_certificate', help='generate leaf certificate')
parser_leaf_cert.add_argument(
'--key_size',
type=_multiple_of_1024,
default=3072,
help='specify RSA key size.')
parser_leaf_cert.add_argument(
'--not_valid_before',
type=_valid_date,
default=datetime.datetime.today(),
help='certificate validity start date - format YYYY-MM-DD')
parser_leaf_cert.add_argument(
'--valid_duration',
type=int,
default=3650,
help='the certificate will expire after the specified number of days.')
parser_leaf_cert.add_argument(
'--intermediate_certificate_file',
type=argparse.FileType('rb'),
required=True)
parser_leaf_cert.add_argument(
'--intermediate_private_key_file',
type=argparse.FileType('rb'),
required=True)
parser_leaf_cert.add_argument('--intermediate_private_key_passphrase')
parser_leaf_cert.add_argument(
'--output_certificate_file', type=argparse.FileType('wb'), required=True)
parser_leaf_cert.add_argument(
'--output_private_key_file', type=argparse.FileType('wb'), required=True)
parser_leaf_cert.add_argument(
'--passphrase',
help=('specify an optional passphrase to encrypt the private key. The '
'private key is not encrypted if omitted.'))
parser_leaf_cert.set_defaults(func=generate_leaf_certificate)
# Subparser for secure file erase.
parser_erase = subparsers.add_parser('erase', help='erase a file securely')
parser_erase.add_argument(
'-F', '--file', type=argparse.FileType('a'), required=True)
parser_erase.add_argument(
'--passes',
type=int,
default=3,
help=('the file will be overwritten with random patterns for the '
'specified number of passes'))
parser_erase.set_defaults(func=secure_erase)
# Subparser to get CSR or certificate or certificate chain metadata.
parser_info = subparsers.add_parser(
'info', help='get CSR or certificate metadata')
parser_info.add_argument(
'-F', '--file', type=argparse.FileType('rb'), required=True)
parser_info.set_defaults(func=get_info)
return parser
def main():
args = sys.argv[1:]
config_file_name = 'oem_certificate.cfg'
if os.path.isfile(config_file_name):
print 'Load from args default configuration file: ', config_file_name
args.append('@' + config_file_name)
parser_args = create_parser().parse_args(args)
parser_args.func(parser_args)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,538 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
import datetime
import os
import shutil
import StringIO
import tempfile
import textwrap
import unittest
from cryptography import x509
from cryptography.hazmat import backends
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509 import oid
import oem_certificate
class ArgParseObject(object):
"""A convenient object to allow adding arbitrary attribute to it."""
pass
class OemCertificateTest(unittest.TestCase):
def _setup_csr_args(self, key_size=4096, passphrase=None):
args = ArgParseObject()
args.key_size = key_size
args.country_name = 'US'
args.state_or_province_name = 'WA'
args.locality_name = 'Kirkland'
args.organization_name = 'CompanyXYZ'
args.organizational_unit_name = 'ContentProtection'
args.output_csr_file = StringIO.StringIO()
args.output_private_key_file = StringIO.StringIO()
args.passphrase = passphrase
return args
def test_widevine_system_id(self):
system_id = 1234567890123
self.assertEqual(
oem_certificate.WidevineSystemId.from_int_value(system_id).int_value(),
system_id)
def test_generate_csr(self):
args = self._setup_csr_args()
oem_certificate.generate_csr(args)
# Verify CSR.
csr = x509.load_pem_x509_csr(args.output_csr_file.getvalue(),
backends.default_backend())
subject = csr.subject
self.assertEqual(
subject.get_attributes_for_oid(oid.NameOID.COUNTRY_NAME)[0].value,
args.country_name)
self.assertEqual(
subject.get_attributes_for_oid(oid.NameOID.STATE_OR_PROVINCE_NAME)[0]
.value, args.state_or_province_name)
self.assertEqual(
subject.get_attributes_for_oid(oid.NameOID.LOCALITY_NAME)[0].value,
args.locality_name)
self.assertEqual(
subject.get_attributes_for_oid(oid.NameOID.ORGANIZATION_NAME)[0].value,
args.organization_name)
self.assertEqual(
subject.get_attributes_for_oid(oid.NameOID.ORGANIZATIONAL_UNIT_NAME)[0]
.value, args.organizational_unit_name)
private_key = serialization.load_der_private_key(
args.output_private_key_file.getvalue(),
args.passphrase,
backend=backends.default_backend())
self.assertEqual(private_key.key_size, args.key_size)
self.assertEqual(csr.public_key().key_size, args.key_size)
# Verify csr and private key match.
self.assertEqual(csr.public_key().public_numbers(),
private_key.public_key().public_numbers())
def test_generate_csr_with_keysize4096_and_passphrase(self):
args = self._setup_csr_args(key_size=4096, passphrase='passphrase_4096')
oem_certificate.generate_csr(args)
private_key = serialization.load_der_private_key(
args.output_private_key_file.getvalue(),
'passphrase_4096',
backend=backends.default_backend())
csr = x509.load_pem_x509_csr(args.output_csr_file.getvalue(),
backends.default_backend())
self.assertEqual(private_key.key_size, 4096)
self.assertEqual(csr.public_key().key_size, 4096)
# Verify csr and private key match.
self.assertEqual(csr.public_key().public_numbers(),
private_key.public_key().public_numbers())
def _create_root_certificate_and_key(self):
key = rsa.generate_private_key(
public_exponent=65537,
key_size=3072,
backend=backends.default_backend())
subject_name = x509.Name(
[x509.NameAttribute(oid.NameOID.COMMON_NAME, u'root_cert')])
certificate = oem_certificate._build_certificate(
subject_name, subject_name, None,
datetime.datetime(2001, 8, 9), 1000, key.public_key(), key, True)
return (key, certificate)
def _setup_intermediate_cert_args(self, csr_bytes, root_key,
root_certificate):
args = ArgParseObject()
args.not_valid_before = datetime.datetime(2001, 8, 9)
args.valid_duration = 100
args.system_id = 1234554321
args.csr_file = StringIO.StringIO(csr_bytes)
args.root_private_key_passphrase = 'root_passphrase'
args.output_certificate_file = StringIO.StringIO()
serialized_private_key = root_key.private_bytes(
serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(
args.root_private_key_passphrase))
serialized_certificate = root_certificate.public_bytes(
serialization.Encoding.DER)
args.root_certificate_file = StringIO.StringIO(serialized_certificate)
args.root_private_key_file = StringIO.StringIO(serialized_private_key)
return args
def test_generate_intermediate_certificate(self):
csr_args = self._setup_csr_args()
oem_certificate.generate_csr(csr_args)
csr_bytes = csr_args.output_csr_file.getvalue()
csr = x509.load_pem_x509_csr(csr_bytes, backends.default_backend())
root_key, root_certificate = self._create_root_certificate_and_key()
args = self._setup_intermediate_cert_args(csr_bytes, root_key,
root_certificate)
oem_certificate.generate_intermediate_certificate(args)
cert = x509.load_der_x509_certificate(
args.output_certificate_file.getvalue(), backends.default_backend())
self.assertEqual(cert.issuer, root_certificate.subject)
self.assertEqual(cert.subject, csr.subject)
system_id_raw_bytes = cert.extensions.get_extension_for_oid(
oem_certificate.WidevineSystemId.oid).value.value
self.assertEqual(
oem_certificate.WidevineSystemId(system_id_raw_bytes).int_value(),
args.system_id)
self.assertEqual(cert.not_valid_before, datetime.datetime(2001, 8, 9))
self.assertEqual(cert.not_valid_after, datetime.datetime(2001, 11, 17))
root_key.public_key().verify(cert.signature, cert.tbs_certificate_bytes,
padding.PKCS1v15(),
cert.signature_hash_algorithm)
def test_generate_intermediate_with_cert_mismatch_root_cert_and_key(self):
root_key1, _ = self._create_root_certificate_and_key()
_, root_certificate2 = self._create_root_certificate_and_key()
args = self._setup_intermediate_cert_args('some csr data', root_key1,
root_certificate2)
with self.assertRaises(ValueError) as context:
oem_certificate.generate_intermediate_certificate(args)
self.assertTrue('certificate does not match' in str(context.exception))
def _setup_leaf_cert_args(self,
intermediate_key_bytes,
intermediate_certificate_bytes,
key_size=1024,
passphrase=None):
args = ArgParseObject()
args.key_size = key_size
args.not_valid_before = datetime.datetime(2001, 8, 9)
args.valid_duration = 8000
args.intermediate_private_key_passphrase = None
args.output_certificate_file = StringIO.StringIO()
args.output_private_key_file = StringIO.StringIO()
args.passphrase = passphrase
args.intermediate_private_key_file = StringIO.StringIO(
intermediate_key_bytes)
args.intermediate_certificate_file = StringIO.StringIO(
intermediate_certificate_bytes)
return args
def _create_intermediate_certificate_and_key_bytes(self,
key_size=4096,
passphrase=None):
csr_args = self._setup_csr_args(key_size, passphrase)
oem_certificate.generate_csr(csr_args)
csr_bytes = csr_args.output_csr_file.getvalue()
root_key, root_certificate = self._create_root_certificate_and_key()
args = self._setup_intermediate_cert_args(csr_bytes, root_key,
root_certificate)
oem_certificate.generate_intermediate_certificate(args)
return (csr_args.output_private_key_file.getvalue(),
args.output_certificate_file.getvalue())
def test_generate_leaf_certificate(self):
intermediate_key_bytes, intermediate_certificate_bytes = (
self._create_intermediate_certificate_and_key_bytes())
args = self._setup_leaf_cert_args(intermediate_key_bytes,
intermediate_certificate_bytes)
oem_certificate.generate_leaf_certificate(args)
certificate_chain = oem_certificate.X509CertificateChain.load_der(
args.output_certificate_file.getvalue())
certificates = list(certificate_chain)
self.assertEqual(len(certificates), 2)
intermediate_cert = certificates[1]
leaf_cert = certificates[0]
self.assertEqual(
intermediate_cert.public_bytes(serialization.Encoding.DER),
intermediate_certificate_bytes)
intermediate_cert.public_key().verify(leaf_cert.signature,
leaf_cert.tbs_certificate_bytes,
padding.PKCS1v15(),
leaf_cert.signature_hash_algorithm)
self.assertEqual(leaf_cert.not_valid_before, datetime.datetime(2001, 8, 9))
self.assertEqual(leaf_cert.not_valid_after, datetime.datetime(2023, 7, 5))
system_id_raw_bytes = leaf_cert.extensions.get_extension_for_oid(
oem_certificate.WidevineSystemId.oid).value.value
self.assertEqual(
oem_certificate.WidevineSystemId(system_id_raw_bytes).int_value(),
1234554321)
leaf_key = serialization.load_der_private_key(
args.output_private_key_file.getvalue(),
args.passphrase,
backend=backends.default_backend())
self.assertEqual(leaf_key.key_size, args.key_size)
self.assertEqual(leaf_cert.public_key().key_size, args.key_size)
# Verify cert and private key match.
self.assertEqual(leaf_cert.public_key().public_numbers(),
leaf_key.public_key().public_numbers())
def test_generate_leaf_certificate_with_keysize4096_and_passphrase(self):
intermediate_key_bytes, intermediate_certificate_bytes = (
self._create_intermediate_certificate_and_key_bytes())
args = self._setup_leaf_cert_args(
intermediate_key_bytes,
intermediate_certificate_bytes,
key_size=4096,
passphrase='leaf passphrase')
oem_certificate.generate_leaf_certificate(args)
serialization.load_der_private_key(
args.output_private_key_file.getvalue(),
'leaf passphrase',
backend=backends.default_backend())
self.assertEqual(4096, args.key_size)
def test_get_csr_info(self):
args = self._setup_csr_args()
oem_certificate.generate_csr(args)
args.file = StringIO.StringIO(args.output_csr_file.getvalue())
output = StringIO.StringIO()
oem_certificate.get_info(args, output)
expected_info = """\
CSR Subject Name:
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.6, name=countryName)>, value=u'US')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.8, name=stateOrProvinceName)>, value=u'WA')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.7, name=localityName)>, value=u'Kirkland')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.10, name=organizationName)>, value=u'CompanyXYZ')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.11, name=organizationalUnitName)>, value=u'ContentProtection')>
Key Size: 4096"""
self.assertEqual(output.getvalue(), textwrap.dedent(expected_info))
def test_get_certificate_info(self):
_, intermediate_certificate_bytes = (
self._create_intermediate_certificate_and_key_bytes())
args = ArgParseObject()
args.file = StringIO.StringIO(intermediate_certificate_bytes)
output = StringIO.StringIO()
oem_certificate.get_info(args, output)
expected_info = """\
Certificate Subject Name:
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.6, name=countryName)>, value=u'US')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.8, name=stateOrProvinceName)>, value=u'WA')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.7, name=localityName)>, value=u'Kirkland')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.10, name=organizationName)>, value=u'CompanyXYZ')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.11, name=organizationalUnitName)>, value=u'ContentProtection')>
Issuer Name:
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'root_cert')>
Key Size: 4096
Widevine System Id: 1234554321
Not valid before: 2001-08-09 00:00:00
Not valid after: 2001-11-17 00:00:00"""
self.assertEqual(output.getvalue(), textwrap.dedent(expected_info))
def test_get_certificate_chain_info(self):
intermediate_key_bytes, intermediate_certificate_bytes = (
self._create_intermediate_certificate_and_key_bytes())
args = self._setup_leaf_cert_args(intermediate_key_bytes,
intermediate_certificate_bytes)
oem_certificate.generate_leaf_certificate(args)
args.file = StringIO.StringIO(args.output_certificate_file.getvalue())
output = StringIO.StringIO()
oem_certificate.get_info(args, output)
expected_info = """\
Certificate Subject Name:
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'1234554321-leaf')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.6, name=countryName)>, value=u'US')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.8, name=stateOrProvinceName)>, value=u'WA')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.7, name=localityName)>, value=u'Kirkland')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.10, name=organizationName)>, value=u'CompanyXYZ')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.11, name=organizationalUnitName)>, value=u'ContentProtection')>
Issuer Name:
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.6, name=countryName)>, value=u'US')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.8, name=stateOrProvinceName)>, value=u'WA')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.7, name=localityName)>, value=u'Kirkland')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.10, name=organizationName)>, value=u'CompanyXYZ')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.11, name=organizationalUnitName)>, value=u'ContentProtection')>
Key Size: 1024
Widevine System Id: 1234554321
Not valid before: 2001-08-09 00:00:00
Not valid after: 2023-07-05 00:00:00
Certificate Subject Name:
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.6, name=countryName)>, value=u'US')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.8, name=stateOrProvinceName)>, value=u'WA')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.7, name=localityName)>, value=u'Kirkland')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.10, name=organizationName)>, value=u'CompanyXYZ')>
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.11, name=organizationalUnitName)>, value=u'ContentProtection')>
Issuer Name:
<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=u'root_cert')>
Key Size: 4096
Widevine System Id: 1234554321
Not valid before: 2001-08-09 00:00:00
Not valid after: 2001-11-17 00:00:00"""
self.assertEqual(output.getvalue(), textwrap.dedent(expected_info))
def test_secure_erase(self):
args = ArgParseObject()
args.file = tempfile.NamedTemporaryFile(delete=False)
args.passes = 2
self.assertTrue(os.path.exists(args.file.name))
oem_certificate.secure_erase(args)
self.assertFalse(os.path.exists(args.file.name))
class OemCertificateArgParseTest(unittest.TestCase):
def setUp(self):
self.parser = oem_certificate.create_parser()
self.test_dir = tempfile.mkdtemp()
def tearDown(self):
shutil.rmtree(self.test_dir)
def test_generate_csr(self):
cmds = ('generate_csr --key_size 4096 -C USA -ST WA '
'-L Kirkland -O Company -OU Widevine').split()
output_private_key_file = os.path.join(self.test_dir, 'private_key')
output_csr_file = os.path.join(self.test_dir, 'csr')
cmds.extend([
'--output_csr_file', output_csr_file, '--output_private_key_file',
output_private_key_file, '--passphrase', 'pass'
])
args = self.parser.parse_args(cmds)
self.assertEqual(args.key_size, 4096)
self.assertEqual(args.country_name, 'USA')
self.assertEqual(args.state_or_province_name, 'WA')
self.assertEqual(args.locality_name, 'Kirkland')
self.assertEqual(args.organization_name, 'Company')
self.assertEqual(args.organizational_unit_name, 'Widevine')
self.assertEqual(args.output_csr_file.name, output_csr_file)
self.assertEqual(args.output_csr_file.mode, 'wb')
self.assertEqual(args.output_private_key_file.name, output_private_key_file)
self.assertEqual(args.output_private_key_file.mode, 'wb')
self.assertEqual(args.passphrase, 'pass')
self.assertEqual(args.func, oem_certificate.generate_csr)
def _fill_file_with_dummy_contents(self, file_name):
with open(file_name, 'wb') as f:
f.write('dummy')
def test_generate_csr_invalid_key_size(self):
cmds = ('generate_csr --key_size unknown -C USA -ST WA '
'-L Kirkland -O Company -OU Widevine').split()
output_private_key_file = os.path.join(self.test_dir, 'private_key')
output_csr_file = os.path.join(self.test_dir, 'csr')
cmds.extend([
'--output_csr_file', output_csr_file, '--output_private_key_file',
output_private_key_file, '--passphrase', 'pass'
])
with self.assertRaises(SystemExit) as context:
self.parser.parse_args(cmds)
self.assertEqual(context.exception.code, 2)
def test_generate_intermediate_cert(self):
cmds = (
'generate_intermediate_certificate --valid_duration 10 --system_id 100'
).split()
csr_file = os.path.join(self.test_dir, 'csr')
self._fill_file_with_dummy_contents(csr_file)
root_certificate_file = os.path.join(self.test_dir, 'root_cert')
self._fill_file_with_dummy_contents(root_certificate_file)
root_private_key_file = os.path.join(self.test_dir, 'root_private_key')
self._fill_file_with_dummy_contents(root_private_key_file)
output_certificate_file = os.path.join(self.test_dir, 'cert')
cmds.extend([
'--csr_file', csr_file, '--root_certificate_file',
root_certificate_file, '--root_private_key_file', root_private_key_file,
'--root_private_key_passphrase', 'root_key',
'--output_certificate_file', output_certificate_file
])
args = self.parser.parse_args(cmds)
self.assertAlmostEqual(
args.not_valid_before,
datetime.datetime.today(),
delta=datetime.timedelta(seconds=60))
self.assertEqual(args.valid_duration, 10)
self.assertEqual(args.system_id, 100)
self.assertEqual(args.csr_file.name, csr_file)
self.assertEqual(args.csr_file.mode, 'rb')
self.assertEqual(args.root_certificate_file.name, root_certificate_file)
self.assertEqual(args.root_certificate_file.mode, 'rb')
self.assertEqual(args.root_private_key_file.name, root_private_key_file)
self.assertEqual(args.root_private_key_file.mode, 'rb')
self.assertEqual(args.root_private_key_passphrase, 'root_key')
self.assertEqual(args.output_certificate_file.name, output_certificate_file)
self.assertEqual(args.output_certificate_file.mode, 'wb')
self.assertEqual(args.func,
oem_certificate.generate_intermediate_certificate)
def test_generate_leaf_cert(self):
cmds = ('generate_leaf_certificate --not_valid_before 2016-01-02 '
'--valid_duration 10').split()
intermediate_certificate_file = os.path.join(self.test_dir,
'intermediate_cert')
self._fill_file_with_dummy_contents(intermediate_certificate_file)
intermediate_private_key_file = os.path.join(self.test_dir,
'intermediate_private_key')
self._fill_file_with_dummy_contents(intermediate_private_key_file)
output_certificate_file = os.path.join(self.test_dir, 'cert')
output_private_key_file = os.path.join(self.test_dir, 'key')
cmds.extend([
'--intermediate_certificate_file', intermediate_certificate_file,
'--intermediate_private_key_file', intermediate_private_key_file,
'--intermediate_private_key_passphrase', 'intermediate_key',
'--output_certificate_file', output_certificate_file,
'--output_private_key_file', output_private_key_file, '--passphrase',
'leaf_key'
])
args = self.parser.parse_args(cmds)
self.assertEqual(args.not_valid_before, datetime.datetime(2016, 1, 2))
self.assertEqual(args.valid_duration, 10)
self.assertEqual(args.intermediate_certificate_file.name,
intermediate_certificate_file)
self.assertEqual(args.intermediate_certificate_file.mode, 'rb')
self.assertEqual(args.intermediate_private_key_file.name,
intermediate_private_key_file)
self.assertEqual(args.intermediate_private_key_file.mode, 'rb')
self.assertEqual(args.intermediate_private_key_passphrase,
'intermediate_key')
self.assertEqual(args.output_certificate_file.name, output_certificate_file)
self.assertEqual(args.output_certificate_file.mode, 'wb')
self.assertEqual(args.output_private_key_file.name, output_private_key_file)
self.assertEqual(args.output_private_key_file.mode, 'wb')
self.assertEqual(args.passphrase, 'leaf_key')
self.assertEqual(args.func, oem_certificate.generate_leaf_certificate)
def test_generate_leaf_cert_invalid_date(self):
cmds = ('generate_leaf_certificate --not_valid_before invaid-date '
'--valid_duration 10').split()
intermediate_certificate_file = os.path.join(self.test_dir,
'intermediate_cert')
self._fill_file_with_dummy_contents(intermediate_certificate_file)
intermediate_private_key_file = os.path.join(self.test_dir,
'intermediate_private_key')
self._fill_file_with_dummy_contents(intermediate_private_key_file)
output_certificate_file = os.path.join(self.test_dir, 'cert')
output_private_key_file = os.path.join(self.test_dir, 'key')
cmds.extend([
'--intermediate_certificate_file', intermediate_certificate_file,
'--intermediate_private_key_file', intermediate_private_key_file,
'--intermediate_private_key_passphrase', 'intermediate_key',
'--output_certificate_file', output_certificate_file,
'--output_private_key_file', output_private_key_file, '--passphrase',
'leaf_key'
])
with self.assertRaises(SystemExit) as context:
self.parser.parse_args(cmds)
self.assertEqual(context.exception.code, 2)
def test_secure_erase(self):
file_path = os.path.join(self.test_dir, 'file')
self._fill_file_with_dummy_contents(file_path)
cmds = ['erase', '-F', file_path, '--passes', '2']
args = self.parser.parse_args(cmds)
self.assertEqual(args.passes, 2)
self.assertEqual(args.file.name, file_path)
self.assertEqual(args.file.mode, 'a')
self.assertEqual(args.func, oem_certificate.secure_erase)
def test_get_info(self):
file_path = os.path.join(self.test_dir, 'file')
self._fill_file_with_dummy_contents(file_path)
cmds = ['info', '-F', file_path]
args = self.parser.parse_args(cmds)
self.assertEqual(args.file.name, file_path)
self.assertEqual(args.file.mode, 'rb')
self.assertEqual(args.func, oem_certificate.get_info)
def test_arbitrary_commands(self):
with self.assertRaises(SystemExit) as context:
self.parser.parse_args(['unsupport', '--commands'])
self.assertEqual(context.exception.code, 2)
def test_no_argument(self):
with self.assertRaises(SystemExit) as context:
self.parser.parse_args([])
self.assertEqual(context.exception.code, 2)
if __name__ == '__main__':
unittest.main()

89
protos/public/BUILD Normal file
View File

@@ -0,0 +1,89 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
#
# Description:
# Public protocol buffer definitions for Widevine Services.
package(default_visibility = ["//visibility:public"])
load("@protobuf_repo//:protobuf.bzl", "cc_proto_library", "py_proto_library")
cc_proto_library(
name = "certificate_provisioning_proto",
srcs = ["certificate_provisioning.proto"],
default_runtime = "@protobuf_repo//:protobuf",
protoc = "@protobuf_repo//:protoc",
deps = [":client_identification_proto"],
)
py_proto_library(
name = "certificate_provisioning_py_pb2",
srcs = ["certificate_provisioning.proto"],
default_runtime = "@protobuf_repo//:protobuf_python",
protoc = "@protobuf_repo//:protoc",
deps = [":client_identification_py_pb2"],
)
cc_proto_library(
name = "client_identification_proto",
srcs = ["client_identification.proto"],
default_runtime = "@protobuf_repo//:protobuf",
protoc = "@protobuf_repo//:protoc",
)
py_proto_library(
name = "client_identification_py_pb2",
srcs = ["client_identification.proto"],
default_runtime = "@protobuf_repo//:protobuf_python",
protoc = "@protobuf_repo//:protoc",
)
cc_proto_library(
name = "device_certificate_proto",
srcs = ["device_certificate.proto"],
default_runtime = "@protobuf_repo//:protobuf",
protoc = "@protobuf_repo//:protoc",
deps = [":provisioned_device_info_proto"],
)
py_proto_library(
name = "device_certificate_py_pb2",
srcs = ["device_certificate.proto"],
default_runtime = "@protobuf_repo//:protobuf_python",
protoc = "@protobuf_repo//:protoc",
deps = [":provisioned_device_info_py_pb2"],
)
cc_proto_library(
name = "signed_device_certificate_proto",
srcs = ["signed_device_certificate.proto"],
default_runtime = "@protobuf_repo//:protobuf",
protoc = "@protobuf_repo//:protoc",
)
py_proto_library(
name = "signed_device_certificate_py_pb2",
srcs = ["signed_device_certificate.proto"],
default_runtime = "@protobuf_repo//:protobuf_python",
protoc = "@protobuf_repo//:protoc",
)
cc_proto_library(
name = "provisioned_device_info_proto",
srcs = ["provisioned_device_info.proto"],
default_runtime = "@protobuf_repo//:protobuf",
protoc = "@protobuf_repo//:protoc",
)
py_proto_library(
name = "provisioned_device_info_py_pb2",
srcs = ["provisioned_device_info.proto"],
default_runtime = "@protobuf_repo//:protobuf_python",
protoc = "@protobuf_repo//:protoc",
)

View File

@@ -0,0 +1,98 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Public protocol buffer definitions for Widevine Device Certificate
// Provisioning protocol.
syntax = "proto2";
package widevine;
option java_package = "com.google.video.widevine.protos";
import "protos/public/client_identification.proto";
// ProvisioningOptions specifies the type of certificate to specify and
// in the case of X509 certificates, the certificate authority to use.
message ProvisioningOptions {
enum CertificateType {
WIDEVINE_DRM = 0; // Default. The original certificate type.
X509 = 1; // X.509 certificate.
}
optional CertificateType certificate_type = 1 [default = WIDEVINE_DRM];
// Contains the application-specific name used to identify the certificate
// authority for signing the generated certificate. This is required iff the
// certificate type is X509.
optional string certificate_authority = 2;
}
// Provisioning request sent by client devices to provisioning service.
message ProvisioningRequest {
oneof clear_or_encrypted_client_id {
// Device root of trust and other client identification. Required.
ClientIdentification client_id = 1;
EncryptedClientIdentification encrypted_client_id = 5;
}
// Nonce value used to prevent replay attacks. Required.
optional bytes nonce = 2;
// Options for type of certificate to generate. Optional.
optional ProvisioningOptions options = 3;
oneof spoid_param {
// Stable identifier, unique for each device + application (or origin).
// To be deprecated.
bytes stable_id = 4;
// Service provider ID from the service certificate's provider_id field.
// Preferred parameter.
bytes provider_id = 6;
// Client-generated stable per-origin identifier to be copied directly
// to the client certificate serial number.
bytes spoid = 7;
}
}
// Provisioning response sent by the provisioning server to client devices.
// This message is used for both regular Widevine DRM certificates and for
// application-specific X.509 certificates.
message ProvisioningResponse {
// AES-128 encrypted device private RSA key. PKCS#1 ASN.1 DER-encoded.
// Required. For X.509 certificates, the private RSA key may also include
// a prefix as specified by private_key_prefix in the X509CertificateMetadata
// proto message.
optional bytes device_rsa_key = 1;
// Initialization vector used to encrypt device_rsa_key. Required.
optional bytes device_rsa_key_iv = 2;
// For Widevine DRM certificates, this contains the serialized
// SignedDrmDeviceCertificate. For X.509 certificates, this contains the PEM
// encoded X.509 certificate. Required.
optional bytes device_certificate = 3;
// Nonce value matching nonce in ProvisioningRequest. Required.
optional bytes nonce = 4;
// Key used to wrap device_rsa_key when DRM provisioning an OEM factory
// provisioned device. Encrypted with the device OEM public key using
// RSA-OAEP.
optional bytes wrapping_key = 5;
}
// Serialized ProvisioningRequest or ProvisioningResponse signed with
// The message authentication key.
message SignedProvisioningMessage {
enum ProtocolVersion {
VERSION_2 = 2; // Keybox factory-provisioned devices.
VERSION_3 = 3; // OEM certificate factory-provisioned devices.
}
// Serialized ProvisioningRequest or ProvisioningResponse. Required.
optional bytes message = 1;
// HMAC-SHA256 (Keybox) or RSASSA-PSS (OEM) signature of message. Required.
optional bytes signature = 2;
// Version number of provisioning protocol.
optional ProtocolVersion protocol_version = 3 [default = VERSION_2];
}

View File

@@ -0,0 +1,101 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// ClientIdentification messages used by provisioning and license protocols.
syntax = "proto2";
package widevine;
option java_package = "com.google.video.widevine.protos";
option java_outer_classname = "ClientIdentificationProtos";
// ClientIdentification message used to authenticate the client device.
message ClientIdentification {
enum TokenType {
KEYBOX = 0;
DRM_DEVICE_CERTIFICATE = 1;
REMOTE_ATTESTATION_CERTIFICATE = 2;
OEM_DEVICE_CERTIFICATE = 3;
}
message NameValue {
optional string name = 1;
optional string value = 2;
}
// Capabilities which not all clients may support. Used for the license
// exchange protocol only.
message ClientCapabilities {
enum HdcpVersion {
HDCP_NONE = 0;
HDCP_V1 = 1;
HDCP_V2 = 2;
HDCP_V2_1 = 3;
HDCP_V2_2 = 4;
HDCP_NO_DIGITAL_OUTPUT = 0xff;
}
enum CertificateKeyType {
RSA_2048 = 0;
RSA_3072 = 1;
}
optional bool client_token = 1 [default = false];
optional bool session_token = 2 [default = false];
optional bool video_resolution_constraints = 3 [default = false];
optional HdcpVersion max_hdcp_version = 4 [default = HDCP_NONE];
optional uint32 oem_crypto_api_version = 5;
// Client has hardware support for protecting the usage table, such as
// storing the generation number in secure memory. For Details, see:
// https://docs.google.com/document/d/1Mm8oB51SYAgry62mEuh_2OEkabikBiS61kN7HsDnh9Y/edit#heading=h.xgjl2srtytjt
optional bool anti_rollback_usage_table = 6 [default = false];
// The client shall report |srm_version| if available.
optional uint32 srm_version = 7;
// A device may have SRM data, and report a version, but may not be capable
// of updating SRM data.
optional bool can_update_srm = 8 [default = false];
repeated CertificateKeyType supported_certificate_key_type = 9;
}
// Type of factory-provisioned device root of trust. Optional.
optional TokenType type = 1 [default = KEYBOX];
// Factory-provisioned device root of trust. Required.
optional bytes token = 2;
// Optional client information name/value pairs.
repeated NameValue client_info = 3;
// Client token generated by the content provider. Optional.
optional bytes provider_client_token = 4;
// Number of licenses received by the client to which the token above belongs.
// Only present if client_token is specified.
optional uint32 license_counter = 5;
// List of non-baseline client capabilities.
optional ClientCapabilities client_capabilities = 6;
// Serialized VmpData message. Optional.
optional bytes vmp_data = 7;
}
// EncryptedClientIdentification message used to hold ClientIdentification
// messages encrypted for privacy purposes.
message EncryptedClientIdentification {
// Provider ID for which the ClientIdentifcation is encrypted (owner of
// service certificate).
optional string provider_id = 1;
// Serial number for the service certificate for which ClientIdentification is
// encrypted.
optional bytes service_certificate_serial_number = 2;
// Serialized ClientIdentification message, encrypted with the privacy key using
// AES-128-CBC with PKCS#5 padding.
optional bytes encrypted_client_id = 3;
// Initialization vector needed to decrypt encrypted_client_id.
optional bytes encrypted_client_id_iv = 4;
// AES-128 privacy key, encrypted with the service public key using RSA-OAEP.
optional bytes encrypted_privacy_key = 5;
}

View File

@@ -0,0 +1,91 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Device certificate and certificate status list format definitions.
syntax = "proto2";
package widevine;
option java_outer_classname = "DeviceCertificateProtos";
option java_package = "com.google.video.widevine.protos";
import "protos/public/provisioned_device_info.proto";
// DRM certificate definition for user devices, intermediate, service, and root
// certificates.
message DrmDeviceCertificate {
enum CertificateType {
ROOT = 0;
DRM_INTERMEDIATE = 1;
DRM_USER_DEVICE = 2;
SERVICE = 3;
PROVISIONER = 4;
}
// Type of certificate. Required.
optional CertificateType type = 1;
// 128-bit globally unique serial number of certificate.
// Value is 0 for root certificate. Required.
optional bytes serial_number = 2;
// POSIX time, in seconds, when the certificate was created. Required.
optional uint32 creation_time_seconds = 3;
// Device public key. PKCS#1 ASN.1 DER-encoded. Required.
optional bytes public_key = 4;
// Widevine system ID for the device. Required for intermediate and
// user device certificates.
optional uint32 system_id = 5;
// Deprecated field, which used to indicate whether the device was a test
// (non-production) device. The test_device field in ProvisionedDeviceInfo
// below should be observed instead.
optional bool test_device_deprecated = 6 [deprecated = true];
// Service identifier (web origin) for the provider which owns the
// certificate. Required for service and provisioner certificates.
optional string provider_id = 7;
}
// Contains DRM and OEM certificate status and device information for a
// specific system ID.
message DeviceCertificateStatus {
enum Status {
VALID = 0;
REVOKED = 1;
};
// Serial number of the intermediate DrmDeviceCertificate to which this
// message refers. Required.
optional bytes drm_serial_number = 1;
// Status of the certificate. Optional.
optional Status status = 2 [default = VALID];
// Device model information about the device to which the intermediate
// certificate(s) correspond.
optional ProvisionedDeviceInfo device_info = 4;
// Serial number of the OEM X.509 intermediate certificate for this type
// of device. Present only if the device is OEM-provisioned.
optional bytes oem_serial_number = 5;
}
// List of DeviceCertificateStatus. Used to propagate certificate revocation
// status and device information.
message DeviceCertificateStatusList {
// POSIX time, in seconds, when the list was created. Required.
optional uint32 creation_time_seconds = 1;
// DeviceCertificateStatus for each system ID.
repeated DeviceCertificateStatus certificate_status = 2;
}
// Signed CertificateStatusList
message SignedCertificateStatusList {
// Serialized DeviceCertificateStatusList. Required.
optional bytes certificate_status_list = 1;
// Signature of certificate_status_list. Signed with root certificate private
// key using RSASSA-PSS. Required.
optional bytes signature = 2;
}

View File

@@ -0,0 +1,47 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// Description:
// Provisioned device info format definitions.
syntax = "proto2";
package widevine;
option java_package = "com.google.video.widevine.protos";
option java_outer_classname = "ProvisionedDeviceInfoProto";
// Contains device model information for a provisioned device.
message ProvisionedDeviceInfo {
enum WvSecurityLevel {
// Defined in Widevine Security Integration Guide for DASH on Android:
// http://doc/1Zum-fcJeoIw6KG1kDP_KepIE5h9gAZg0PaMtemBvk9c/edit#heading=h.1t3h5sf
LEVEL_UNSPECIFIED = 0;
LEVEL_1 = 1;
LEVEL_2 = 2;
LEVEL_3 = 3;
}
// Widevine system ID for the device. Mandatory.
optional uint32 system_id = 1;
// Name of system-on-a-chip. Optional.
optional string soc = 2;
// Name of manufacturer. Optional.
optional string manufacturer = 3;
// Manufacturer's model name. Matches "brand" in device metadata. Optional.
optional string model = 4;
// Type of device (Phone, Tablet, TV, etc).
optional string device_type = 5;
// Device model year. Optional.
optional uint32 model_year = 6;
// Widevine-defined security level. Optional.
optional WvSecurityLevel security_level = 7 [default = LEVEL_UNSPECIFIED];
// True if the certificate corresponds to a test (non production) device.
// Optional.
optional bool test_device = 8 [default = false];
}

View File

@@ -0,0 +1,27 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// Signed device certificate definition.
syntax = "proto2";
package widevine;
option java_outer_classname = "SignedDeviceCertificateProtos";
option java_package = "com.google.video.widevine.protos";
// DrmDeviceCertificate signed by a higher (CA) DRM certificate.
message SignedDrmDeviceCertificate {
// Serialized certificate. Required.
optional bytes drm_certificate = 1;
// Signature of certificate. Signed with root or intermediate
// certificate specified below. Required.
optional bytes signature = 2;
// SignedDrmDeviceCertificate used to sign this certificate.
optional SignedDrmDeviceCertificate signer = 3;
}

View File

@@ -0,0 +1,112 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
# Build file for provisioning 3.0 SDK internal library.
# Only accessible by public provisioning_sdk apis.
package_group(
name = "internal",
packages = [
"//provisioning_sdk/...",
],
)
package(
default_visibility = [":internal"],
)
cc_library(
name = "provisioning_engine_impl",
srcs = ["provisioning_engine_impl.cc"],
hdrs = ["provisioning_engine_impl.h"],
deps = [
":oem_device_cert",
"//base",
"//common:random_util",
"//common:rsa_key",
"//provisioning_sdk/internal/certificates:root_certificates",
"//provisioning_sdk/public:certificate_type",
"//provisioning_sdk/public:provisioning_status",
"//protos/public:device_certificate_proto",
"//protos/public:provisioned_device_info_proto",
"//protos/public:signed_device_certificate_proto",
],
)
cc_test(
name = "provisioning_engine_impl_test",
size = "small",
srcs = ["provisioning_engine_impl_test.cc"],
deps = [
":provisioning_engine_impl",
"//base",
"//external:gtest_main",
"//common:mock_rsa_key",
"//provisioning_sdk/public:certificate_type",
],
)
cc_library(
name = "provisioning_session_impl",
srcs = ["provisioning_session_impl.cc"],
hdrs = ["provisioning_session_impl.h"],
deps = [
":oem_device_cert",
":provisioning_engine_impl",
"//base",
"//common:aes_cbc_util",
"//common:random_util",
"//common:rsa_key",
"//common:sha_util",
"//provisioning_sdk/public:provisioning_status",
"//protos/public:certificate_provisioning_proto",
"//protos/public:client_identification_proto",
"//protos/public:device_certificate_proto",
"//protos/public:provisioned_device_info_proto",
],
)
cc_test(
name = "provisioning_session_impl_test",
size = "small",
srcs = ["provisioning_session_impl_test.cc"],
deps = [
":oem_device_cert",
":provisioning_engine_impl",
":provisioning_session_impl",
"//external:gtest_main",
"//common:aes_cbc_util",
"//common:mock_rsa_key",
"//common:sha_util",
],
)
cc_library(
name = "oem_device_cert",
srcs = ["oem_device_cert.cc"],
hdrs = ["oem_device_cert.h"],
deps = [
"//base",
"//external:openssl",
"//common:openssl_util",
"//common:rsa_key",
"//provisioning_sdk/internal/certificates:root_certificates",
"//provisioning_sdk/public:certificate_type",
],
)
cc_test(
name = "oem_device_cert_test",
size = "small",
srcs = ["oem_device_cert_test.cc"],
deps = [
":oem_device_cert",
"//external:gtest_main",
"//provisioning_sdk/internal/certificates:test_certificates",
],
)

View File

@@ -0,0 +1,117 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
# Build file for test certificates.
package(
default_visibility = ["//visibility:public"],
)
cc_library(
name = "root_certificates",
srcs = [
"root_certificates.cc",
":drm_ca_root_dev_cert",
":drm_ca_root_prod_cert",
":drm_ca_root_test_cert",
":oem_ca_root_dev_der",
":oem_ca_root_prod_der",
],
hdrs = ["root_certificates.h"],
)
genrule(
name = "drm_ca_root_test_cert",
srcs = ["drm_ca_root_test.cert"],
outs = ["drm_ca_root_test_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "drm_ca_root_dev_cert",
srcs = ["drm_ca_root_dev.cert"],
outs = ["drm_ca_root_dev_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "drm_ca_root_prod_cert",
srcs = ["drm_ca_root_prod.cert"],
outs = ["drm_ca_root_prod_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "oem_ca_root_dev_der",
srcs = ["oem_ca_root_dev_cert.der"],
outs = ["oem_ca_root_dev_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "oem_ca_root_prod_der",
srcs = ["oem_ca_root_prod_cert.der"],
outs = ["oem_ca_root_prod_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
cc_library(
name = "test_certificates",
srcs = [
"test_certificates.cc",
":backwards_chain_der",
":expired_2000_chain_der",
":invalid_chain_der",
":single_cert_chain_der",
":sysid_2001_chain_der",
":sysid_2001_public_key_der",
],
hdrs = ["test_certificates.h"],
)
genrule(
name = "single_cert_chain_der",
srcs = ["single-cert-chain.der"],
outs = ["single_cert_chain.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "sysid_2001_chain_der",
srcs = ["sysid-2001-chain.der"],
outs = ["sysid_2001_chain.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "sysid_2001_public_key_der",
srcs = ["sysid-2001-public-key.der"],
outs = ["sysid_2001_public_key.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "expired_2000_chain_der",
srcs = ["expired-2000-chain.der"],
outs = ["expired_2000_chain.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "backwards_chain_der",
srcs = ["backwards-chain.der"],
outs = ["backwards_chain.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "invalid_chain_der",
srcs = ["invalid_chain.der"],
outs = ["invalid_chain.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)

View File

@@ -0,0 +1,38 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/certificates/root_certificates.h"
#include "provisioning_sdk/internal/certificates/drm_ca_root_dev_cert.h"
#include "provisioning_sdk/internal/certificates/drm_ca_root_prod_cert.h"
#include "provisioning_sdk/internal/certificates/drm_ca_root_test_cert.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_dev_cert.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_prod_cert.h"
namespace widevine {
RootCertificates::RootCertificates()
: drm_root_test_certificate_(
drm_ca_root_test_cert,
drm_ca_root_test_cert + drm_ca_root_test_cert_len),
drm_root_dev_certificate_(
drm_ca_root_dev_cert,
drm_ca_root_dev_cert + drm_ca_root_dev_cert_len),
drm_root_prod_certificate_(
drm_ca_root_prod_cert,
drm_ca_root_prod_cert + drm_ca_root_prod_cert_len),
oem_root_dev_certificate_(
oem_ca_root_dev_cert_der,
oem_ca_root_dev_cert_der + oem_ca_root_dev_cert_der_len),
oem_root_prod_certificate_(
oem_ca_root_prod_cert_der,
oem_ca_root_prod_cert_der + oem_ca_root_prod_cert_der_len) {}
RootCertificates::~RootCertificates() {}
} // namespace widevine

View File

@@ -0,0 +1,56 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_CERTIFICATES_H_
#include <string>
namespace widevine {
// This class contains DRM and OEM root certificates.
class RootCertificates {
public:
RootCertificates();
~RootCertificates();
const std::string& drm_root_test_certificate() const {
return drm_root_test_certificate_;
}
const std::string& drm_root_dev_certificate() const {
return drm_root_dev_certificate_;
}
const std::string& drm_root_prod_certificate() const {
return drm_root_prod_certificate_;
}
const std::string& oem_root_dev_certificate() const {
return oem_root_dev_certificate_;
}
const std::string& oem_root_prod_certificate() const {
return oem_root_prod_certificate_;
}
private:
RootCertificates(const RootCertificates&) = delete;
RootCertificates& operator=(const RootCertificates&) = delete;
std::string drm_root_test_certificate_;
std::string drm_root_dev_certificate_;
std::string drm_root_prod_certificate_;
std::string oem_root_dev_certificate_;
std::string oem_root_prod_certificate_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_CERTIFICATES_H_

View File

@@ -0,0 +1,40 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/certificates/test_certificates.h"
#include "provisioning_sdk/internal/certificates/backwards_chain.h"
#include "provisioning_sdk/internal/certificates/expired_2000_chain.h"
#include "provisioning_sdk/internal/certificates/invalid_chain.h"
#include "provisioning_sdk/internal/certificates/single_cert_chain.h"
#include "provisioning_sdk/internal/certificates/sysid_2001_chain.h"
#include "provisioning_sdk/internal/certificates/sysid_2001_public_key.h"
namespace widevine {
TestCertificates::TestCertificates()
: single_certificate_chain_der_(
single_cert_chain_der,
single_cert_chain_der + single_cert_chain_der_len),
valid_certificate_chain_der_(
sysid_2001_chain_der,
sysid_2001_chain_der + sysid_2001_chain_der_len),
valid_certificate_public_key_der_(
sysid_2001_public_key_der,
sysid_2001_public_key_der + sysid_2001_public_key_der_len),
expired_certificate_chain_der_(
expired_2000_chain_der,
expired_2000_chain_der + expired_2000_chain_der_len),
backwards_certificate_chain_der_(
backwards_chain_der, backwards_chain_der + backwards_chain_der_len),
invalid_certificate_chain_der_(
invalid_chain_der, invalid_chain_der + invalid_chain_der_len) {}
TestCertificates::~TestCertificates() {}
} // namespace widevine

View File

@@ -0,0 +1,63 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_CERTIFICATES_H_
#include <string>
namespace widevine {
// This class contains DER-encoded test certificates. The keys for these
// certificates came from common/rsa_test_keys.h.
class TestCertificates {
public:
TestCertificates();
~TestCertificates();
const std::string& single_certificate_chain_der() const {
return single_certificate_chain_der_;
}
const std::string& valid_certificate_chain_der() const {
return valid_certificate_chain_der_;
}
const std::string& valid_certificate_public_key_der() const {
return valid_certificate_public_key_der_;
}
const std::string& expired_certificate_chain_der() const {
return expired_certificate_chain_der_;
}
const std::string& backwards_certificate_chain_der() const {
return backwards_certificate_chain_der_;
}
const std::string& invalid_certificate_chain_der() const {
return invalid_certificate_chain_der_;
}
private:
TestCertificates(const TestCertificates&) = delete;
TestCertificates& operator=(const TestCertificates&) = delete;
std::string single_certificate_chain_der_;
// leaf + intermediate certificates.
std::string valid_certificate_chain_der_;
std::string valid_certificate_public_key_der_;
std::string expired_certificate_chain_der_;
// intermediate + leaf certificates.
std::string backwards_certificate_chain_der_;
std::string invalid_certificate_chain_der_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_CERTIFICATES_H_

View File

@@ -0,0 +1,210 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/oem_device_cert.h"
#include <string.h>
#include "glog/logging.h"
#include "openssl/asn1.h"
#include "openssl/x509.h"
#include "openssl/x509v3.h"
#include "provisioning_sdk/internal/certificates/root_certificates.h"
namespace widevine {
namespace {
const int kExtensionOidSize = 64;
const char kWidevineSystemIdExtensionOid[] = "1.3.6.1.4.1.11129.4.1.1";
bool ExtractPublicKey(X509* x509, std::unique_ptr<RsaPublicKey>* public_key) {
DCHECK(x509);
ScopedPKEY pkey(X509_get_pubkey(x509));
if (!pkey) {
LOG(WARNING) << "X509_get_pubkey failed.";
return false;
}
public_key->reset(new RsaPublicKey(EVP_PKEY_get1_RSA(pkey.get())));
return true;
}
bool ExtractSystemId(X509* x509, uint32_t* system_id) {
DCHECK(x509);
const int num_of_extensions = X509_get_ext_count(x509);
for (int i = 0; i < num_of_extensions; ++i) {
X509_EXTENSION* extension = X509_get_ext(x509, i);
if (!extension) {
LOG(WARNING) << "X509_get_ext failed.";
return false;
}
ASN1_OBJECT* extension_object = X509_EXTENSION_get_object(extension);
if (!extension_object) {
LOG(WARNING) << "X509_EXTENSION_get_object failed.";
return false;
}
char extension_name[kExtensionOidSize + 1];
OBJ_obj2txt(extension_name, kExtensionOidSize, extension_object, 1);
if (strcmp(extension_name, kWidevineSystemIdExtensionOid)) continue;
ASN1_OCTET_STRING* octet_str = X509_EXTENSION_get_data(extension);
if (!octet_str) {
LOG(WARNING) << "X509_EXTENSION_get_data failed.";
return false;
}
const unsigned char* data = octet_str->data;
if (!data) {
LOG(WARNING) << "null data in octet string.";
return false;
}
ScopedAsn1Integer asn1_integer(
d2i_ASN1_INTEGER(nullptr, &data, octet_str->length));
if (!asn1_integer) {
LOG(WARNING) << "d2i_ASN1_INTEGER failed.";
return false;
}
int64_t system_id_long = ASN1_INTEGER_get(asn1_integer.get());
if (system_id_long == -1) {
LOG(WARNING) << "ASN1_INTEGER_get failed.";
return false;
}
*system_id = system_id_long;
return true;
}
LOG(WARNING) << "Widevine system ID extension not found.";
return false;
}
bool ExtractSerialNumber(X509* x509, std::string* oem_ca_serial_number) {
ASN1_INTEGER* serial = X509_get_serialNumber(x509);
if (!serial) {
LOG(WARNING) << "X509_get_serialNumber failed.";
return false;
}
uint8_t* buffer = ASN1_STRING_data(serial);
if (!buffer) {
LOG(WARNING) << "ASN1_STRING_data failed.";
return false;
}
int length = ASN1_STRING_length(serial);
if (length <= 0) {
LOG(WARNING) << "ASN1_STRING_length returns " << length;
}
oem_ca_serial_number->assign(reinterpret_cast<char*>(buffer), length);
return true;
}
} // namespace
OemDeviceCert::OemDeviceCert() {}
OemDeviceCert::~OemDeviceCert() {}
bool OemDeviceCert::Initialize(CertificateType certificate_type) {
RootCertificates root_certificates;
switch (certificate_type) {
case kCertTesting:
case kCertDevelopment:
return Initialize(root_certificates.oem_root_dev_certificate());
case kCertProduction:
return Initialize(root_certificates.oem_root_prod_certificate());
default:
LOG(WARNING) << "Invalid certificate type " << certificate_type;
return false;
}
}
bool OemDeviceCert::VerifyCertificateChain(
const std::string& certificate_chain,
std::unique_ptr<RsaPublicKey>* leaf_public_key, uint32_t* system_id,
std::string* oem_ca_serial_number) const {
if (certificate_chain.empty()) {
LOG(WARNING) << "Empty certificate.";
return false;
}
ScopedX509Stack x509_stack(sk_X509_new_null());
if (!x509_stack) {
LOG(WARNING) << "sk_X509_new_null returned NULL.";
return false;
}
CBS pkcs7;
CBS_init(&pkcs7, reinterpret_cast<const uint8_t*>(certificate_chain.data()),
certificate_chain.size());
if (!PKCS7_get_certificates(x509_stack.get(), &pkcs7)) {
LOG(WARNING) << "PKCS7_get_certificates failed.";
return false;
}
if (sk_X509_num(x509_stack.get()) != 2) {
LOG(WARNING) << "Expecting one and only one intermediate certificate.";
return false;
}
X509* leaf_certificate = sk_X509_value(x509_stack.get(), 0);
X509* intermediate_certificate = sk_X509_value(x509_stack.get(), 1);
DCHECK(leaf_certificate);
DCHECK(intermediate_certificate);
// Verify the cert.
// TODO(user): Implement some form of caching mechanism so that we do not
// have to verify the same intermediate certs over and over.
ScopedX509StoreCtx context(X509_STORE_CTX_new());
if (!context) {
LOG(WARNING) << "X509_STORE_CTX_new returned NULL.";
return false;
}
if (!X509_STORE_CTX_init(context.get(), store_.get(), leaf_certificate,
x509_stack.get())) {
LOG(WARNING) << "X509_STORE_CTX_init failed.";
return false;
}
if (X509_verify_cert(context.get()) != 1) {
LOG(WARNING) << "Verification error: "
<< X509_verify_cert_error_string(
X509_STORE_CTX_get_error(context.get()));
return false;
}
if (sk_X509_num(context->chain) < 3) {
LOG(WARNING) << "The leaf certificate should not be signed by the root "
"certificate directly.";
return false;
}
// Extract public key from the leaf certificate and system_id extension and
// oem serial number from the intermediate certificate.
return ExtractPublicKey(leaf_certificate, leaf_public_key) &&
ExtractSystemId(intermediate_certificate, system_id) &&
ExtractSerialNumber(intermediate_certificate, oem_ca_serial_number);
}
bool OemDeviceCert::Initialize(const std::string& serialized_root_certificate) {
if (serialized_root_certificate.empty()) {
LOG(WARNING) << "Empty root certificate.";
return false;
}
store_.reset(X509_STORE_new());
if (!store_) {
LOG(WARNING) << "X509_STORE_new returned NULL";
return false;
}
const char* data = serialized_root_certificate.data();
ScopedX509 root_certificate(d2i_X509(nullptr,
reinterpret_cast<const uint8_t**>(&data),
serialized_root_certificate.size()));
if (!root_certificate) {
LOG(WARNING) << "d2i_X509 returned NULL.";
return false;
}
if (!X509_STORE_add_cert(store_.get(), root_certificate.get())) {
LOG(WARNING) << "X509_STORE_add_cert failed.";
return false;
}
return true;
}
} // namespace widevine

View File

@@ -0,0 +1,56 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_INTERNAL_OEM_DEVICE_CERT_H_
#define PROVISIONING_SDK_INTERNAL_OEM_DEVICE_CERT_H_
#include <stdint.h>
#include <memory>
#include <string>
#include "common/openssl_util.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/public/certificate_type.h"
namespace widevine {
// Implements a class to handle OEM certificate: verifies the validity of the
// certificate and extracts leaf public key and system id.
class OemDeviceCert {
public:
OemDeviceCert();
virtual ~OemDeviceCert();
// Initialize with root certificate.
bool Initialize(CertificateType certificate_type);
// Verify the given certificate chain (in DER encoded pkcs7 format), which
// includes the leaf certificate (a device unique certificate containing the
// device public OEM key) and the intermediate certificate (OEM model
// intermediate CA certificate for a specific device make + model), and
// extract public key from the leaf certificate and system id extension and
// oem ca serial number from the intermediate certificate.
virtual bool VerifyCertificateChain(
const std::string& certificate_chain,
std::unique_ptr<RsaPublicKey>* leaf_public_key, uint32_t* system_id,
std::string* oem_ca_serial_number) const;
private:
OemDeviceCert(const OemDeviceCert&) = delete;
OemDeviceCert& operator=(const OemDeviceCert&) = delete;
// Internal implementation of Initialize function.
bool Initialize(const std::string& serialized_root_certificate);
ScopedX509Store store_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_OEM_DEVICE_CERT_H_

View File

@@ -0,0 +1,95 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "gtest/gtest.h"
#include "provisioning_sdk/internal/certificates/test_certificates.h"
namespace widevine {
class OemDeviceCertTest : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(oem_device_cert_.Initialize(kCertTesting));
}
OemDeviceCert oem_device_cert_;
TestCertificates test_certificates_;
};
TEST_F(OemDeviceCertTest, EmptyCertificateChain) {
std::unique_ptr<RsaPublicKey> leaf_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
EXPECT_FALSE(oem_device_cert_.VerifyCertificateChain(
"", &leaf_public_key, &system_id, &oem_ca_serial_number));
}
TEST_F(OemDeviceCertTest, InvalidCertificateChain) {
std::unique_ptr<RsaPublicKey> leaf_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
EXPECT_FALSE(oem_device_cert_.VerifyCertificateChain(
"invalid certificte chain", &leaf_public_key, &system_id,
&oem_ca_serial_number));
}
TEST_F(OemDeviceCertTest, OnlyOneCertificateInCertificateChain) {
std::unique_ptr<RsaPublicKey> leaf_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
EXPECT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.single_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}
TEST_F(OemDeviceCertTest, ValidCertificateChain) {
std::unique_ptr<RsaPublicKey> leaf_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_TRUE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.valid_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
std::unique_ptr<RsaPublicKey> public_key(RsaPublicKey::Create(
test_certificates_.valid_certificate_public_key_der()));
ASSERT_TRUE(public_key);
EXPECT_TRUE(leaf_public_key->MatchesPublicKey(*public_key));
EXPECT_EQ(2001u, system_id);
EXPECT_EQ("\x1", oem_ca_serial_number);
}
TEST_F(OemDeviceCertTest, ExpiredCertificateChain) {
std::unique_ptr<RsaPublicKey> leaf_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.expired_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}
TEST_F(OemDeviceCertTest, OutOfOrderCertificateChain) {
std::unique_ptr<RsaPublicKey> leaf_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.backwards_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}
TEST_F(OemDeviceCertTest, CertificateChainNotSignedByRoot) {
std::unique_ptr<RsaPublicKey> leaf_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.invalid_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}
} // namespace widevine

View File

@@ -0,0 +1,464 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
#include <stddef.h>
#include <time.h>
#include <cstdint>
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include "glog/logging.h"
#include "common/random_util.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/certificates/root_certificates.h"
#include "provisioning_sdk/public/provisioning_status.h"
#define LOG_WITH_PROTO(message, proto) \
LOG(WARNING) << (message) << " [proto: " << (proto).ShortDebugString() << "]"
namespace widevine {
namespace {
// Verify that |certificate| is signed by |public_key|. If |public_key| is null,
// |certificate| should be self signed.
bool VerifyAndExtractCertificate(const RsaPublicKey* public_key,
const std::string& certificate,
SignedDrmDeviceCertificate* signed_drm_cert,
DrmDeviceCertificate* drm_cert) {
DCHECK(signed_drm_cert);
DCHECK(drm_cert);
if (!signed_drm_cert->ParseFromString(certificate)) {
LOG(WARNING) << "Failed to parse SignedDrmDeviceCertificate.";
return false;
}
if (signed_drm_cert->drm_certificate().empty()) {
LOG_WITH_PROTO("Missing drm_certificate", *signed_drm_cert);
return false;
}
if (signed_drm_cert->signature().empty()) {
LOG_WITH_PROTO("Missing signature", *signed_drm_cert);
return false;
}
if (!drm_cert->ParseFromString(signed_drm_cert->drm_certificate())) {
LOG_WITH_PROTO("Failed to parse DrmDeviceCertificate", *signed_drm_cert);
return false;
}
if (drm_cert->public_key().empty()) {
LOG_WITH_PROTO("Missing public_key", *drm_cert);
return false;
}
std::unique_ptr<RsaPublicKey> local_public_key;
if (!public_key) {
local_public_key.reset(RsaPublicKey::Create(drm_cert->public_key()));
if (!local_public_key) {
LOG_WITH_PROTO("Invalid root public key", *drm_cert);
return false;
}
public_key = local_public_key.get();
}
if (!public_key->VerifySignature(signed_drm_cert->drm_certificate(),
signed_drm_cert->signature())) {
LOG_WITH_PROTO("Signature verification failed", *signed_drm_cert);
return false;
}
return true;
}
bool GenerateCertificate(DrmDeviceCertificate::CertificateType type,
uint32_t system_id,
const std::string& provider_id,
const std::string& serial_number,
const std::string& public_key,
const RsaPrivateKey& signing_key,
const SignedDrmDeviceCertificate& signer,
std::string* certificate) {
DCHECK(type == DrmDeviceCertificate::DRM_INTERMEDIATE ||
type == DrmDeviceCertificate::DRM_USER_DEVICE);
if (serial_number.empty()) {
LOG(WARNING) << "Require an non-empty serial number.";
return false;
}
DrmDeviceCertificate drm_cert;
drm_cert.set_type(type);
drm_cert.set_system_id(system_id);
if (!provider_id.empty()) drm_cert.set_provider_id(provider_id);
drm_cert.set_serial_number(serial_number);
drm_cert.set_creation_time_seconds(time(nullptr));
drm_cert.set_public_key(public_key);
SignedDrmDeviceCertificate signed_cert;
if (!drm_cert.SerializeToString(
signed_cert.mutable_drm_certificate())) {
LOG(WARNING) << "Error serializing DrmDeviceCertificate.";
return false;
}
if (!signing_key.GenerateSignature(signed_cert.drm_certificate(),
signed_cert.mutable_signature())) {
LOG(WARNING) << "Failed to generate signature for DrmDeviceCertificate.";
return false;
}
*signed_cert.mutable_signer() = signer;
if (!signed_cert.SerializeToString(certificate)) {
LOG(WARNING) << "Failed to serialize SignedDrmDeviceCertificate to string.";
return false;
}
return true;
}
// Compares oem serial number, which is a 16-byte big number.
bool IsSerialNumberEq(const std::string& a, const std::string& b) {
// An empty serial number indicates that it does not need to be matched.
if (a.empty() || b.empty()) return true;
int a_index = a.size() - 1;
int b_index = b.size() - 1;
// Matching a and b backwards.
for (; a_index >= 0 && b_index >= 0; --a_index, --b_index)
if (a[a_index] != b[b_index]) return false;
// The remaining characters should be 0.
for (; a_index >= 0; --a_index)
if (a[a_index] != 0) return false;
for (; b_index >= 0; --b_index)
if (b[b_index] != 0) return false;
return true;
}
} // namespace
ProvisioningEngineImpl::ProvisioningEngineImpl()
: rsa_key_factory_(new RsaKeyFactory) {}
ProvisioningEngineImpl::~ProvisioningEngineImpl() {}
ProvisioningStatus ProvisioningEngineImpl::Initialize(
CertificateType certificate_type, const std::string& drm_service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_phassphrase,
const std::string& provisioning_drm_certificate,
const std::string& provisioning_private_key,
const std::string& provisioning_private_key_phassphrase,
const std::string& secret_spoid_sauce) {
if (!LoadDrmRootPublicKey(certificate_type)) return INVALID_CERTIFICATE_TYPE;
SignedDrmDeviceCertificate signed_drm_cert;
DrmDeviceCertificate drm_cert;
if (!VerifyAndExtractCertificate(root_public_key_.get(),
drm_service_certificate, &signed_drm_cert,
&drm_cert)) {
return INVALID_SERVICE_DRM_CERTIFICATE;
}
if (drm_cert.type() != DrmDeviceCertificate::SERVICE) {
LOG(WARNING) << "Expecting SERVICE certificate.";
return INVALID_SERVICE_DRM_CERTIFICATE;
}
service_public_key_ =
rsa_key_factory_->CreateFromPkcs1PublicKey(drm_cert.public_key());
if (!service_public_key_) return INVALID_SERVICE_DRM_CERTIFICATE;
service_private_key_ = rsa_key_factory_->CreateFromPkcs8PrivateKey(
service_private_key, service_private_key_phassphrase);
if (!service_private_key_) return INVALID_SERVICE_PRIVATE_KEY;
if (!service_public_key_->MatchesPrivateKey(*service_private_key_)) {
LOG(WARNING) << "Services public key and private key do not match.";
return INVALID_SERVICE_PRIVATE_KEY;
}
if (!VerifyAndExtractCertificate(root_public_key_.get(),
provisioning_drm_certificate,
&signed_provisioning_cert_, &drm_cert)) {
return INVALID_PROVISIONER_DRM_CERTIFICATE;
}
if (drm_cert.type() != DrmDeviceCertificate::ROOT &&
drm_cert.type() != DrmDeviceCertificate::PROVISIONER) {
LOG(WARNING) << "Expecting ROOT or PROVISIONER certificate.";
return INVALID_PROVISIONER_DRM_CERTIFICATE;
}
provisioning_public_key_ =
rsa_key_factory_->CreateFromPkcs1PublicKey(drm_cert.public_key());
if (!provisioning_public_key_) return INVALID_PROVISIONER_DRM_CERTIFICATE;
provisioning_private_key_ = rsa_key_factory_->CreateFromPkcs8PrivateKey(
provisioning_private_key, provisioning_private_key_phassphrase);
if (!provisioning_private_key_) return INVALID_PROVISIONER_PRIVATE_KEY;
if (!provisioning_public_key_->MatchesPrivateKey(
*provisioning_private_key_)) {
LOG(WARNING) << "Provisioning public key and private key do not match.";
return INVALID_PROVISIONER_PRIVATE_KEY;
}
if (secret_spoid_sauce.empty()) {
LOG(WARNING) << "SPOID secret sauce is empty!";
return INVALID_SPOID_SAUCE;
}
secret_spoid_sauce_ = secret_spoid_sauce;
if (!oem_device_cert_.Initialize(certificate_type)) return INTERNAL_ERROR;
return OK;
}
ProvisioningStatus ProvisioningEngineImpl::SetCertificateStatusList(
const std::string& certificate_status_list, uint32_t expiration_period_seconds) {
if (certificate_status_list.empty()) {
LOG(WARNING) << "Empty certificate_status_list.";
return INVALID_STATUS_LIST;
}
SignedCertificateStatusList signed_cert_status_list;
if (!signed_cert_status_list.ParseFromString(certificate_status_list)) {
LOG(WARNING) << "Error parsing SignedCertificateStatusList.";
return INVALID_STATUS_LIST;
}
if (!root_public_key_->VerifySignature(
signed_cert_status_list.certificate_status_list(),
signed_cert_status_list.signature())) {
LOG_WITH_PROTO("Signature verification failed", signed_cert_status_list);
return INVALID_STATUS_LIST;
}
DeviceCertificateStatusList cert_status_list;
if (!cert_status_list.ParseFromString(
signed_cert_status_list.certificate_status_list())) {
LOG_WITH_PROTO("Error parsing DeviceCertificateStatusList",
signed_cert_status_list);
return INVALID_STATUS_LIST;
}
WriterMutexLock writer_lock(&mutex_);
if (expiration_period_seconds == 0) {
certificate_expiration_seconds_utc_ = std::numeric_limits<uint32_t>::max();
} else {
certificate_expiration_seconds_utc_ =
cert_status_list.creation_time_seconds() + expiration_period_seconds;
}
certificate_status_map_.clear();
for (DeviceCertificateStatus& cert_status :
*cert_status_list.mutable_certificate_status()) {
const uint32_t system_id = cert_status.device_info().system_id();
certificate_status_map_[system_id].Swap(&cert_status);
}
// Remove items that are no longer valid.
for (auto it = intermediate_certs_info_.begin();
it != intermediate_certs_info_.end();) {
auto certificate_status_it = certificate_status_map_.find(it->first);
if (certificate_status_it == certificate_status_map_.end())
intermediate_certs_info_.erase(it++);
else
++it;
}
// Set / Update device info.
for (const auto& cert_status : certificate_status_map_) {
auto device_info = std::make_shared<ProvisionedDeviceInfo>();
*device_info = cert_status.second.device_info();
intermediate_certs_info_[cert_status.first].device_info = device_info;
// intermediate certificate and private key are not changed if exists.
}
return OK;
}
ProvisioningStatus ProvisioningEngineImpl::GenerateDrmIntermediateCertificate(
uint32_t system_id, const std::string& public_key, std::string* certificate) const {
auto intermediate_public_key =
rsa_key_factory_->CreateFromPkcs1PublicKey(public_key);
if (!intermediate_public_key) return INVALID_INTERMEDIATE_PUBLIC_KEY;
const size_t kCertificateSerialNumberSize = 16;
std::string serial_number;
if (!RandomBytes(kCertificateSerialNumberSize, &serial_number)) {
LOG(WARNING) << "Failed to generate serial_number.";
return INTERNAL_ERROR;
}
if (!GenerateCertificate(DrmDeviceCertificate::DRM_INTERMEDIATE,
system_id, std::string(), serial_number, public_key,
*provisioning_private_key_,
signed_provisioning_cert_, certificate)) {
return INTERNAL_ERROR;
}
return OK;
}
ProvisioningStatus ProvisioningEngineImpl::AddDrmIntermediateCertificate(
const std::string& intermediate_cert, const std::string& cert_private_key,
const std::string& cert_private_key_passphrase) {
SignedDrmDeviceCertificate intermediate_signed_cert;
DrmDeviceCertificate intermediate_drm_cert;
if (!VerifyAndExtractCertificate(provisioning_public_key_.get(),
intermediate_cert, &intermediate_signed_cert,
&intermediate_drm_cert)) {
return INVALID_INTERMEDIATE_DRM_CERTIFICATE;
}
if (intermediate_drm_cert.type() !=
DrmDeviceCertificate::DRM_INTERMEDIATE) {
LOG_WITH_PROTO("Invalid device certificate type", intermediate_drm_cert);
return INVALID_INTERMEDIATE_DRM_CERTIFICATE;
}
if (!intermediate_drm_cert.has_system_id()) {
LOG_WITH_PROTO("Missing system_id", intermediate_drm_cert);
return UNKNOWN_SYSTEM_ID;
}
const std::string empty_oem_ca_serial_number;
ProvisioningStatus status = CheckDeviceStatus(
intermediate_drm_cert.system_id(), empty_oem_ca_serial_number);
if (status != OK) return status;
auto intermediate_public_key = rsa_key_factory_->CreateFromPkcs1PublicKey(
intermediate_drm_cert.public_key());
if (!intermediate_public_key) return INVALID_INTERMEDIATE_DRM_CERTIFICATE;
std::unique_ptr<RsaPrivateKey> intermediate_private_key =
rsa_key_factory_->CreateFromPkcs8PrivateKey(cert_private_key,
cert_private_key_passphrase);
if (!intermediate_private_key) return INVALID_INTERMEDIATE_PRIVATE_KEY;
if (!intermediate_public_key->MatchesPrivateKey(*intermediate_private_key)) {
LOG(WARNING) << "Intermediate public key and private key do not match.";
return INVALID_INTERMEDIATE_PRIVATE_KEY;
}
WriterMutexLock writer_lock(&mutex_);
auto& certificate_info =
intermediate_certs_info_[intermediate_drm_cert.system_id()];
certificate_info.signed_drm_certificate.Swap(&intermediate_signed_cert);
certificate_info.private_key = std::move(intermediate_private_key);
return OK;
}
ProvisioningStatus ProvisioningEngineImpl::GenerateDeviceDrmCertificate(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& public_key, const std::string& certificate_serial_number,
std::string* certificate) const {
// |oem_ca_serial_number| could be empty if it is called directly from
// ProvisioningEngine::GenerateDeviceDrmCertificate.
DCHECK(!certificate_serial_number.empty());
return GenerateProviderDeviceDrmCertificate(
system_id, oem_ca_serial_number, std::string(), public_key,
certificate_serial_number, certificate);
}
ProvisioningStatus ProvisioningEngineImpl::GenerateProviderDeviceDrmCertificate(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& provider_id, const std::string& public_key,
const std::string& certificate_serial_number, std::string* certificate) const {
// |oem_ca_serial_number| could be empty if it is called directly from
// ProvisioningEngine::GenerateDeviceDrmCertificate.
DCHECK(!certificate_serial_number.empty());
ProvisioningStatus status =
CheckDeviceStatus(system_id, oem_ca_serial_number);
if (status != OK) return status;
std::shared_ptr<RsaPrivateKey> intermediate_private_key;
const SignedDrmDeviceCertificate* intermediate_cert = nullptr;
{
ReaderMutexLock reader_lock(&mutex_);
auto info_it = intermediate_certs_info_.find(system_id);
if (info_it == intermediate_certs_info_.end() ||
!info_it->second.private_key) {
LOG(WARNING) << "Cannot find the intermediate certificate for system: "
<< system_id;
return MISSING_DRM_INTERMEDIATE_CERT;
}
intermediate_private_key = info_it->second.private_key;
intermediate_cert = &info_it->second.signed_drm_certificate;
}
if (!GenerateCertificate(DrmDeviceCertificate::DRM_USER_DEVICE,
system_id, provider_id, certificate_serial_number,
public_key, *intermediate_private_key,
*intermediate_cert, certificate)) {
return INTERNAL_ERROR;
}
return OK;
}
std::shared_ptr<ProvisionedDeviceInfo> ProvisioningEngineImpl::GetDeviceInfo(
uint32_t system_id) const {
ReaderMutexLock reader_lock(&mutex_);
auto info_it = intermediate_certs_info_.find(system_id);
if (info_it == intermediate_certs_info_.end()) {
LOG(WARNING) << "Cannot find the system id in device certificate list: "
<< system_id;
return std::shared_ptr<ProvisionedDeviceInfo>();
}
return info_it->second.device_info;
}
bool ProvisioningEngineImpl::LoadDrmRootPublicKey(
CertificateType certificate_type) {
const std::string* root_cert_string = nullptr;
RootCertificates root_certificates;
switch (certificate_type) {
case kCertTesting:
root_cert_string = &root_certificates.drm_root_test_certificate();
break;
case kCertDevelopment:
root_cert_string = &root_certificates.drm_root_dev_certificate();
break;
case kCertProduction:
root_cert_string = &root_certificates.drm_root_prod_certificate();
break;
default:
LOG(WARNING) << "Invalid certificate type " << certificate_type;
return false;
}
SignedDrmDeviceCertificate signed_root_cert;
DrmDeviceCertificate root_cert;
if (!VerifyAndExtractCertificate(nullptr /* self signed */, *root_cert_string,
&signed_root_cert, &root_cert)) {
LOG(WARNING) << "Failed to extract root certificate.";
return false;
}
if (root_cert.type() != DrmDeviceCertificate::ROOT) {
LOG(WARNING) << "Expecting ROOT certificate.";
return false;
}
root_public_key_ =
rsa_key_factory_->CreateFromPkcs1PublicKey(root_cert.public_key());
CHECK(root_public_key_);
return true;
}
ProvisioningStatus ProvisioningEngineImpl::CheckDeviceStatus(
uint32_t system_id, const std::string& oem_ca_serial_number) const {
ReaderMutexLock reader_lock(&mutex_);
if (certificate_expiration_seconds_utc_ < time(nullptr))
return STATUS_LIST_EXPIRED;
auto certificate_status_it = certificate_status_map_.find(system_id);
if (certificate_status_it == certificate_status_map_.end()) {
LOG(WARNING) << "Cannot find the system id in device certificate list: "
<< system_id;
return UNKNOWN_SYSTEM_ID;
}
if (!IsSerialNumberEq(certificate_status_it->second.oem_serial_number(),
oem_ca_serial_number)) {
LOG(WARNING) << "Provided serial number does not match with stored serial "
"number. It may come from a revoked device. System Id: "
<< system_id;
return DEVICE_REVOKED;
}
if (certificate_status_it->second.status() !=
DeviceCertificateStatus::VALID) {
LOG(WARNING) << "Device revoked " << system_id;
return DEVICE_REVOKED;
}
return OK;
}
} // namespace widevine

View File

@@ -0,0 +1,189 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// ProvisioningEngine internal implementation. This class is thread-safe.
#ifndef PROVISIONING_SDK_INTERNAL_PROVISIONING_ENGINE_IMPL_H_
#define PROVISIONING_SDK_INTERNAL_PROVISIONING_ENGINE_IMPL_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include "base/mutex.h"
#include "base/thread_annotations.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "provisioning_sdk/public/certificate_type.h"
#include "provisioning_sdk/public/provisioning_status.h"
#include "protos/public/device_certificate.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/signed_device_certificate.pb.h"
namespace widevine {
class ProvisioningSession;
class ProvisioningEngineImpl {
public:
ProvisioningEngineImpl();
virtual ~ProvisioningEngineImpl();
// Initializes the provisioning engine with required credentials.
// * |certificate_type| indicates which type of certificate chains will be
// used for device provisioning via this engine.
// * |drm_service_certificate| is a Google-generated certificate used to
// authenticate the service provider for purposes of user privacy.
// * |service_private_key| is the encrypted PKCS#8 private RSA key
// corresponding to the service certificate.
// * |service_private_key_passphrase| is the password required to decrypt
// |service_private_key|, if any.
// * |provisioning_drm_certificate| is a Google-generated certificate used to
// sign intermediate DRM certificates.
// * |provisioning_private_key| is the encrypted PKCS#8 private RSA key
// corresponding to the provisioning certificate.
// * |provisioning_private_key_passphrase| is the password required to
// decrypt |provisioning_private_key|, if any.
// * |secret_spoid_sauce| is a stable secret used as a factor in the
// derivation of Stable Per-Origin IDentifiers.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus Initialize(
CertificateType certificate_type,
const std::string& drm_service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase,
const std::string& provisioning_drm_certificate,
const std::string& provisioning_private_key,
const std::string& provisioning_private_key_passphrase,
const std::string& secret_spoid_sauce);
// Set the certificate status list for this engine.
// * |certificate_status_list| is a certificate status list generated by the
// Widevine Provisioning Service.
// * |expiration_period| is the number of seconds until the
// |certificate_status_list| expires after its creation time
// (creation_time_seconds). Zero means it will never expire.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus SetCertificateStatusList(
const std::string& certificate_status_list,
uint32_t expiration_period_seconds);
// Generate an intermediate DRM certificate.
// * |system_id| is the Widevine system ID for the type of device.
// * |public_key| is a DER-encoded PKCS#1.5 RSAPublicKey message which will
// be embedded in the generated certificate.
// * |certificate| will contain the new intermediate certificate, upon
// successful return.
// * Returns OK on success, or an appropriate error status code otherwise.
// NOTE: The generated certificate and associated private key should be stored
// securely to be reused. They should also be propagated to all
// engines, including this one, by invoking
// |AddIntermediatedrmcertificate| on all active ProvisioningEngine(s).
ProvisioningStatus GenerateDrmIntermediateCertificate(
uint32_t system_id, const std::string& public_key, std::string* certificate) const;
// Add an intermediate DRM certificate to the provisioning engine. This is
// usually done once for each supported device type.
// * |intermediate_cert| is the intermediate DRM certificate to be added.
// * |cert_private_key| is a PKCS#8 private key corresponding to
// |intermediate_cert|.
// * |cert_private_key_passphrase| is the passphrase for cert_private_key,
// if any.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus AddDrmIntermediateCertificate(
const std::string& intermediate_cert, const std::string& cert_private_key,
const std::string& cert_private_key_passphrase);
// Generate a new device DRM certificate to be provisioned.
// * |system_id| is the Widevine system ID for the type of device being
// provisioned.
// * |oem_ca_serial_number| is the oem serial number for the type of device
// being provisioned. ProvisioningEngine uses |system_id| and
// |oem_ca_serial_number| to determine if the device is valid, e.g. whether
// it has been revoked. |oem_ca_serial_number| can be empty if we do not
// care about serial number matches or not.
// * |public_key| is a DER-encoded PKCS#1.5 RSAPublicKey message which will
// be embedded in the generated certificate.
// * |certificate_serial_number| is a binary std::string to be used as the
// generated DRM certificate serial number.
// * |certificate| will contain, upon successful return the generated
// certificate.
// * Returns OK on success, or an appropriate error status code otherwise.
// Virtual for mocking.
virtual ProvisioningStatus GenerateDeviceDrmCertificate(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& public_key, const std::string& certificate_serial_number,
std::string* certificate) const;
// Internal version of the method above. Allows specifying |provider_id|.
virtual ProvisioningStatus GenerateProviderDeviceDrmCertificate(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& provider_id, const std::string& public_key,
const std::string& certificate_serial_number, std::string* certificate) const;
// Get the device info for the given |system_id|.
std::shared_ptr<ProvisionedDeviceInfo> GetDeviceInfo(
uint32_t system_id) const;
// Returns the service private key.
const RsaPrivateKey* service_private_key() const {
return service_private_key_.get();
}
const OemDeviceCert& oem_device_cert() const { return oem_device_cert_; }
const std::string& secret_spoid_sauce() const { return secret_spoid_sauce_; }
private:
friend class ProvisioningEngineImplTest;
ProvisioningEngineImpl(const ProvisioningEngineImpl&) = delete;
ProvisioningEngineImpl& operator=(const ProvisioningEngineImpl&) = delete;
// Load DRM root public key with type |certificate_type|.
bool LoadDrmRootPublicKey(CertificateType certificate_type);
// Check device status.
// If |oem_ca_serial_number| is empty, we do not care whether serial number
// matches or not.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus CheckDeviceStatus(
uint32_t system_id, const std::string& oem_ca_serial_number) const;
// Inject rsa_key_factory for testing.
void set_rsa_key_factory(std::unique_ptr<RsaKeyFactory> rsa_key_factory) {
rsa_key_factory_ = std::move(rsa_key_factory);
}
std::unique_ptr<RsaKeyFactory> rsa_key_factory_;
std::unique_ptr<RsaPublicKey> root_public_key_;
std::unique_ptr<RsaPublicKey> service_public_key_;
std::unique_ptr<RsaPrivateKey> service_private_key_;
SignedDrmDeviceCertificate signed_provisioning_cert_;
std::unique_ptr<RsaPublicKey> provisioning_public_key_;
std::unique_ptr<RsaPrivateKey> provisioning_private_key_;
std::string secret_spoid_sauce_;
OemDeviceCert oem_device_cert_;
mutable Mutex mutex_;
// POSIX time, in seconds, when the list would be expired.
uint32_t certificate_expiration_seconds_utc_ GUARDED_BY(mutex_) = 0;
// Maps with system_id as the key.
std::map<uint32_t, DeviceCertificateStatus> certificate_status_map_
GUARDED_BY(mutex_);
struct IntermediateCertificateInfo {
SignedDrmDeviceCertificate signed_drm_certificate;
std::shared_ptr<ProvisionedDeviceInfo> device_info;
std::shared_ptr<RsaPrivateKey> private_key;
};
std::map<uint32_t, IntermediateCertificateInfo> intermediate_certs_info_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_PROVISIONING_ENGINE_IMPL_H_

View File

@@ -0,0 +1,783 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
#include <time.h>
#include <memory>
#include "glog/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "common/mock_rsa_key.h"
#include "provisioning_sdk/public/certificate_type.h"
using ::testing::_;
using ::testing::ByMove;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::StrEq;
namespace {
const int kSystemId = 100;
const int kExpirationPeriodSeconds = 3600;
const int kInfiniteExpirationPeriodSeconds = 0;
const char kEmptyOemSerialNumber[] = "";
const char kSecretSauce[] = "Twas bryllyg, and ye slythy toves";
const char kCertificateSerialNumber[] = "certificate_serial_number";
const char kOemSerialNumber0[] = "oem_serial_number_0";
const char kOemSerialNumber1[] = "oem_serial_number_1";
const char kDevicePublicKey[] = "device_public_key";
const char kSignature[] = "mock_signature";
const char kIntermediatePrivateKey[] = "intermediate_private_key";
const char kIntermediatePrivateKeyPassphrase[] =
"intermediate_private_key_passphrase";
const char kIntermediatePublicKey[] = "intermediate_public_key";
const char kServicePrivateKey[] = "service_private_key";
const char kServicePrivateKeyPassphrase[] = "service_private_key_phassphrase";
const char kServiceDrmCertificate[] = "service_drm_certificate";
const char kProvisioningDrmCertificate[] = "provisioning_drm_certificate";
const char kProvisioningPrivateKey[] = "provisioning_private_key";
const char kProvisioningPrivateKeyPassphrase[] =
"provisioning_private_key_phassphrase";
const char kProvisioningPublicKey[] = "provisioning_public_key";
const char kProvisioningSignature[] = "provisioning_signature";
// A simple std::string concatenation function. This assumes i within [0, 9].
std::string StrCat(const std::string& in, int i) {
DCHECK_LE(i, 9);
DCHECK_GE(i, 0);
std::string out = in + "0";
out[out.size() - 1] += i;
return out;
}
} // namespace
namespace widevine {
class ProvisioningEngineImplTest : public ::testing::Test {
protected:
ProvisioningEngineImplTest() {
mock_rsa_key_factory_ = new MockRsaKeyFactory;
engine_impl_.set_rsa_key_factory(
std::unique_ptr<RsaKeyFactory>(mock_rsa_key_factory_));
}
ProvisioningStatus CheckDeviceStatus(uint32_t system_id,
const std::string& oem_ca_serial_number) {
return engine_impl_.CheckDeviceStatus(system_id, oem_ca_serial_number);
}
ProvisioningEngineImpl engine_impl_;
MockRsaKeyFactory* mock_rsa_key_factory_ = nullptr;
};
TEST_F(ProvisioningEngineImplTest, InvalidCertType) {
CertificateType invalid_certificate = static_cast<CertificateType>(100);
EXPECT_EQ(
INVALID_CERTIFICATE_TYPE,
engine_impl_.Initialize(
invalid_certificate, kServiceDrmCertificate, kServicePrivateKey,
kServicePrivateKeyPassphrase, kProvisioningDrmCertificate,
kProvisioningPrivateKey, kProvisioningPrivateKeyPassphrase,
kSecretSauce));
}
class ProvisioningEngineImplServiceTest : public ProvisioningEngineImplTest {
protected:
void SetUp() override {
mock_root_public_key_ = new MockRsaPublicKey();
EXPECT_CALL(*mock_rsa_key_factory_, CreateFromPkcs1PublicKey(_))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_root_public_key_))));
service_cert_.set_public_key("service_public_key");
service_cert_.set_type(DrmDeviceCertificate::SERVICE);
signed_service_cert_.set_drm_certificate(service_cert_.SerializeAsString());
signed_service_cert_.set_signature("service_signature");
}
ProvisioningStatus Initialize(const std::string& service_drm_certificate) {
return engine_impl_.Initialize(
kCertTesting, service_drm_certificate, kServicePrivateKey,
kServicePrivateKeyPassphrase, kProvisioningDrmCertificate,
kProvisioningPrivateKey, kProvisioningPrivateKeyPassphrase,
kSecretSauce);
}
DrmDeviceCertificate service_cert_;
SignedDrmDeviceCertificate signed_service_cert_;
MockRsaPublicKey* mock_root_public_key_;
};
TEST_F(ProvisioningEngineImplServiceTest, Empty) {
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE, Initialize(""));
}
TEST_F(ProvisioningEngineImplServiceTest, MissingDeviceCert) {
signed_service_cert_.clear_drm_certificate();
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, MissingSignature) {
signed_service_cert_.clear_signature();
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, SignatureVerificationFailure) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(StrEq(service_cert_.SerializeAsString()),
"service_signature"))
.WillOnce(Return(false));
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, InvalidDeviceCertType) {
service_cert_.set_type(DrmDeviceCertificate::PROVISIONER);
signed_service_cert_.set_drm_certificate(service_cert_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(StrEq(service_cert_.SerializeAsString()),
"service_signature"))
.WillOnce(Return(true));
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, InvaidPublicKey) {
EXPECT_CALL(*mock_root_public_key_, VerifySignature(_, "service_signature"))
.WillOnce(Return(true));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey("service_public_key"))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, InvalidPrivateKey) {
EXPECT_CALL(*mock_root_public_key_, VerifySignature(_, "service_signature"))
.WillOnce(Return(true));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey("service_public_key"))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(new MockRsaPublicKey))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kServicePrivateKey,
kServicePrivateKeyPassphrase))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(INVALID_SERVICE_PRIVATE_KEY,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, MismatchPublicKeyPrivateKey) {
EXPECT_CALL(*mock_root_public_key_, VerifySignature(_, "service_signature"))
.WillOnce(Return(true));
MockRsaPublicKey* mock_rsa_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey("service_public_key"))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
MockRsaPrivateKey* mock_rsa_private_key = new MockRsaPrivateKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kServicePrivateKey,
kServicePrivateKeyPassphrase))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPrivateKey>(mock_rsa_private_key))));
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
.WillOnce(Return(false));
EXPECT_EQ(INVALID_SERVICE_PRIVATE_KEY,
Initialize(signed_service_cert_.SerializeAsString()));
}
class ProvisioningEngineImplProvTest
: public ProvisioningEngineImplServiceTest {
protected:
void SetUp() override {
ProvisioningEngineImplServiceTest::SetUp();
// Service certificate expectations.
EXPECT_CALL(*mock_root_public_key_, VerifySignature(_, "service_signature"))
.WillOnce(Return(true));
mock_service_public_key_ = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey("service_public_key"))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_service_public_key_))));
mock_service_private_key_ = new MockRsaPrivateKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kServicePrivateKey,
kServicePrivateKeyPassphrase))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(mock_service_private_key_))));
EXPECT_CALL(*mock_service_public_key_, MatchesPrivateKey(_))
.WillOnce(Return(true));
prov_cert_.set_public_key(kProvisioningPublicKey);
prov_cert_.set_type(DrmDeviceCertificate::PROVISIONER);
signed_prov_cert_.set_drm_certificate(prov_cert_.SerializeAsString());
signed_prov_cert_.set_signature(kProvisioningSignature);
}
ProvisioningStatus Initialize(const std::string& provisioning_drm_certificate) {
return engine_impl_.Initialize(
kCertTesting, signed_service_cert_.SerializeAsString(),
kServicePrivateKey, kServicePrivateKeyPassphrase,
provisioning_drm_certificate, kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase, "spoid_secret_sauce");
}
DrmDeviceCertificate prov_cert_;
SignedDrmDeviceCertificate signed_prov_cert_;
MockRsaPublicKey* mock_service_public_key_ = nullptr;
MockRsaPrivateKey* mock_service_private_key_ = nullptr;
};
TEST_F(ProvisioningEngineImplProvTest, Empty) {
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE, Initialize(""));
}
TEST_F(ProvisioningEngineImplProvTest, MissingDeviceCert) {
signed_prov_cert_.clear_drm_certificate();
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, MissingSignature) {
signed_prov_cert_.clear_signature();
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, SignatureVerificationFailure) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(StrEq(prov_cert_.SerializeAsString()),
kProvisioningSignature))
.WillOnce(Return(false));
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, InvalidDeviceCertType) {
prov_cert_.set_type(DrmDeviceCertificate::SERVICE);
signed_prov_cert_.set_drm_certificate(prov_cert_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(StrEq(prov_cert_.SerializeAsString()),
kProvisioningSignature))
.WillOnce(Return(true));
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, InvaidPublicKey) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, kProvisioningSignature))
.WillOnce(Return(true));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kProvisioningPublicKey))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, InvalidPrivateKey) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, kProvisioningSignature))
.WillOnce(Return(true));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kProvisioningPublicKey))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(new MockRsaPublicKey))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(INVALID_PROVISIONER_PRIVATE_KEY,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, MismatchPublicKeyPrivateKey) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, kProvisioningSignature))
.WillOnce(Return(true));
MockRsaPublicKey* mock_rsa_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kProvisioningPublicKey))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
MockRsaPrivateKey* mock_rsa_private_key = new MockRsaPrivateKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPrivateKey>(mock_rsa_private_key))));
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
.WillOnce(Return(false));
EXPECT_EQ(INVALID_PROVISIONER_PRIVATE_KEY,
Initialize(signed_prov_cert_.SerializeAsString()));
}
class ProvisioningEngineImplGeneralTest
: public ProvisioningEngineImplProvTest {
protected:
void SetUp() override {
ProvisioningEngineImplProvTest::SetUp();
// Provisioning certificate expectations.
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, kProvisioningSignature))
.WillOnce(Return(true));
mock_prov_public_key_ = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kProvisioningPublicKey))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_prov_public_key_))));
mock_prov_private_key_ = new MockRsaPrivateKey;
EXPECT_CALL(
*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(mock_prov_private_key_))));
EXPECT_CALL(*mock_prov_public_key_, MatchesPrivateKey(_))
.WillOnce(Return(true));
ASSERT_EQ(OK, ProvisioningEngineImplProvTest::Initialize(
signed_prov_cert_.SerializeAsString()));
// Setup certificate status list.
cert_status_list_.set_creation_time_seconds(time(nullptr));
for (int i = 0; i < 2; ++i) {
DeviceCertificateStatus* cert_status =
cert_status_list_.add_certificate_status();
cert_status->set_oem_serial_number(StrCat("oem_serial_number_", i));
ProvisionedDeviceInfo* device_info = cert_status->mutable_device_info();
device_info->set_system_id(kSystemId + i);
device_info->set_model(StrCat("model_", i));
}
cert_status_list_.mutable_certificate_status(0)->set_status(
DeviceCertificateStatus::VALID);
cert_status_list_.mutable_certificate_status(1)->set_status(
DeviceCertificateStatus::REVOKED);
SignedCertificateStatusList signed_cert_status_list;
signed_cert_status_list.set_certificate_status_list(
cert_status_list_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(
StrEq(signed_cert_status_list.certificate_status_list()),
"cert_status_list_signature"))
.WillOnce(Return(true));
signed_cert_status_list.set_signature("cert_status_list_signature");
ASSERT_EQ(OK, engine_impl_.SetCertificateStatusList(
signed_cert_status_list.SerializeAsString(),
kExpirationPeriodSeconds));
// Setup a DrmDeviceCertificate to be used later.
intermediate_cert_.set_type(DrmDeviceCertificate::DRM_INTERMEDIATE);
intermediate_cert_.set_system_id(kSystemId);
intermediate_cert_.set_public_key(kIntermediatePublicKey);
signed_intermediate_cert_.set_drm_certificate(
intermediate_cert_.SerializeAsString());
signed_intermediate_cert_.set_signature(kSignature);
}
MockRsaPublicKey* mock_prov_public_key_ = nullptr;
MockRsaPrivateKey* mock_prov_private_key_ = nullptr;
DeviceCertificateStatusList cert_status_list_;
DrmDeviceCertificate intermediate_cert_;
SignedDrmDeviceCertificate signed_intermediate_cert_;
};
TEST_F(ProvisioningEngineImplGeneralTest, InvalidCertificateStatusList) {
EXPECT_EQ(INVALID_STATUS_LIST, engine_impl_.SetCertificateStatusList(
"", kExpirationPeriodSeconds));
EXPECT_EQ(INVALID_STATUS_LIST,
engine_impl_.SetCertificateStatusList(
"invalid_certificate_status_list", kExpirationPeriodSeconds));
}
TEST_F(ProvisioningEngineImplGeneralTest,
CertificateStatusListIncorrectSignature) {
SignedCertificateStatusList signed_cert_status_list;
signed_cert_status_list.set_certificate_status_list(
cert_status_list_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, "cert_status_list_signature"))
.WillOnce(Return(false));
signed_cert_status_list.set_signature("cert_status_list_signature");
ASSERT_EQ(INVALID_STATUS_LIST,
engine_impl_.SetCertificateStatusList(
signed_cert_status_list.SerializeAsString(),
kExpirationPeriodSeconds));
}
TEST_F(ProvisioningEngineImplGeneralTest, GetDeviceInfoAndCheckDeviceStatus) {
EXPECT_EQ(OK, CheckDeviceStatus(kSystemId, kEmptyOemSerialNumber));
auto device_info = engine_impl_.GetDeviceInfo(kSystemId);
ASSERT_NE(nullptr, device_info);
EXPECT_EQ("model_0", device_info->model());
EXPECT_EQ(DEVICE_REVOKED,
CheckDeviceStatus(kSystemId + 1, kEmptyOemSerialNumber));
// We can still query device info for revoked device.
device_info = engine_impl_.GetDeviceInfo(kSystemId + 1);
ASSERT_NE(nullptr, device_info);
EXPECT_EQ("model_1", device_info->model());
EXPECT_EQ(UNKNOWN_SYSTEM_ID,
CheckDeviceStatus(kSystemId + 2, kEmptyOemSerialNumber));
EXPECT_EQ(nullptr, engine_impl_.GetDeviceInfo(kSystemId + 2));
}
TEST_F(ProvisioningEngineImplGeneralTest, UpdateCertificateStatusList) {
cert_status_list_.mutable_certificate_status(0)->set_status(
DeviceCertificateStatus::REVOKED);
DeviceCertificateStatus* cert_status =
cert_status_list_.add_certificate_status();
ProvisionedDeviceInfo* device_info = cert_status->mutable_device_info();
device_info->set_system_id(kSystemId + 2);
device_info->set_model("model_2");
SignedCertificateStatusList signed_cert_status_list;
signed_cert_status_list.set_certificate_status_list(
cert_status_list_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, "cert_status_list_signature"))
.WillOnce(Return(true));
signed_cert_status_list.set_signature("cert_status_list_signature");
ASSERT_EQ(OK, engine_impl_.SetCertificateStatusList(
signed_cert_status_list.SerializeAsString(),
kInfiniteExpirationPeriodSeconds));
// Now device with system id = kSystemId is revoked.
EXPECT_EQ(DEVICE_REVOKED,
CheckDeviceStatus(kSystemId, kEmptyOemSerialNumber));
EXPECT_EQ("model_0", engine_impl_.GetDeviceInfo(kSystemId)->model());
EXPECT_EQ(DEVICE_REVOKED,
CheckDeviceStatus(kSystemId + 1, kEmptyOemSerialNumber));
EXPECT_EQ("model_1", engine_impl_.GetDeviceInfo(kSystemId + 1)->model());
EXPECT_EQ(OK, CheckDeviceStatus(kSystemId + 2, kEmptyOemSerialNumber));
EXPECT_EQ("model_2", engine_impl_.GetDeviceInfo(kSystemId + 2)->model());
}
TEST_F(ProvisioningEngineImplGeneralTest,
GenerateDrmIntermediateCertificateInvalidPublicKey) {
std::string drm_certificate;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kIntermediatePublicKey))
.WillOnce(Return(ByMove(nullptr)));
std::string certificate;
ASSERT_EQ(INVALID_INTERMEDIATE_PUBLIC_KEY,
engine_impl_.GenerateDrmIntermediateCertificate(
kSystemId, kIntermediatePublicKey, &certificate));
}
TEST_F(ProvisioningEngineImplGeneralTest, GenerateDrmIntermediateCertificate) {
std::string drm_certificate;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kIntermediatePublicKey))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(new MockRsaPublicKey))));
EXPECT_CALL(*mock_prov_private_key_, GenerateSignature(_, _))
.WillOnce(DoAll(SaveArg<0>(&drm_certificate),
SetArgPointee<1>(kSignature), Return(true)));
std::string certificate;
ASSERT_EQ(OK, engine_impl_.GenerateDrmIntermediateCertificate(
kSystemId, kIntermediatePublicKey, &certificate));
SignedDrmDeviceCertificate signed_drm_cert_proto;
ASSERT_TRUE(signed_drm_cert_proto.ParseFromString(certificate));
EXPECT_EQ(drm_certificate, signed_drm_cert_proto.drm_certificate());
EXPECT_EQ(kSignature, signed_drm_cert_proto.signature());
EXPECT_EQ(signed_prov_cert_.SerializeAsString(),
signed_drm_cert_proto.signer().SerializeAsString());
DrmDeviceCertificate drm_cert_proto;
ASSERT_TRUE(drm_cert_proto.ParseFromString(drm_certificate));
EXPECT_EQ(DrmDeviceCertificate::DRM_INTERMEDIATE, drm_cert_proto.type());
EXPECT_NE("", drm_cert_proto.serial_number());
EXPECT_EQ(kSystemId, drm_cert_proto.system_id());
EXPECT_EQ(kIntermediatePublicKey, drm_cert_proto.public_key());
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateInvalidCert) {
EXPECT_EQ(INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
"", kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
"invalid_intermediate_cert", kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateIncorrectCertType) {
intermediate_cert_.set_type(DrmDeviceCertificate::DRM_USER_DEVICE);
signed_intermediate_cert_.set_drm_certificate(
intermediate_cert_.SerializeAsString());
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_EQ(
INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateMissingSystemId) {
intermediate_cert_.clear_system_id();
signed_intermediate_cert_.set_drm_certificate(
intermediate_cert_.SerializeAsString());
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_EQ(
UNKNOWN_SYSTEM_ID,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateRevokedCert) {
intermediate_cert_.set_system_id(kSystemId + 1);
signed_intermediate_cert_.set_drm_certificate(
intermediate_cert_.SerializeAsString());
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_EQ(DEVICE_REVOKED, engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateInvalidPublicKey) {
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kIntermediatePublicKey))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(
INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateInvalidPrivateKey) {
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kIntermediatePublicKey))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(new MockRsaPublicKey))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(
INVALID_INTERMEDIATE_PRIVATE_KEY,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateMismatchPublicPrivateKey) {
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
MockRsaPublicKey* mock_intermediate_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kIntermediatePublicKey))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_intermediate_public_key))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
EXPECT_CALL(*mock_intermediate_public_key, MatchesPrivateKey(_))
.WillOnce(Return(false));
EXPECT_EQ(
INVALID_INTERMEDIATE_PRIVATE_KEY,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateSuccess) {
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
MockRsaPublicKey* mock_intermediate_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kIntermediatePublicKey))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_intermediate_public_key))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
EXPECT_CALL(*mock_intermediate_public_key, MatchesPrivateKey(_))
.WillOnce(Return(true));
EXPECT_EQ(OK, engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest, ExpiredCertificateStatusList) {
cert_status_list_.set_creation_time_seconds(time(nullptr) -
kExpirationPeriodSeconds - 1);
SignedCertificateStatusList signed_cert_status_list;
signed_cert_status_list.set_certificate_status_list(
cert_status_list_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, "cert_status_list_signature"))
.WillOnce(Return(true));
signed_cert_status_list.set_signature("cert_status_list_signature");
ASSERT_EQ(OK, engine_impl_.SetCertificateStatusList(
signed_cert_status_list.SerializeAsString(),
kExpirationPeriodSeconds));
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_EQ(
STATUS_LIST_EXPIRED,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
GenerateDeviceDrmCertificateRevokedDevice) {
std::string certificate;
EXPECT_EQ(DEVICE_REVOKED,
engine_impl_.GenerateDeviceDrmCertificate(
kSystemId + 1, kOemSerialNumber1, kDevicePublicKey,
kCertificateSerialNumber, &certificate));
}
TEST_F(ProvisioningEngineImplGeneralTest,
GenerateDeviceDrmCertificateWithMismatchingOemSerialNumber) {
std::string certificate;
// If oem serial number does not match, consider as revoked.
EXPECT_EQ(DEVICE_REVOKED,
engine_impl_.GenerateDeviceDrmCertificate(
kSystemId, kOemSerialNumber1, kDevicePublicKey,
kCertificateSerialNumber, &certificate));
}
TEST_F(ProvisioningEngineImplGeneralTest,
GenerateDeviceDrmCertificateWithoutIntermediateCert) {
std::string certificate;
EXPECT_EQ(MISSING_DRM_INTERMEDIATE_CERT,
engine_impl_.GenerateDeviceDrmCertificate(
kSystemId, kOemSerialNumber0, kDevicePublicKey,
kCertificateSerialNumber, &certificate));
}
TEST_F(ProvisioningEngineImplGeneralTest,
GenerateDeviceDrmCertificate) {
// Add Intermediate certificate.
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
MockRsaPublicKey* mock_intermediate_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kIntermediatePublicKey))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_intermediate_public_key))));
MockRsaPrivateKey* mock_intermediate_private_key = new MockRsaPrivateKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase))
.WillOnce(Return(ByMove(
std::unique_ptr<RsaPrivateKey>(mock_intermediate_private_key))));
EXPECT_CALL(*mock_intermediate_public_key, MatchesPrivateKey(_))
.WillOnce(Return(true));
EXPECT_EQ(OK, engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase));
// Intermediate private key expectation.
std::string drm_certificate;
EXPECT_CALL(*mock_intermediate_private_key, GenerateSignature(_, _))
.WillOnce(DoAll(SaveArg<0>(&drm_certificate),
SetArgPointee<1>(kSignature), Return(true)));
std::string certificate;
EXPECT_EQ(OK, engine_impl_.GenerateDeviceDrmCertificate(
kSystemId, kOemSerialNumber0, kDevicePublicKey,
kCertificateSerialNumber, &certificate));
SignedDrmDeviceCertificate signed_drm_cert_proto;
ASSERT_TRUE(signed_drm_cert_proto.ParseFromString(certificate));
EXPECT_EQ(drm_certificate, signed_drm_cert_proto.drm_certificate());
EXPECT_EQ(kSignature, signed_drm_cert_proto.signature());
EXPECT_THAT(signed_intermediate_cert_.SerializeAsString(),
signed_drm_cert_proto.signer().SerializeAsString());
DrmDeviceCertificate drm_cert_proto;
ASSERT_TRUE(drm_cert_proto.ParseFromString(drm_certificate));
EXPECT_EQ(DrmDeviceCertificate::DRM_USER_DEVICE, drm_cert_proto.type());
EXPECT_EQ(kCertificateSerialNumber, drm_cert_proto.serial_number());
EXPECT_EQ(kSystemId, drm_cert_proto.system_id());
EXPECT_EQ(kDevicePublicKey, drm_cert_proto.public_key());
}
} // namespace widevine

View File

@@ -0,0 +1,256 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/provisioning_session_impl.h"
#include <stddef.h>
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "common/aes_cbc_util.h"
#include "common/random_util.h"
#include "common/rsa_key.h"
#include "common/sha_util.h"
#include "provisioning_sdk/public/provisioning_status.h"
DEFINE_int32(provisioning_log_every_n, 1,
"parameter for LOG_EVERY_N to help abate log spamming.");
#define LOG_EVERY_N_WITH_PROTO(message, proto) \
LOG_EVERY_N(WARNING, FLAGS_provisioning_log_every_n) \
<< (message) << " [proto: " << (proto).ShortDebugString() << "]"
namespace widevine {
ProvisioningSessionImpl::ProvisioningSessionImpl(
const ProvisioningEngineImpl& engine, const OemDeviceCert& oem_device_cert,
const RsaPrivateKey& service_private_key)
: engine_(engine),
oem_device_cert_(oem_device_cert),
service_private_key_(service_private_key),
rsa_key_factory_(new RsaKeyFactory) {}
ProvisioningSessionImpl::~ProvisioningSessionImpl() {}
ProvisioningStatus ProvisioningSessionImpl::Initialize(
const std::string& device_public_key, const std::string& device_private_key) {
auto rsa_public_key =
rsa_key_factory_->CreateFromPkcs1PublicKey(device_public_key);
if (!rsa_public_key) return INVALID_DEVICE_PUBLIC_KEY;
auto rsa_private_key =
rsa_key_factory_->CreateFromPkcs1PrivateKey(device_private_key);
if (!rsa_private_key) return INVALID_DEVICE_PRIVATE_KEY;
if (!rsa_public_key->MatchesPrivateKey(*rsa_private_key)) {
LOG(WARNING) << "Device public key and private key do not match.";
return INVALID_DEVICE_PRIVATE_KEY;
}
device_public_key_ = device_public_key;
device_private_key_ = device_private_key;
return OK;
}
ProvisioningStatus ProvisioningSessionImpl::ProcessMessage(
const std::string& message, std::string* response) {
SignedProvisioningMessage signed_request;
ProvisioningRequest request;
if (!ValidateAndDeserializeRequest(message, &signed_request, &request))
return INVALID_REQUEST_MESSAGE;
ClientIdentification client_id;
if (request.has_encrypted_client_id()) {
if (!DecryptClientIdentification(request.encrypted_client_id(), &client_id))
return INVALID_REQUEST_MESSAGE;
} else {
DCHECK(request.has_client_id());
client_id.Swap(request.mutable_client_id());
}
if (client_id.type() != ClientIdentification::OEM_DEVICE_CERTIFICATE) {
LOG_EVERY_N_WITH_PROTO("Invalid client_id type", client_id);
return INVALID_REQUEST_MESSAGE;
}
if (client_id.token().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing client_id.token", client_id);
return INVALID_REQUEST_MESSAGE;
}
std::unique_ptr<RsaPublicKey> cert_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
if (!oem_device_cert_.VerifyCertificateChain(client_id.token(),
&cert_public_key, &system_id,
&oem_ca_serial_number)) {
LOG_EVERY_N_WITH_PROTO("Invalid token", client_id);
return INVALID_REQUEST_MESSAGE;
}
if (!cert_public_key->VerifySignature(signed_request.message(),
signed_request.signature())) {
LOG_EVERY_N_WITH_PROTO("Signature verification failed", client_id);
return INVALID_REQUEST_MESSAGE;
}
// Save device_info for query later.
device_info_ = engine_.GetDeviceInfo(system_id);
std::string certificate_serial_number;
if (request.has_spoid()) {
certificate_serial_number = request.spoid();
} else {
// Generate stable serial number.
const std::string stable_data(client_id.token() + request.stable_id() +
request.provider_id() +
engine_.secret_spoid_sauce());
const std::string hash = Sha256_Hash(stable_data);
const size_t kCertificateSerialNumberSize = 16;
certificate_serial_number = hash.substr(0, kCertificateSerialNumberSize);
}
ProvisioningResponse provisioning_response;
ProvisioningStatus status = GenerateProvisioningResponse(
system_id, oem_ca_serial_number, request.provider_id(),
certificate_serial_number, *cert_public_key, &provisioning_response);
if (status != OK) return status;
provisioning_response.set_nonce(request.nonce());
// Sign the response.
SignedProvisioningMessage signed_message;
if (!provisioning_response.SerializeToString(
signed_message.mutable_message())) {
LOG(WARNING) << "Error serializing ProvisioningResponse.";
return INTERNAL_ERROR;
}
if (!service_private_key_.GenerateSignature(
signed_message.message(), signed_message.mutable_signature())) {
LOG(WARNING) << "Failed to sign ProvisioningResponse.";
return INTERNAL_ERROR;
}
if (!signed_message.SerializeToString(response)) {
LOG(WARNING) << "Error serializing SignedProvisioningMessage.";
return INTERNAL_ERROR;
}
return OK;
}
bool ProvisioningSessionImpl::ValidateAndDeserializeRequest(
const std::string& message, SignedProvisioningMessage* signed_request,
ProvisioningRequest* request) const {
if (!signed_request->ParseFromString(message)) {
LOG_EVERY_N(WARNING, FLAGS_provisioning_log_every_n)
<< "Failed to parse SignedProvisioningMessage.";
return false;
}
VLOG(1) << "signed_request: " << signed_request->ShortDebugString();
if (signed_request->message().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing message", *signed_request);
return false;
}
if (signed_request->signature().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing signature", *signed_request);
return false;
}
if (!request->ParseFromString(signed_request->message())) {
LOG_EVERY_N_WITH_PROTO("Failed to parse ProvisioningRequest",
*signed_request);
return false;
}
if (request->has_encrypted_client_id()) {
const EncryptedClientIdentification& encrypted_client_id =
request->encrypted_client_id();
if (encrypted_client_id.encrypted_client_id().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing encrypted_client_id",
encrypted_client_id);
return false;
}
if (encrypted_client_id.encrypted_client_id_iv().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing encrypted_client_id_iv",
encrypted_client_id);
return false;
}
if (encrypted_client_id.encrypted_privacy_key().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing encrypted_privacy_key",
encrypted_client_id);
return false;
}
} else if (!request->has_client_id()) {
LOG_EVERY_N_WITH_PROTO("Missing clear_or_encrypted_client_id", *request);
return false;
}
const size_t kMinimumRequiredNonceLength = 4;
if (request->nonce().size() < kMinimumRequiredNonceLength) {
LOG_EVERY_N_WITH_PROTO("Missing or invalid nonce", *request);
return false;
}
return true;
}
bool ProvisioningSessionImpl::DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
std::string privacy_key;
if (!service_private_key_.Decrypt(encrypted_client_id.encrypted_privacy_key(),
&privacy_key)) {
LOG_EVERY_N_WITH_PROTO("Failed to decrypt encrypted_privacy_key",
encrypted_client_id);
return false;
}
std::string serialized_client_id(crypto_util::DecryptAesCbc(
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
encrypted_client_id.encrypted_client_id()));
if (serialized_client_id.empty()) {
LOG_EVERY_N_WITH_PROTO("Failed to decrypt client_id", encrypted_client_id);
return false;
}
if (!client_id->ParseFromString(serialized_client_id)) {
LOG_EVERY_N_WITH_PROTO("Failed to parse client_id", encrypted_client_id);
return false;
}
return true;
}
ProvisioningStatus ProvisioningSessionImpl::GenerateProvisioningResponse(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& provider_id, const std::string& certificate_serial_number,
const RsaPublicKey& cert_public_key, ProvisioningResponse* response) {
ProvisioningStatus status = engine_.GenerateProviderDeviceDrmCertificate(
system_id, oem_ca_serial_number, provider_id, device_public_key_,
certificate_serial_number, response->mutable_device_certificate());
if (status != OK) return status;
const size_t kAesKeySize = 16;
const size_t kIvSize = 16;
// Encrypt private key.
std::string message_key;
if (!RandomBytes(kAesKeySize, &message_key)) {
LOG(WARNING) << "Failed to generate message_key.";
return INTERNAL_ERROR;
}
std::string iv;
if (!RandomBytes(kIvSize, &iv)) {
LOG(WARNING) << "Failed to generate iv.";
return INTERNAL_ERROR;
}
response->set_device_rsa_key_iv(iv);
response->set_device_rsa_key(
crypto_util::EncryptAesCbc(message_key, iv, device_private_key_));
if (response->device_rsa_key().empty()) {
LOG(WARNING) << "Failed to encrypt device_rsa_key";
return INTERNAL_ERROR;
}
if (!cert_public_key.Encrypt(message_key, response->mutable_wrapping_key())) {
LOG(WARNING) << "Failed to encrypt wrapping_key";
return INTERNAL_ERROR;
}
return OK;
}
} // namespace widevine

View File

@@ -0,0 +1,88 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// ProvisioningSession internal implementation.
#ifndef PROVISIONING_SDK_INTERNAL_PROVISIONING_SESSION_IMPL_H_
#define PROVISIONING_SDK_INTERNAL_PROVISIONING_SESSION_IMPL_H_
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
#include "provisioning_sdk/public/provisioning_status.h"
#include "protos/public/certificate_provisioning.pb.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_certificate.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
namespace widevine {
class ProvisioningSessionImpl {
public:
ProvisioningSessionImpl(const ProvisioningEngineImpl& engine,
const OemDeviceCert& oem_device_cert,
const RsaPrivateKey& service_private_key);
~ProvisioningSessionImpl();
// Initialize provisioning session with given public key and private key.
ProvisioningStatus Initialize(const std::string& device_public_key,
const std::string& device_private_key);
// Process a message from the client device.
// * |message| is the message received from the client device.
// * |response| will contain, upon successful return, a message to be sent
// back to the client device as a response to |message|.
// Returns OK if successful, or an appropriate error status code otherwise.
ProvisioningStatus ProcessMessage(const std::string& message, std::string* response);
// * Returns a ProvisioneddeviceInfo message containing information about the
// type of device being provisioned. May return nullptr.
const ProvisionedDeviceInfo* GetDeviceInfo() const {
return device_info_.get();
}
private:
friend class ProvisioningSessionImplTest;
ProvisioningSessionImpl(const ProvisioningSessionImpl&) = delete;
ProvisioningSessionImpl& operator=(const ProvisioningSessionImpl&) = delete;
bool ValidateAndDeserializeRequest(const std::string& message,
SignedProvisioningMessage* signed_request,
ProvisioningRequest* request) const;
bool DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id);
ProvisioningStatus GenerateProvisioningResponse(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& provider_id, const std::string& certificate_serial_number,
const RsaPublicKey& cert_public_key, ProvisioningResponse* response);
// Inject rsa_key_factory for testing.
void set_rsa_key_factory(std::unique_ptr<RsaKeyFactory> rsa_key_factory) {
rsa_key_factory_ = std::move(rsa_key_factory);
}
const ProvisioningEngineImpl& engine_;
const OemDeviceCert& oem_device_cert_;
const RsaPrivateKey& service_private_key_;
std::unique_ptr<RsaKeyFactory> rsa_key_factory_;
std::string device_public_key_;
std::string device_private_key_;
std::shared_ptr<ProvisionedDeviceInfo> device_info_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_PROVISIONING_SESSION_IMPL_H_

View File

@@ -0,0 +1,426 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/provisioning_session_impl.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "common/aes_cbc_util.h"
#include "common/mock_rsa_key.h"
#include "common/sha_util.h"
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
using ::testing::_;
using ::testing::ByMove;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
namespace {
const char kEncryptedClientIdIv[] = "sixteen_bytes_iv";
const char kPrivacyKey[] = "privacy_key_16B_";
const char kProviderId[] = "testing_provider";
const char kClientToken[] = "client_id_token";
const char kDevicePublicKey[] = "device_public_key";
const char kEncryptedPrivacyKey[] = "encrypted_privacy_key";
const char kDevicePrivateKey[] = "device_private_key";
const char kWrappingKey[] = "wrapping_key";
const char kDeviceCertificate[] = "device_certificate";
const char kNonce[] = "testing_nonce";
const char kSignature[] = "generated_signature";
// Derives Stable Per-Origin IDentifiers.
std::string DeriveSpoid(const std::string& client_token,
const std::string& provider_id,
const std::string& secret_sauce) {
return widevine::Sha256_Hash(client_token + provider_id + secret_sauce)
.substr(0, 16);
}
} // namespace
namespace widevine {
class MockProvisioningEngineImpl : public ProvisioningEngineImpl {
public:
MOCK_CONST_METHOD6(GenerateProviderDeviceDrmCertificate,
ProvisioningStatus(uint32_t system_id,
const std::string& oem_ca_serial_number,
const std::string& provider_id,
const std::string& public_key,
const std::string& certificate_serial_number,
std::string* certificate));
};
class MockOemDeviceCert : public OemDeviceCert {
public:
// gmock does not support SetArgPointee on std::unique_ptr, so we have to
// workaround it with a trick.
MOCK_CONST_METHOD4(DoVerifyCertificateChain,
bool(const std::string& certificate_chain,
RsaPublicKey** leaf_public_key, uint32_t* system_id,
std::string* oem_ca_serial_number));
bool VerifyCertificateChain(const std::string& certificate_chain,
std::unique_ptr<RsaPublicKey>* leaf_public_key,
uint32_t* system_id,
std::string* oem_ca_serial_number) const override {
RsaPublicKey* raw_leaf_public_key = nullptr;
if (!DoVerifyCertificateChain(certificate_chain, &raw_leaf_public_key,
system_id, oem_ca_serial_number)) {
return false;
}
*leaf_public_key = std::unique_ptr<RsaPublicKey>(raw_leaf_public_key);
return true;
}
};
class ProvisioningSessionImplTest : public ::testing::Test {
protected:
ProvisioningSessionImplTest()
: session_impl_(mock_engine_impl_, mock_oem_device_cert_,
mock_service_private_key_) {
mock_rsa_key_factory_ = new MockRsaKeyFactory;
session_impl_.set_rsa_key_factory(
std::unique_ptr<RsaKeyFactory>(mock_rsa_key_factory_));
}
ProvisioningSessionImpl session_impl_;
MockRsaKeyFactory* mock_rsa_key_factory_ = nullptr;
MockProvisioningEngineImpl mock_engine_impl_;
MockOemDeviceCert mock_oem_device_cert_;
MockRsaPrivateKey mock_service_private_key_;
};
TEST_F(ProvisioningSessionImplTest, InitializeWithInvalidPublicKey) {
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kDevicePublicKey))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(
INVALID_DEVICE_PUBLIC_KEY,
session_impl_.Initialize(kDevicePublicKey, kDevicePrivateKey));
}
TEST_F(ProvisioningSessionImplTest, InitializeWithInvalidPrivateKey) {
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kDevicePublicKey))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(new MockRsaPublicKey))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PrivateKey(kDevicePrivateKey))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(
INVALID_DEVICE_PRIVATE_KEY,
session_impl_.Initialize(kDevicePublicKey, kDevicePrivateKey));
}
TEST_F(ProvisioningSessionImplTest, InitializeWithMismatchPublicPrivateKey) {
MockRsaPublicKey* mock_rsa_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kDevicePublicKey))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PrivateKey(kDevicePrivateKey))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
.WillOnce(Return(false));
EXPECT_EQ(
INVALID_DEVICE_PRIVATE_KEY,
session_impl_.Initialize(kDevicePublicKey, kDevicePrivateKey));
}
class ProvisioningSessionImplProcessTest : public ProvisioningSessionImplTest {
public:
void SetUp() override {
MockRsaPublicKey* mock_rsa_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kDevicePublicKey))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PrivateKey(kDevicePrivateKey))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
.WillOnce(Return(true));
ASSERT_EQ(OK, session_impl_.Initialize(kDevicePublicKey,
kDevicePrivateKey));
// Setup Provisioning Message.
client_id_.set_type(ClientIdentification::OEM_DEVICE_CERTIFICATE);
client_id_.set_token(kClientToken);
EncryptedClientIdentification* encrypted_client_id =
prov_request_.mutable_encrypted_client_id();
encrypted_client_id->set_encrypted_client_id(crypto_util::EncryptAesCbc(
kPrivacyKey, kEncryptedClientIdIv, client_id_.SerializeAsString()));
encrypted_client_id->set_encrypted_client_id_iv(kEncryptedClientIdIv);
encrypted_client_id->set_encrypted_privacy_key(kEncryptedPrivacyKey);
prov_request_.set_provider_id(kProviderId);
prov_request_.set_nonce(kNonce);
signed_prov_message_.set_message(prov_request_.SerializeAsString());
signed_prov_message_.set_signature("testing_signature");
}
ClientIdentification client_id_;
ProvisioningRequest prov_request_;
SignedProvisioningMessage signed_prov_message_;
};
TEST_F(ProvisioningSessionImplProcessTest, InvalidMessage) {
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage("invalid_message", &response));
}
TEST_F(ProvisioningSessionImplProcessTest, EmptyMessage) {
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage("", &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingMessage) {
signed_prov_message_.clear_message();
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingSignature) {
signed_prov_message_.clear_signature();
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingClientId) {
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingEncryptedClientId) {
prov_request_.mutable_encrypted_client_id()->clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingEncryptedClientIdIv) {
prov_request_.mutable_encrypted_client_id()->clear_encrypted_client_id_iv();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingEncryptedPrivacyKey) {
prov_request_.mutable_encrypted_client_id()->clear_encrypted_privacy_key();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, InvalidNonce) {
// Nonce should be at least 4 buytes.
const char kNonceWithLessThanFourBytes[] = "xx";
prov_request_.set_nonce(kNonceWithLessThanFourBytes);
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, PrivacyKeyDecryptionFailed) {
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(Return(false));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, InvalidEncryptedClientId) {
prov_request_.mutable_encrypted_client_id()->set_encrypted_client_id(
"invalid_encrypted_client_id");
signed_prov_message_.set_message(prov_request_.SerializeAsString());
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, VerifyCertificateChainFailed) {
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(Return(false));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest,
ClearClientIdVerifyCertificateChainFailed) {
*prov_request_.mutable_client_id() = client_id_;
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(Return(false));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, ClearClientIdInvalidClientIdType) {
client_id_.set_type(ClientIdentification::KEYBOX);
*prov_request_.mutable_client_id() = client_id_;
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, ClearClientIdMissingToken) {
client_id_.clear_token();
*prov_request_.mutable_client_id() = client_id_;
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, VerifySignatureFailed) {
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
MockRsaPublicKey* mock_cert_public_key = new MockRsaPublicKey;
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(mock_cert_public_key), Return(true)));
EXPECT_CALL(*mock_cert_public_key,
VerifySignature(signed_prov_message_.message(),
signed_prov_message_.signature()))
.WillOnce(Return(false));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, GenerateDeviceCertificateFailed) {
const uint32_t kSystemId = 1234;
const char kExpectedOemSerialNumber[] = "test_oem_serial_number";
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
MockRsaPublicKey* mock_cert_public_key = new MockRsaPublicKey;
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(DoAll(
SetArgPointee<1>(mock_cert_public_key), SetArgPointee<2>(kSystemId),
SetArgPointee<3>(kExpectedOemSerialNumber), Return(true)));
EXPECT_CALL(*mock_cert_public_key,
VerifySignature(signed_prov_message_.message(),
signed_prov_message_.signature()))
.WillOnce(Return(true));
EXPECT_CALL(
mock_engine_impl_,
GenerateProviderDeviceDrmCertificate(
kSystemId, kExpectedOemSerialNumber, kProviderId, kDevicePublicKey,
DeriveSpoid(kClientToken, kProviderId, ""), _))
.WillOnce(Return(INTERNAL_ERROR));
std::string response;
EXPECT_EQ(INTERNAL_ERROR,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, Success) {
const uint32_t kSystemId = 1234;
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
MockRsaPublicKey* mock_cert_public_key = new MockRsaPublicKey;
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(mock_cert_public_key),
SetArgPointee<2>(kSystemId), Return(true)));
EXPECT_CALL(*mock_cert_public_key,
VerifySignature(signed_prov_message_.message(),
signed_prov_message_.signature()))
.WillOnce(Return(true));
EXPECT_CALL(mock_engine_impl_,
GenerateProviderDeviceDrmCertificate(kSystemId, _, _,
kDevicePublicKey, _, _))
.WillOnce(DoAll(SetArgPointee<5>(kDeviceCertificate), Return(OK)));
std::string message_key;
EXPECT_CALL(*mock_cert_public_key, Encrypt(_, _))
.WillOnce(DoAll(SaveArg<0>(&message_key),
SetArgPointee<1>(kWrappingKey), Return(true)));
std::string message;
EXPECT_CALL(mock_service_private_key_, GenerateSignature(_, _))
.WillOnce(DoAll(SaveArg<0>(&message),
SetArgPointee<1>(kSignature), Return(true)));
std::string response;
ASSERT_EQ(OK, session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
// Verify the response.
SignedProvisioningMessage signed_prov_message;
ASSERT_TRUE(signed_prov_message.ParseFromString(response));
EXPECT_EQ(message, signed_prov_message.message());
EXPECT_EQ(kSignature, signed_prov_message.signature());
ProvisioningResponse prov_response;
ASSERT_TRUE(prov_response.ParseFromString(message));
EXPECT_EQ(
kDevicePrivateKey,
crypto_util::DecryptAesCbc(message_key, prov_response.device_rsa_key_iv(),
prov_response.device_rsa_key()));
EXPECT_EQ(kDeviceCertificate, prov_response.device_certificate());
EXPECT_EQ(kNonce, prov_response.nonce());
EXPECT_EQ(kWrappingKey, prov_response.wrapping_key());
}
} // namespace widevine

View File

@@ -0,0 +1,84 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
# Build file for provisioning 3.0 SDK.
package(
default_visibility = ["//visibility:public"],
)
# Defines the common copts for cc_library targets. The main option here is
# -fvisibility=default, which exports symbols from the public APIs in the shared
# library.
# Note that the shared library should be built with -fvisibility=hidden.
PUBLIC_COPTS = ["-fvisibility=default"]
cc_binary(
name = "libprovisioning_sdk.so",
linkshared = 1,
deps = [":provisioning_engine"],
)
cc_library(
name = "libprovisioning_sdk",
srcs = [":libprovisioning_sdk.so"],
hdrs = glob(["*.h"]),
)
cc_library(
name = "provisioning_engine",
srcs = ["provisioning_engine.cc"],
hdrs = ["provisioning_engine.h"],
copts = PUBLIC_COPTS,
deps = [
":certificate_type",
":provisioning_session",
":provisioning_status",
"//base",
"//common:rsa_key",
"//provisioning_sdk/internal:provisioning_engine_impl",
"//provisioning_sdk/internal:provisioning_session_impl",
],
)
cc_test(
name = "provisioning_engine_test",
size = "small",
srcs = ["provisioning_engine_test.cc"],
deps = [
":provisioning_engine",
"//external:gtest_main",
],
)
cc_library(
name = "provisioning_session",
srcs = ["provisioning_session.cc"],
hdrs = ["provisioning_session.h"],
copts = PUBLIC_COPTS,
deps = [
":provisioning_status",
"//base",
"//provisioning_sdk/internal:provisioning_session_impl",
"//protos/public:device_certificate_proto",
],
)
cc_library(
name = "provisioning_status",
srcs = ["provisioning_status.cc"],
hdrs = ["provisioning_status.h"],
copts = PUBLIC_COPTS,
deps = ["//base"],
)
cc_library(
name = "certificate_type",
hdrs = ["certificate_type.h"],
copts = PUBLIC_COPTS,
)

View File

@@ -0,0 +1,22 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_PUBLIC_CERTIFICATE_TYPE_H_
#define PROVISIONING_SDK_PUBLIC_CERTIFICATE_TYPE_H_
namespace widevine {
enum CertificateType {
kCertTesting = 0,
kCertDevelopment,
kCertProduction,
};
} // namespace widevine
#endif // PROVISIONING_SDK_PUBLIC_CERTIFICATE_TYPE_H_

View File

@@ -0,0 +1,118 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/public/provisioning_engine.h"
#include <utility>
#include "glog/logging.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
#include "provisioning_sdk/internal/provisioning_session_impl.h"
#include "provisioning_sdk/public/provisioning_session.h"
namespace widevine {
ProvisioningEngine::ProvisioningEngine() {}
ProvisioningEngine::~ProvisioningEngine() {}
ProvisioningStatus ProvisioningEngine::Initialize(
CertificateType certificate_type, const std::string& service_drm_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase,
const std::string& provisioning_drm_certificate,
const std::string& provisioning_private_key,
const std::string& provisioning_private_key_passphrase,
const std::string& secret_spoid_sauce) {
if (impl_) {
LOG(WARNING) << "ProvisioningEngine is already initialized.";
return INTERNAL_ERROR;
}
std::unique_ptr<ProvisioningEngineImpl> impl(new ProvisioningEngineImpl);
ProvisioningStatus status = impl->Initialize(
certificate_type, service_drm_certificate, service_private_key,
service_private_key_passphrase, provisioning_drm_certificate,
provisioning_private_key, provisioning_private_key_passphrase,
secret_spoid_sauce);
if (status != OK) return status;
impl_ = std::move(impl);
return OK;
}
ProvisioningStatus ProvisioningEngine::SetCertificateStatusList(
const std::string& certificate_status_list, uint32_t expiration_period_seconds) {
if (!impl_) return PROVISIONING_ENGINE_UNINITIALIZED;
return impl_->SetCertificateStatusList(certificate_status_list,
expiration_period_seconds);
}
ProvisioningStatus ProvisioningEngine::GenerateDrmIntermediateCertificate(
uint32_t system_id, const std::string& public_key, std::string* certificate) const {
if (!impl_) return PROVISIONING_ENGINE_UNINITIALIZED;
if (!certificate) {
LOG(WARNING) << "|certificate| should not be a nullptr.";
return INTERNAL_ERROR;
}
return impl_->GenerateDrmIntermediateCertificate(system_id, public_key,
certificate);
}
ProvisioningStatus ProvisioningEngine::AddDrmIntermediateCertificate(
const std::string& intermediate_cert, const std::string& cert_private_key,
const std::string& cert_private_key_passphrase) {
if (!impl_) return PROVISIONING_ENGINE_UNINITIALIZED;
return impl_->AddDrmIntermediateCertificate(
intermediate_cert, cert_private_key, cert_private_key_passphrase);
}
ProvisioningStatus ProvisioningEngine::NewProvisioningSession(
const std::string& device_public_key, const std::string& device_private_key,
std::unique_ptr<ProvisioningSession>* new_session) const {
if (!impl_) return PROVISIONING_ENGINE_UNINITIALIZED;
if (!new_session) {
LOG(WARNING) << "|new_session| should not be a nullptr.";
return INTERNAL_ERROR;
}
std::unique_ptr<ProvisioningSessionImpl> session_impl(
new ProvisioningSessionImpl(*impl_, impl_->oem_device_cert(),
*impl_->service_private_key()));
ProvisioningStatus status =
session_impl->Initialize(device_public_key, device_private_key);
if (status != OK) return status;
new_session->reset(new ProvisioningSession(std::move(session_impl)));
return OK;
}
ProvisioningStatus ProvisioningEngine::GenerateDeviceDrmCertificate(
uint32_t system_id, const std::string& public_key, const std::string& serial_number,
std::string* certificate) const {
if (!impl_) return PROVISIONING_ENGINE_UNINITIALIZED;
if (!certificate) {
LOG(WARNING) << "|certificate| should not be a nullptr.";
return INTERNAL_ERROR;
}
// Validate public key. This validation is done here instead of inside
// |impl_->GenerateDeviceDrmCertificate| is because the latter is an internal
// function which expect the input to be already validated.
std::unique_ptr<RsaPublicKey> rsa_public_key(
RsaPublicKey::Create(public_key));
if (!rsa_public_key) return INVALID_DEVICE_PUBLIC_KEY;
if (serial_number.empty()) return INVALID_SERIAL_NUMBER;
const std::string empty_oem_ca_serial_number;
return impl_->GenerateDeviceDrmCertificate(
system_id, empty_oem_ca_serial_number, public_key, serial_number,
certificate);
}
} // namespace widevine

View File

@@ -0,0 +1,153 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_PUBLIC_PROVISIONING_ENGINE_H_
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_ENGINE_H_
#include <cstdint>
#include <memory>
#include <string>
#include "provisioning_sdk/public/certificate_type.h"
#include "provisioning_sdk/public/provisioning_status.h"
namespace widevine {
class ProvisioningEngineImpl;
class ProvisioningSession;
// Class which is used to implement a Widevine DRM device provisioning engine.
// There should be only one instance of ProvisioningEngine. The engine should
// be "Initialized" before being used. ProvisioningEngine::Initialize is the
// only method that is not thread-safe. After initializing the engine, it can
// be safely used in different threads.
class ProvisioningEngine {
public:
ProvisioningEngine();
~ProvisioningEngine();
// Initializes the provisioning engine with required credentials.
// * |certificate_type| indicates which type of certificate chains will be
// used for device provisioning via this engine.
// * |service_drm_certificate| is a Google-generated certificate used to
// authenticate the service provider for purposes of user privacy.
// * |service_private_key| is the encrypted PKCS#8 private RSA key
// corresponding to the service certificate.
// * |service_private_key_passphrase| is the password required to decrypt
// |service_private_key|, if any.
// * |provisioning_drm_certificate| is a Google-generated certificate used to
// sign intermediate DRM certificates.
// * |provisioning_private_key| is the encrypted PKCS#8 private RSA key
// corresponding to the provisioning certificate.
// * |provisioning_private_key_passphrase| is the password required to
// decrypt |provisioning_private_key|, if any.
// * |secret_spoid_sauce| is a stable secret used as a factor in the
// derivation of Stable Per-Origin IDentifiers.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus Initialize(
CertificateType certificate_type,
const std::string& service_drm_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase,
const std::string& provisioning_drm_certificate,
const std::string& provisioning_private_key,
const std::string& provisioning_private_key_passphrase,
const std::string& secret_spoid_sauce);
// Set the certificate status list for this engine.
// * |certificate_status_list| is a certificate status list generated by the
// Widevine Provisioning Service.
// * |expiration_period| is the number of seconds until the
// |certificate_status_list| expires after its creation time
// (creation_time_seconds). Zero means it will never expire.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus SetCertificateStatusList(
const std::string& certificate_status_list,
uint32_t expiration_period_seconds);
// Generate an intermediate DRM certificate.
// * |system_id| is the Widevine system ID for the type of device.
// * |public_key| is a DER-encoded PKCS#1.5 RSAPublicKey message which will
// be embedded in the generated certificate.
// * |certificate| will contain the new intermediate certificate, upon
// successful return.
// * Returns OK on success, or an appropriate error status code otherwise.
// NOTE: The generated certificate and associated private key should be stored
// securely to be reused. They should also be propagated to all
// engines, including this one, by invoking
// |AddIntermediatedrmcertificate| on all active ProvisioningEngine(s).
ProvisioningStatus GenerateDrmIntermediateCertificate(
uint32_t system_id,
const std::string& public_key,
std::string* certificate) const;
// Add an intermediate DRM certificate to the provisioning engine. This is
// usually done once for each supported device type.
// * |intermediate_cert| is the intermediate DRM certificate to be added.
// * |cert_private_key| is a PKCS#8 private key corresponding to
// |intermediate_cert|.
// * |cert_private_key_passphrase| is the passphrase for cert_private_key,
// if any.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus AddDrmIntermediateCertificate(
const std::string& intermediate_cert,
const std::string& cert_private_key,
const std::string& cert_private_key_passphrase);
// Create a session to handle a provisioning exchange between a client device
// and the provisioning server.
// * |device_public_key| is a DER-encoded PKCS#1.5 RSAPublicKey message which
// will used to create the DRM certificate to be provisioned onto the
// device.
// * |device_private_key| is a DER-encoded PKCS#8 PrivateKeyInfo message
// which contains the private key matching |device_public_key|.
// * |new_session| will point, on successful return, to the newly created
// ProvisioningSession.
// * Returns OK if successful, or an appropriate error status code otherwise.
// The key pairs can be re-used if the created session failed to process the
// message.
// NOTE: All ProvisioningSession objects must be deleted before the
// ProvisioningEngine which created them.
ProvisioningStatus NewProvisioningSession(
const std::string& device_public_key,
const std::string& device_private_key,
std::unique_ptr<ProvisioningSession>* new_session) const;
// Generate a new device DRM certificate to be provisioned by means other than
// the Widevine provisioning protocol.
// NOTE: This API should only be used to provision devices which were
// manufactured without Widevine DRM support. It is meant to be used as
// an exception, and not the norm. Most devices should be provisioned
// by means of a ProvisioningSession.
// * |system_id| is the Widevine system ID for the type of device being
// provisioned.
// * |public_key| is a DER-encoded PKCS#1.5 RSAPublicKey message which will
// be embedded in the generated certificate.
// * |serial_number| is a binary std::string to be used as the generated DRM
// certificate serial number.
// * |certificate| will contain, upon successful return the generated
// certificate.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus GenerateDeviceDrmCertificate(
uint32_t system_id,
const std::string& public_key,
const std::string& serial_number,
std::string* certificate) const;
private:
#ifndef SWIGPYTHON
ProvisioningEngine(const ProvisioningEngine&) = delete;
ProvisioningEngine& operator=(const ProvisioningEngine&) = delete;
#endif
std::unique_ptr<ProvisioningEngineImpl> impl_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_PUBLIC_PROVISIONING_ENGINE_H_

View File

@@ -0,0 +1,58 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/public/provisioning_engine.h"
#include "gtest/gtest.h"
namespace {
const int kSystemId = 100;
const int kExpirationPeriodSeconds = 3600;
} // namespace
namespace widevine {
class ProvisioningEngineTest : public ::testing::Test {
protected:
ProvisioningEngine engine_;
};
TEST_F(ProvisioningEngineTest, SetCertificateStatusListWithoutInit) {
EXPECT_EQ(PROVISIONING_ENGINE_UNINITIALIZED,
engine_.SetCertificateStatusList("certificate_status_list",
kExpirationPeriodSeconds));
}
TEST_F(ProvisioningEngineTest, GenerateDrmIntermediateCertificateWithoutInit) {
std::string certificate;
EXPECT_EQ(PROVISIONING_ENGINE_UNINITIALIZED,
engine_.GenerateDrmIntermediateCertificate(
kSystemId, "intermediate_public_key", &certificate));
}
TEST_F(ProvisioningEngineTest, AddDrmIntermediateCertificateWithoutInit) {
std::string certificate;
EXPECT_EQ(PROVISIONING_ENGINE_UNINITIALIZED,
engine_.AddDrmIntermediateCertificate(
"intermediate_certificate", "intermediate_private_key",
"intermediate_private_key_passphrase"));
}
TEST_F(ProvisioningEngineTest, GenerateDeviceDrmCertificateWithoutInit) {
std::string certificate;
EXPECT_EQ(PROVISIONING_ENGINE_UNINITIALIZED,
engine_.GenerateDeviceDrmCertificate(kSystemId, "device_public_key",
"device_serial_number",
&certificate));
}
// ProvisioningEngine is basically a wrapper of ProvisioningEngineImpl, so there
// is no need to test the functionalities as ProvisioningEngineImpl is already
// tested.
} // namespace widevine

View File

@@ -0,0 +1,48 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/public/provisioning_session.h"
#include <utility>
#include "glog/logging.h"
#include "provisioning_sdk/internal/provisioning_session_impl.h"
#include "protos/public/device_certificate.pb.h"
namespace widevine {
ProvisioningSession::~ProvisioningSession() {}
ProvisioningStatus ProvisioningSession::ProcessMessage(const std::string& message,
std::string* response,
bool* done) {
if (!response) {
LOG(WARNING) << "|response| should not be a nullptr.";
return INTERNAL_ERROR;
}
if (!done) {
LOG(WARNING) << "|done| should not be a nullptr.";
return INTERNAL_ERROR;
}
ProvisioningStatus status = impl_->ProcessMessage(message, response);
*done = true;
return status;
}
const ProvisionedDeviceInfo* ProvisioningSession::GetDeviceInfo() const {
return impl_->GetDeviceInfo();
}
ProvisioningSession::ProvisioningSession(
std::unique_ptr<ProvisioningSessionImpl> impl)
: impl_(std::move(impl)) {
DCHECK(impl_);
}
} // namespace widevine

View File

@@ -0,0 +1,56 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_PUBLIC_PROVISIONING_SESSION_H_
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_SESSION_H_
#include <memory>
#include <string>
#include "provisioning_sdk/public/provisioning_status.h"
namespace widevine {
class ProvisionedDeviceInfo;
class ProvisioningSessionImpl;
// Class which is used to implement the provisioning session state machine.
class ProvisioningSession {
public:
~ProvisioningSession();
// Process a message from the client device.
// * |message| is the message received from the client device.
// * |response| will contain, upon successful return, a message to be sent
// back to the client device as a response to |message|.
// * |done| will indicate, upon successful return, whether the provisioning
// exchange is complete, and the ProvisioningSession can be deleted.
// Returns OK if successful, or an appropriate error status code otherwise.
ProvisioningStatus ProcessMessage(const std::string& message,
std::string* response,
bool* done);
// * Returns a ProvisioneddeviceInfo message containing information about the
// type of device being provisioned. May return nullptr.
const ProvisionedDeviceInfo* GetDeviceInfo() const;
private:
#ifndef SWIGPYTHON
friend class ProvisioningEngine;
ProvisioningSession(const ProvisioningSession&) = delete;
ProvisioningSession& operator=(const ProvisioningSession&) = delete;
#endif
explicit ProvisioningSession(std::unique_ptr<ProvisioningSessionImpl> impl);
std::unique_ptr<ProvisioningSessionImpl> impl_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_PUBLIC_PROVISIONING_SESSION_H_

View File

@@ -0,0 +1,48 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/public/provisioning_status.h"
#include "base/macros.h"
namespace widevine {
static const char* kProvisioningStatusMessage[] = {
"OK",
"Invalid certificate type",
"Provisioning engine uninitialized",
"Invalid service drm certificate",
"Invalid service private key",
"Invalid provisioning drm certificate",
"Invalid provisioning private key",
"Invalid intermediate drm certificate",
"Invalid intermediate public key",
"Invalid intermediate private key",
"Invalid status list",
"Status list expired",
"Unknown system id",
"Invalid device public key",
"Invalid device private key",
"Invalid request message",
"Invalid MAC",
"Missing DRM intermediate certificate",
"DRM device certificate not set",
"Device revoked",
"Invalid serial number",
"Internal error",
"Invalid SPOID secret sauce"
};
const char* GetProvisioningStatusMessage(ProvisioningStatus status) {
static_assert(
arraysize(kProvisioningStatusMessage) == NUM_PROVISIONING_STATUS,
"mismatching provisioning status message and provisioning status.");
return kProvisioningStatusMessage[status];
}
} // namespace widevine

View File

@@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_
namespace widevine {
enum ProvisioningStatus {
OK = 0,
INVALID_CERTIFICATE_TYPE = 1,
PROVISIONING_ENGINE_UNINITIALIZED = 2,
INVALID_SERVICE_DRM_CERTIFICATE = 3,
// Invalid service private key or private key passphrase.
INVALID_SERVICE_PRIVATE_KEY = 4,
INVALID_PROVISIONER_DRM_CERTIFICATE = 5,
// Invalid provisioner private key or private key passphrase.
INVALID_PROVISIONER_PRIVATE_KEY = 6,
INVALID_INTERMEDIATE_DRM_CERTIFICATE = 7,
INVALID_INTERMEDIATE_PUBLIC_KEY = 8,
// Invalid intermediate private key or private key passphrase.
INVALID_INTERMEDIATE_PRIVATE_KEY = 9,
INVALID_STATUS_LIST = 10,
STATUS_LIST_EXPIRED = 11,
UNKNOWN_SYSTEM_ID = 12,
INVALID_DEVICE_PUBLIC_KEY = 13,
INVALID_DEVICE_PRIVATE_KEY = 14,
INVALID_REQUEST_MESSAGE = 15,
INVALID_MAC = 16,
MISSING_DRM_INTERMEDIATE_CERT = 17,
DRM_DEVICE_CERTIFICATE_NOT_SET = 18,
DEVICE_REVOKED = 19,
INVALID_SERIAL_NUMBER = 20,
INTERNAL_ERROR = 21,
INVALID_SPOID_SAUCE = 22,
NUM_PROVISIONING_STATUS,
};
// Returns the message std::string for the given ProvisioningStatus.
const char* GetProvisioningStatusMessage(ProvisioningStatus status);
} // namespace widevine
#endif // PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_

View File

@@ -0,0 +1,73 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
package(default_visibility = ["//visibility:public"])
py_library(
name = "test_data_utility",
srcs = ["test_data_utility.py"],
data = ["//example:example_data"],
deps = [
"//protos/public:certificate_provisioning_py_pb2",
],
)
py_library(
name = "crypto_utility",
srcs = ["crypto_utility.py"],
)
py_test(
name = "init_engine_test",
size = "small",
srcs = ["init_engine_test.py"],
deps = [
":test_data_utility",
],
)
py_test(
name = "set_certificate_status_list_test",
size = "small",
srcs = ["set_certificate_status_list_test.py"],
deps = [
":test_data_utility",
],
)
py_test(
name = "drm_intermediate_certificate_test",
size = "small",
srcs = ["drm_intermediate_certificate_test.py"],
deps = [
":test_data_utility",
],
)
py_test(
name = "engine_generate_certificate_test",
size = "small",
srcs = ["engine_generate_certificate_test.py"],
deps = [
":crypto_utility",
":test_data_utility",
"//protos/public:signed_device_certificate_py_pb2",
],
)
py_test(
name = "new_session_test",
size = "small",
srcs = ["new_session_test.py"],
deps = [
":crypto_utility",
":test_data_utility",
"//protos/public:certificate_provisioning_py_pb2",
"//protos/public:signed_device_certificate_py_pb2",
],
)

View File

@@ -0,0 +1,27 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
%include "std_string.i"
%include "typemaps.i"
%define %ignoreall %ignore ""; %enddef
%define %unignore %rename("%s") %enddef
%define %unignoreall %rename("%s") ""; %enddef
%define COPY_TYPEMAPS(oldtype, newtype)
typedef oldtype newtype;
%apply oldtype * OUTPUT { newtype * OUTPUT };
%apply oldtype & OUTPUT { newtype & OUTPUT };
%apply oldtype * INPUT { newtype * INPUT };
%apply oldtype & INPUT { newtype & INPUT };
%apply oldtype * INOUT { newtype * INOUT };
%apply oldtype & INOUT { newtype & INOUT };
%enddef
COPY_TYPEMAPS(int, int32);
COPY_TYPEMAPS(unsigned int, uint32);

View File

@@ -0,0 +1,28 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// Swig file to generate a Python library for:
// provisioning_sdk/public/certificate_type.h
%module pywrapcertificate_type
%include "base.i"
%{
#include "provisioning_sdk/public/certificate_type.h"
%}
%ignoreall
%unignore widevine;
%unignore widevine::CertificateType;
%unignore widevine::kCertTesting;
%unignore widevine::kCertDevelopment;
%include "provisioning_sdk/public/certificate_type.h"
%unignoreall

View File

@@ -0,0 +1,25 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
"""Utility functions for cryptography."""
from cryptography.hazmat import backends
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
def VerifySignature(public_key, signature, data):
hash_algorithm = hashes.SHA1()
salt_len = 20
key = serialization.load_der_public_key(
public_key, backend=backends.default_backend())
key.verify(signature, data,
padding.PSS(padding.MGF1(hash_algorithm), salt_len),
hash_algorithm)

View File

@@ -0,0 +1,54 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
import unittest
import pywrapprovisioning_engine
import pywrapprovisioning_status
import test_data_utility
class AddDrmIntermediateTest(unittest.TestCase):
def setUp(self):
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
def testGenerateDrmIntermediateCertificateWithValidExpirationPeriod(self):
test_data_utility.SetCertificateStatusListWithTestData(
self._engine, 0, verify_success=True)
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
def testSetCertificateStatusListInvalid(self):
set_cert_status_list = self._engine.SetCertificateStatusList(
'INVALID_STATUS_LIST', 0)
self.assertEqual(pywrapprovisioning_status.INVALID_STATUS_LIST,
set_cert_status_list)
def testAddDrmIntermediateCertificateWithoutCertificateStatusList(self):
# Users should not be able to add DRM certificate without having
# certificate status list.
status = test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001)
self.assertEqual(pywrapprovisioning_status.STATUS_LIST_EXPIRED, status)
def testAddDrmIntermediateCertificateSystemIdInvalid(self):
test_data_utility.SetCertificateStatusListWithTestData(
self._engine, 0, verify_success=True)
# system_id 9999 is not in the sample certificate status list
add_ca_status = test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 9999)
self.assertEqual(pywrapprovisioning_status.UNKNOWN_SYSTEM_ID, add_ca_status)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,64 @@
################################################################################
# Copyright 2016 Google Inc.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
import unittest
import crypto_utility
import pywrapprovisioning_engine
import pywrapprovisioning_status
import test_data_utility
from protos.public import signed_device_certificate_pb2
class EngineGenerateCertificateTest(unittest.TestCase):
def setUp(self):
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
test_data_utility.SetCertificateStatusListWithTestData(
self._engine, 0, verify_success=True)
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
def testSuccess(self):
status, signed_cert_string = self._engine.GenerateDeviceDrmCertificate(
2001, test_data_utility.DEVICE_PUBLIC_KEY, 'DEVICE_SERIAL_NUMBER')
self.assertEqual(pywrapprovisioning_status.OK, status)
signed_cert = signed_device_certificate_pb2.SignedDrmDeviceCertificate()
signed_cert.ParseFromString(signed_cert_string)
crypto_utility.VerifySignature(test_data_utility.CA_PUBLIC_KEY,
signed_cert.signature,
signed_cert.drm_certificate)
def testEmptySerialNumber(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2001, test_data_utility.DEVICE_PUBLIC_KEY, '')
self.assertEqual(pywrapprovisioning_status.INVALID_SERIAL_NUMBER, status)
def testEmptyPublicKey(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2001, '', 'DEVICE_SERIAL_NUMBER')
self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY,
status)
def testInvalidPublicKey(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2001, 'PUBLIC_KEY_MUST_BE_IN_DER_ENCODED_PKCS1_FORMAT',
'DEVICE_SERIAL_NUMBER')
self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY,
status)
def testMissingIntermediateCertificate(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2002, test_data_utility.DEVICE_PUBLIC_KEY, 'DEVICE_SERIAL_NUMBER')
self.assertEqual(pywrapprovisioning_status.DEVICE_REVOKED, status)
if __name__ == '__main__':
unittest.main()

Some files were not shown because too many files have changed in this diff Show More