Import Cobalt 10.55341
diff --git a/src/base/time.cc b/src/base/time.cc
index 6d20667..fad5508 100644
--- a/src/base/time.cc
+++ b/src/base/time.cc
@@ -15,6 +15,7 @@
 #include "base/third_party/nspr/prtime.h"
 
 #include "base/logging.h"
+#include "starboard/double.h"
 
 namespace base {
 
@@ -137,7 +138,7 @@
 
 // static
 Time Time::FromDoubleT(double dt) {
-  if (dt == 0 || isnan(dt))
+  if (dt == 0 || SbDoubleIsNan(dt))
     return Time();  // Preserve 0 so we can tell it doesn't exist.
   if (dt == std::numeric_limits<double>::max())
     return Max();
diff --git a/src/cobalt/accessibility/starboard_tts_engine.cc b/src/cobalt/accessibility/starboard_tts_engine.cc
index d2788fc..6fb7a10 100644
--- a/src/cobalt/accessibility/starboard_tts_engine.cc
+++ b/src/cobalt/accessibility/starboard_tts_engine.cc
@@ -21,12 +21,12 @@
 namespace cobalt {
 namespace accessibility {
 
-void StarboardTTSEngine::SpeakNow(const std::string& text) OVERRIDE {
+void StarboardTTSEngine::SpeakNow(const std::string& text) {
   SbSpeechSynthesisCancel();
   Speak(text);
 }
 
-void StarboardTTSEngine::Speak(const std::string& text) OVERRIDE {
+void StarboardTTSEngine::Speak(const std::string& text) {
   SbSpeechSynthesisSpeak(text.c_str());
 }
 
diff --git a/src/cobalt/base/tokens.h b/src/cobalt/base/tokens.h
index c70a97e..7ca128e 100644
--- a/src/cobalt/base/tokens.h
+++ b/src/cobalt/base/tokens.h
@@ -21,82 +21,90 @@
 namespace base {
 
 // clang-format off
-#define TOKENS_FOR_EACH_WITH_NAME_ONLY(MacroOpWithNameOnly)   \
-    MacroOpWithNameOnly(addsourcebuffer)                      \
-    MacroOpWithNameOnly(addtrack)                             \
-    MacroOpWithNameOnly(abort)                                \
-    MacroOpWithNameOnly(additions)                            \
-    MacroOpWithNameOnly(all)                                  \
-    MacroOpWithNameOnly(alt)                                  \
-    MacroOpWithNameOnly(animationend)                         \
-    MacroOpWithNameOnly(assertive)                            \
-    MacroOpWithNameOnly(attributes)                           \
-    MacroOpWithNameOnly(blur)                                 \
-    MacroOpWithNameOnly(boundary)                             \
-    MacroOpWithNameOnly(canplay)                              \
-    MacroOpWithNameOnly(canplaythrough)                       \
-    MacroOpWithNameOnly(change)                               \
-    MacroOpWithNameOnly(characterData)                        \
-    MacroOpWithNameOnly(childList)                            \
-    MacroOpWithNameOnly(close)                                \
-    MacroOpWithNameOnly(durationchange)                       \
-    MacroOpWithNameOnly(emptied)                              \
-    MacroOpWithNameOnly(end)                                  \
-    MacroOpWithNameOnly(ended)                                \
-    MacroOpWithNameOnly(error)                                \
-    MacroOpWithNameOnly(focus)                                \
-    MacroOpWithNameOnly(hashchange)                           \
-    MacroOpWithNameOnly(keyadded)                             \
-    MacroOpWithNameOnly(keydown)                              \
-    MacroOpWithNameOnly(keyerror)                             \
-    MacroOpWithNameOnly(keymessage)                           \
-    MacroOpWithNameOnly(keypress)                             \
-    MacroOpWithNameOnly(keyup)                                \
-    MacroOpWithNameOnly(load)                                 \
-    MacroOpWithNameOnly(loadeddata)                           \
-    MacroOpWithNameOnly(loadedmetadata)                       \
-    MacroOpWithNameOnly(loadend)                              \
-    MacroOpWithNameOnly(loadstart)                            \
-    MacroOpWithNameOnly(mark)                                 \
-    MacroOpWithNameOnly(message)                              \
-    MacroOpWithNameOnly(needkey)                              \
-    MacroOpWithNameOnly(nomatch)                              \
-    MacroOpWithNameOnly(off)                                  \
-    MacroOpWithNameOnly(open)                                 \
-    MacroOpWithNameOnly(pause)                                \
-    MacroOpWithNameOnly(play)                                 \
-    MacroOpWithNameOnly(playing)                              \
-    MacroOpWithNameOnly(polite)                               \
-    MacroOpWithNameOnly(progress)                             \
-    MacroOpWithNameOnly(ratechange)                           \
-    MacroOpWithNameOnly(readystatechange)                     \
-    MacroOpWithNameOnly(removals)                             \
-    MacroOpWithNameOnly(removesourcebuffer)                   \
-    MacroOpWithNameOnly(removetrack)                          \
-    MacroOpWithNameOnly(result)                               \
-    MacroOpWithNameOnly(resume)                               \
-    MacroOpWithNameOnly(securitypolicyviolation)              \
-    MacroOpWithNameOnly(seeked)                               \
-    MacroOpWithNameOnly(seeking)                              \
-    MacroOpWithNameOnly(soundend)                             \
-    MacroOpWithNameOnly(soundstart)                           \
-    MacroOpWithNameOnly(sourceclose)                          \
-    MacroOpWithNameOnly(sourceended)                          \
-    MacroOpWithNameOnly(sourceopen)                           \
-    MacroOpWithNameOnly(start)                                \
-    MacroOpWithNameOnly(storage)                              \
-    MacroOpWithNameOnly(stalled)                              \
-    MacroOpWithNameOnly(suspend)                              \
-    MacroOpWithNameOnly(text)                                 \
-    MacroOpWithNameOnly(timeout)                              \
-    MacroOpWithNameOnly(timeupdate)                           \
-    MacroOpWithNameOnly(transitionend)                        \
-    MacroOpWithNameOnly(unload)                               \
-    MacroOpWithNameOnly(update)                               \
-    MacroOpWithNameOnly(updateend)                            \
-    MacroOpWithNameOnly(updatestart)                          \
-    MacroOpWithNameOnly(voiceschanged)                        \
-    MacroOpWithNameOnly(volumechange)                         \
+#if defined(COBALT_MEDIA_SOURCE_2016)
+#define TOKENS_FOR_EACH_WITH_NAME_ONLY_EME(MacroOpWithNameOnly)      \
+    MacroOpWithNameOnly(encrypted)
+#else  // defined(COBALT_MEDIA_SOURCE_2016)
+#define TOKENS_FOR_EACH_WITH_NAME_ONLY_EME(MacroOpWithNameOnly)      \
+    MacroOpWithNameOnly(keyadded)                                    \
+    MacroOpWithNameOnly(keyerror)                                    \
+    MacroOpWithNameOnly(keymessage)                                  \
+    MacroOpWithNameOnly(needkey)
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
+
+#define TOKENS_FOR_EACH_WITH_NAME_ONLY(MacroOpWithNameOnly)          \
+    TOKENS_FOR_EACH_WITH_NAME_ONLY_EME(MacroOpWithNameOnly)          \
+    MacroOpWithNameOnly(addsourcebuffer)                             \
+    MacroOpWithNameOnly(addtrack)                                    \
+    MacroOpWithNameOnly(abort)                                       \
+    MacroOpWithNameOnly(additions)                                   \
+    MacroOpWithNameOnly(all)                                         \
+    MacroOpWithNameOnly(alt)                                         \
+    MacroOpWithNameOnly(animationend)                                \
+    MacroOpWithNameOnly(assertive)                                   \
+    MacroOpWithNameOnly(attributes)                                  \
+    MacroOpWithNameOnly(blur)                                        \
+    MacroOpWithNameOnly(boundary)                                    \
+    MacroOpWithNameOnly(canplay)                                     \
+    MacroOpWithNameOnly(canplaythrough)                              \
+    MacroOpWithNameOnly(change)                                      \
+    MacroOpWithNameOnly(characterData)                               \
+    MacroOpWithNameOnly(childList)                                   \
+    MacroOpWithNameOnly(close)                                       \
+    MacroOpWithNameOnly(durationchange)                              \
+    MacroOpWithNameOnly(emptied)                                     \
+    MacroOpWithNameOnly(end)                                         \
+    MacroOpWithNameOnly(ended)                                       \
+    MacroOpWithNameOnly(error)                                       \
+    MacroOpWithNameOnly(focus)                                       \
+    MacroOpWithNameOnly(hashchange)                                  \
+    MacroOpWithNameOnly(keydown)                                     \
+    MacroOpWithNameOnly(keypress)                                    \
+    MacroOpWithNameOnly(keyup)                                       \
+    MacroOpWithNameOnly(load)                                        \
+    MacroOpWithNameOnly(loadeddata)                                  \
+    MacroOpWithNameOnly(loadedmetadata)                              \
+    MacroOpWithNameOnly(loadend)                                     \
+    MacroOpWithNameOnly(loadstart)                                   \
+    MacroOpWithNameOnly(mark)                                        \
+    MacroOpWithNameOnly(message)                                     \
+    MacroOpWithNameOnly(nomatch)                                     \
+    MacroOpWithNameOnly(off)                                         \
+    MacroOpWithNameOnly(open)                                        \
+    MacroOpWithNameOnly(pause)                                       \
+    MacroOpWithNameOnly(play)                                        \
+    MacroOpWithNameOnly(playing)                                     \
+    MacroOpWithNameOnly(polite)                                      \
+    MacroOpWithNameOnly(progress)                                    \
+    MacroOpWithNameOnly(ratechange)                                  \
+    MacroOpWithNameOnly(readystatechange)                            \
+    MacroOpWithNameOnly(removals)                                    \
+    MacroOpWithNameOnly(removesourcebuffer)                          \
+    MacroOpWithNameOnly(removetrack)                                 \
+    MacroOpWithNameOnly(result)                                      \
+    MacroOpWithNameOnly(resume)                                      \
+    MacroOpWithNameOnly(securitypolicyviolation)                     \
+    MacroOpWithNameOnly(seeked)                                      \
+    MacroOpWithNameOnly(seeking)                                     \
+    MacroOpWithNameOnly(soundend)                                    \
+    MacroOpWithNameOnly(soundstart)                                  \
+    MacroOpWithNameOnly(sourceclose)                                 \
+    MacroOpWithNameOnly(sourceended)                                 \
+    MacroOpWithNameOnly(sourceopen)                                  \
+    MacroOpWithNameOnly(start)                                       \
+    MacroOpWithNameOnly(storage)                                     \
+    MacroOpWithNameOnly(stalled)                                     \
+    MacroOpWithNameOnly(suspend)                                     \
+    MacroOpWithNameOnly(text)                                        \
+    MacroOpWithNameOnly(timeout)                                     \
+    MacroOpWithNameOnly(timeupdate)                                  \
+    MacroOpWithNameOnly(transitionend)                               \
+    MacroOpWithNameOnly(unload)                                      \
+    MacroOpWithNameOnly(update)                                      \
+    MacroOpWithNameOnly(updateend)                                   \
+    MacroOpWithNameOnly(updatestart)                                 \
+    MacroOpWithNameOnly(voiceschanged)                               \
+    MacroOpWithNameOnly(volumechange)                                \
     MacroOpWithNameOnly(waiting)
 
 #define TOKENS_FOR_EACH_WITH_NAME_AND_VALUE(MacroOpWithNameAndValue)    \
diff --git a/src/cobalt/bindings/testing/numeric_type_bindings_test.cc b/src/cobalt/bindings/testing/numeric_type_bindings_test.cc
index 5741eb5..f6620f0 100644
--- a/src/cobalt/bindings/testing/numeric_type_bindings_test.cc
+++ b/src/cobalt/bindings/testing/numeric_type_bindings_test.cc
@@ -17,6 +17,7 @@
 #include "base/stringprintf.h"
 #include "cobalt/bindings/testing/bindings_test_base.h"
 #include "cobalt/bindings/testing/numeric_types_test_interface.h"
+#include "starboard/double.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -81,7 +82,7 @@
 // warning C4800: 'int' : forcing value to bool 'true' or 'false'
 #pragma warning(disable:4800)
 #endif
-  return isnan(number);
+  return SbDoubleIsNan(number);
 #if defined(_MSC_VER)
 #pragma warning(pop)
 #endif
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index 0bd7afe..765245a 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -471,6 +471,17 @@
   }
 #endif  // !defined(COBALT_FORCE_HTTPS)
 
+  if (command_line->HasSwitch(switches::kVideoPlaybackRateMultiplier)) {
+    double playback_rate = 1.0;
+    base::StringToDouble(command_line->GetSwitchValueASCII(
+                             switches::kVideoPlaybackRateMultiplier),
+                         &playback_rate);
+    options.web_module_options.video_playback_rate_multiplier =
+        static_cast<float>(playback_rate);
+    DLOG(INFO) << "Set video playback rate multiplier to "
+               << options.web_module_options.video_playback_rate_multiplier;
+  }
+
   EnableUsingStubImageDecoderIfRequired();
 
   if (command_line->HasSwitch(browser::switches::kDisableWebmVp9)) {
@@ -497,6 +508,13 @@
   }
 #endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
+  if (command_line->HasSwitch(browser::switches::kDisableNavigationWhitelist)) {
+    LOG(ERROR) << "\n"
+               << "  *** Disabling the default navigation whitelist! ***\n"
+               << "  *** Do not run in this mode in production!      ***";
+    options.web_module_options.location_policy = "h5vcc-location-src *";
+  }
+
   account_manager_.reset(new account::AccountManager());
   browser_module_.reset(new BrowserModule(initial_url, system_window_.get(),
                                           account_manager_.get(), options));
diff --git a/src/cobalt/browser/browser_bindings_gen.gyp b/src/cobalt/browser/browser_bindings_gen.gyp
index aa35c9a..685296f 100644
--- a/src/cobalt/browser/browser_bindings_gen.gyp
+++ b/src/cobalt/browser/browser_bindings_gen.gyp
@@ -97,8 +97,6 @@
         '../dom/html_image_element.idl',
         '../dom/html_link_element.idl',
         '../dom/html_media_element.idl',
-        #'../dom/html_media_element_eme.idl',
-        #'../dom/html_media_encrypted_event.idl',
         '../dom/html_meta_element.idl',
         '../dom/html_paragraph_element.idl',
         '../dom/html_script_element.idl',
@@ -110,18 +108,6 @@
         '../dom/keyboard_event.idl',
         '../dom/location.idl',
         '../dom/media_error.idl',
-        '../dom/media_key_complete_event.idl',
-        '../dom/media_key_error.idl',
-        '../dom/media_key_error_event.idl',
-        '../dom/media_key_message_event.idl',
-        #'../dom/media_key_message_event_init.idl',
-        '../dom/media_key_needed_event.idl',
-        #'../dom/media_key_session.idl',
-        #'../dom/media_key_status_map.idl',
-        #'../dom/media_key_system_access.idl',
-        #'../dom/media_key_system_configuration.idl',
-        #'../dom/media_key_system_media_capability.idl',
-        #'../dom/media_keys.idl',
         '../dom/media_query_list.idl',
         '../dom/media_source.idl',
         '../dom/memory_info.idl',
@@ -131,7 +117,6 @@
         '../dom/mutation_record.idl',
         '../dom/named_node_map.idl',
         '../dom/navigator.idl',
-        #'../dom/navigator_eme.idl',
         '../dom/node.idl',
         '../dom/node_list.idl',
         '../dom/performance.idl',
@@ -219,7 +204,6 @@
         '../xhr/xml_http_request_upload.idl',
     ],
 
-
     # IDL files that will end up generating a .h that will be #included in
     # Cobalt directly. IDL files for dictionaries and enums.
     'generated_header_idl_files': [
@@ -227,8 +211,6 @@
         '../audio/audio_node_channel_interpretation.idl',
         '../dom/blob_property_bag.idl',
         '../dom/dom_parser_supported_type.idl',
-        '../dom/media_key_status.idl',
-        '../dom/media_keys_requirement.idl',
         '../dom/media_source_end_of_stream_error.idl',
         '../dom/media_source_ready_state.idl',
         '../dom/mutation_observer_init.idl',
@@ -238,11 +220,11 @@
         '../media_session/media_metadata_init.idl',
         '../media_session/media_session_action.idl',
         '../media_session/media_session_playback_state.idl',
-        '../speech/speech_synthesis_error_code.idl',
         '../speech/speech_recognition_error_code.idl',
-        '../websocket/close_event_init.idl',
+        '../speech/speech_synthesis_error_code.idl',
         '../web_animations/animation_fill_mode.idl',
         '../web_animations/animation_playback_direction.idl',
+        '../websocket/close_event_init.idl',
     ],
 
     # Partial interfaces and the right-side of "implements". Also includes
@@ -252,12 +234,13 @@
     'dependency_idl_files': [
         '../cssom/link_style.idl',
 
+        '../dom/buffer_source.idl',
+        '../dom/document__web_animations_api.idl',
         '../dom/document_cssom.idl',
         '../dom/document_html5.idl',
-        '../dom/document__web_animations_api.idl',
+        '../dom/element_css_inline_style.idl',
         '../dom/element_cssom_view.idl',
         '../dom/element_dom_parsing_and_serialization.idl',
-        '../dom/element_css_inline_style.idl',
         '../dom/global_crypto.idl',
         '../dom/global_event_handlers.idl',
         '../dom/html_element_cssom_view.idl',
@@ -272,14 +255,50 @@
         '../dom/speech_synthesis_getter.idl',
         '../dom/url_utils.idl',
         '../dom/window__animation_timing.idl',
+        '../dom/window__performance.idl',
         '../dom/window_cssom.idl',
         '../dom/window_cssom_view.idl',
-        '../dom/window__performance.idl',
         '../dom/window_event_handlers.idl',
         '../dom/window_local_storage.idl',
         '../dom/window_session_storage.idl',
         '../dom/window_timers.idl',
         '../media_session/navigator_media_session.idl',
     ],
+
+    'conditions': [
+      ['cobalt_media_source_2016==1', {
+        'source_idl_files': [
+            '../dom/eme/media_encrypted_event.idl',
+            '../dom/eme/media_key_message_event.idl',
+            '../dom/eme/media_key_session.idl',
+            '../dom/eme/media_key_system_access.idl',
+            '../dom/eme/media_keys.idl',
+        ],
+        'generated_header_idl_files': [
+            '../dom/eme/media_encrypted_event_init.idl',
+            '../dom/eme/media_key_message_event_init.idl',
+            '../dom/eme/media_key_message_type.idl',
+            '../dom/eme/media_key_session_type.idl',
+            '../dom/eme/media_key_system_configuration.idl',
+            '../dom/eme/media_key_system_media_capability.idl',
+            '../dom/eme/media_keys_requirement.idl',
+        ],
+        'dependency_idl_files': [
+            '../dom/eme/html_media_element.idl',
+            '../dom/eme/navigator.idl',
+        ],
+      }, {
+        'source_idl_files': [
+            '../dom/media_key_complete_event.idl',
+            '../dom/media_key_error.idl',
+            '../dom/media_key_error_event.idl',
+            '../dom/media_key_message_event.idl',
+            '../dom/media_key_needed_event.idl',
+        ],
+        'dependency_idl_files': [
+            '../dom/html_media_element_eme_01b.idl',
+        ],
+      }],
+    ],
   },
 }
diff --git a/src/cobalt/browser/cobalt.gyp b/src/cobalt/browser/cobalt.gyp
index 6950cdd..d858eac 100644
--- a/src/cobalt/browser/cobalt.gyp
+++ b/src/cobalt/browser/cobalt.gyp
@@ -23,6 +23,15 @@
       'conditions': [
         ['cobalt_enable_lib == 1', {
             'sources': ['lib/main.cc',],
+            'all_dependent_settings': {
+              'target_conditions': [
+                ['_type=="executable" and _toolset=="target"', {
+                  'sources': [
+                    'lib/imported/main_stub.cc',
+                  ],
+                }],
+              ],
+            },
         }, {
             'sources': ['main.cc',],
         }],
diff --git a/src/cobalt/browser/lib/imported/main.h b/src/cobalt/browser/lib/imported/main.h
index c3abcb8..1cbfd3a 100644
--- a/src/cobalt/browser/lib/imported/main.h
+++ b/src/cobalt/browser/lib/imported/main.h
@@ -18,25 +18,19 @@
 #ifndef COBALT_BROWSER_LIB_IMPORTED_MAIN_H_
 #define COBALT_BROWSER_LIB_IMPORTED_MAIN_H_
 
+#include "starboard/event.h"
+#include "starboard/export.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-// Structure representing an input event and its data. This provides a subset
-// of SbEvent so that clients don't have to copy the Starboard headers into
-// their codebase.
-typedef struct CbLibKeyInputEvent {
-  unsigned char keycode;
-  bool pressed;
-} CbLibKeyInputEvent;
-
 // Invoked after Cobalt has been initialized.
-void CbLibOnCobaltInitialized();
+SB_IMPORT_PLATFORM void CbLibOnCobaltInitialized();
 
 // Invoked when Cobalt is receiving an event from Starboard.
-// Returns true if the event should pass through to Cobalt; returns false if
-// the event was consumed.
-bool CbLibHandleEvent(const CbLibKeyInputEvent& event);
+// Returns true if the client consumed |event|; false otherwise.
+SB_IMPORT_PLATFORM bool CbLibHandleEvent(const SbEvent* event);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/src/cobalt/browser/lib/imported/main_stub.cc b/src/cobalt/browser/lib/imported/main_stub.cc
new file mode 100644
index 0000000..ad5c642
--- /dev/null
+++ b/src/cobalt/browser/lib/imported/main_stub.cc
@@ -0,0 +1,9 @@
+#include "cobalt/browser/lib/imported/main.h"
+
+// Empty implementations so that 'lib' targets can be compiled into executables
+// by the builder without missing symbol definitions.
+void CbLibOnCobaltInitialized() {}
+bool CbLibHandleEvent(const SbEvent* event) {
+  (void) event;
+  return false;
+}
diff --git a/src/cobalt/browser/lib/main.cc b/src/cobalt/browser/lib/main.cc
index 51cd1e4..5d0fb44 100644
--- a/src/cobalt/browser/lib/main.cc
+++ b/src/cobalt/browser/lib/main.cc
@@ -23,26 +23,6 @@
 
 namespace {
 
-bool SbEventToCbLibKeyInputEvent(
-    const SbEvent* starboard_event,
-    CbLibKeyInputEvent* out_key_input_event) {
-  if (starboard_event == NULL ||
-      starboard_event->type != SbEventType::kSbEventTypeInput) {
-    return false;
-  }
-  const SbInputData* input_data =
-      static_cast<SbInputData*>(starboard_event->data);
-  if (input_data->device_type !=
-      SbInputDeviceType::kSbInputDeviceTypeKeyboard) {
-    return false;
-  }
-  out_key_input_event->pressed =
-      input_data->type == SbInputEventType::kSbInputEventTypePress;
-  out_key_input_event->keycode =
-      static_cast<unsigned char>(input_data->character);
-  return true;
-}
-
 cobalt::browser::Application* g_application = NULL;
 
 void StartApplication(int /*argc*/, char** /*argv*/, const char* /*link*/,
@@ -62,9 +42,7 @@
 }
 
 void HandleEvent(const SbEvent* starboard_event) {
-  CbLibKeyInputEvent key;
-  if (!SbEventToCbLibKeyInputEvent(starboard_event, &key) ||
-      CbLibHandleEvent(key)) {
+  if (!CbLibHandleEvent(starboard_event)) {
     cobalt::browser::EventHandler::HandleEvent(starboard_event);
   }
 }
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc
index 5e2ffd0..3b43b3d 100644
--- a/src/cobalt/browser/switches.cc
+++ b/src/cobalt/browser/switches.cc
@@ -112,6 +112,10 @@
 
 #endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
+// Disables the hard-coded navigation whitelist without disabling any other
+// security checks. This is enabled in Gold builds.
+const char kDisableNavigationWhitelist[] = "disable_navigation_whitelist";
+
 // Determines the capacity of the image cache which manages image surfaces
 // downloaded from a web page.  While it depends on the platform, often (and
 // ideally) these images are cached within GPU memory.
@@ -173,6 +177,10 @@
 // Specifies the maximum GPU usage of the cobalt.
 const char kMaxCobaltGpuUsage[] = "max_cobalt_gpu_usage";
 
+// Specifies the multiplier of video playback rate.  Set to a value greater than
+// 1.0 to play video faster.  Set to a value less than 1.0 to play video slower.
+const char kVideoPlaybackRateMultiplier[] = "video_playback_rate_multiplier";
+
 }  // namespace switches
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/switches.h b/src/cobalt/browser/switches.h
index 9214784..49a5fc7 100644
--- a/src/cobalt/browser/switches.h
+++ b/src/cobalt/browser/switches.h
@@ -47,6 +47,7 @@
 extern const char kWebDriverListenIp[];
 #endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
+extern const char kDisableNavigationWhitelist[];
 extern const char kImageCacheSizeInBytes[];
 extern const char kInitialURL[];
 extern const char kRemoteTypefaceCacheSizeInBytes[];
@@ -62,6 +63,8 @@
 extern const char kMaxCobaltCpuUsage[];
 extern const char kMaxCobaltGpuUsage[];
 
+extern const char kVideoPlaybackRateMultiplier[];
+
 }  // namespace switches
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/testdata/eme-demo/eme-demo.html b/src/cobalt/browser/testdata/eme-demo/eme-demo.html
new file mode 100644
index 0000000..0ebf640
--- /dev/null
+++ b/src/cobalt/browser/testdata/eme-demo/eme-demo.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!--
+ | Copyright 2017 Google Inc. All Rights Reserved.
+ |
+ | Licensed under the Apache License, Version 2.0 (the "License");
+ | you may not use this file except in compliance with the License.
+ | You may obtain a copy of the License at
+ |
+ |     http://www.apache.org/licenses/LICENSE-2.0
+ |
+ | Unless required by applicable law or agreed to in writing, software
+ | distributed under the License is distributed on an "AS IS" BASIS,
+ | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ | See the License for the specific language governing permissions and
+ | limitations under the License.
+ -->
+<html>
+<head>
+  <title>Encrypted Media Extensions (16 March 2017) Demo</title>
+  <style>
+    body {
+      background-color: white;
+    }
+    video {
+      height: 240px;
+      width: 426px;
+    }
+  </style>
+</head>
+
+<body>
+  <video></video>
+  <script src="eme-demo.js"></script>
+</body>
+</html>
diff --git a/src/cobalt/browser/testdata/eme-demo/eme-demo.js b/src/cobalt/browser/testdata/eme-demo/eme-demo.js
new file mode 100644
index 0000000..1a111db
--- /dev/null
+++ b/src/cobalt/browser/testdata/eme-demo/eme-demo.js
@@ -0,0 +1,89 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+function fetchArrayBuffer(method, url, body, callback) {
+  var xhr = new XMLHttpRequest();
+  xhr.responseType = 'arraybuffer';
+  xhr.addEventListener('load', function() {
+    callback(xhr.response);
+  });
+  xhr.open(method, url);
+  xhr.send(body);
+}
+
+function extractLicense(licenseArrayBuffer) {
+  var licenseArray = new Uint8Array(licenseArrayBuffer);
+  var licenseStartIndex = licenseArray.length - 2;
+  while (licenseStartIndex >= 0) {
+    if (licenseArray[licenseStartIndex] == 13 &&
+        licenseArray[licenseStartIndex + 1] == 10) {
+      licenseStartIndex += 2;
+      break;
+    }
+    --licenseStartIndex;
+  }
+
+  return licenseArray.subarray(licenseStartIndex);
+}
+
+var videoContentType = 'video/mp4; codecs="avc1.640028"';
+var audioContentType = 'audio/mp4; codecs="mp4a.40.2"';
+
+navigator.requestMediaKeySystemAccess('com.widevine.alpha', [{
+  'initDataTypes': ['cenc'],
+  'videoCapabilities': [{'contentType': videoContentType}],
+  'audioCapabilities': [{'contentType': audioContentType}]
+}]).then(function(mediaKeySystemAccess) {
+  return mediaKeySystemAccess.createMediaKeys();
+}).then(function(mediaKeys) {
+  var videoElement = document.querySelector('video');
+
+  videoElement.setMediaKeys(mediaKeys);
+
+  mediaKeySession = mediaKeys.createSession();
+  mediaKeySession.addEventListener('message', function(messageEvent) {
+    var licenseServerUrl = 'https://dash-mse-test.appspot.com/api/drm/widevine?drm_system=widevine&source=YOUTUBE&ip=0.0.0.0&ipbits=0&expire=19000000000&key=test_key1&sparams=ip,ipbits,expire,drm_system,source,video_id&video_id=03681262dc412c06&signature=9C4BE99E6F517B51FED1F0B3B31966D3C5DAB9D6.6A1F30BB35F3A39A4CA814B731450D4CBD198FFD';
+    fetchArrayBuffer('POST', licenseServerUrl, messageEvent.message,
+        function(licenseArrayBuffer) {
+          mediaKeySession.update(extractLicense(licenseArrayBuffer));
+        });
+  });
+
+  videoElement.addEventListener('encrypted', function(encryptedEvent) {
+    mediaKeySession.generateRequest(
+        encryptedEvent.initDataType, encryptedEvent.initData);
+  });
+
+  var mediaSource = new MediaSource();
+  mediaSource.addEventListener('sourceopen', function() {
+    var videoSourceBuffer = mediaSource.addSourceBuffer(videoContentType);
+    fetchArrayBuffer('GET',
+                     'http://yt-dash-mse-test.commondatastorage.googleapis.com/media/oops_cenc-20121114-142.mp4',
+                     null,
+                     function(videoArrayBuffer) {
+      videoSourceBuffer.appendBuffer(videoArrayBuffer);
+    });
+
+    var audioSourceBuffer = mediaSource.addSourceBuffer(audioContentType);
+    fetchArrayBuffer('GET',
+                     'http://yt-dash-mse-test.commondatastorage.googleapis.com/media/oops_cenc-20121114-148.mp4',
+                     null,
+                     function(audioArrayBuffer) {
+      audioSourceBuffer.appendBuffer(audioArrayBuffer);
+    });
+  });
+
+  videoElement.src = URL.createObjectURL(mediaSource);
+  videoElement.play();
+});
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 2b6aad6..380b091 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -495,7 +495,8 @@
       data.window_close_callback, data.window_minimize_callback,
       data.system_window_, data.options.camera_3d,
       media_session_client_->GetMediaSession(),
-      data.options.csp_insecure_allowed_token, data.dom_max_element_depth);
+      data.options.csp_insecure_allowed_token, data.dom_max_element_depth,
+      data.options.video_playback_rate_multiplier);
   DCHECK(window_);
 
   window_weak_ = base::AsWeakPtr(window_.get());
@@ -779,10 +780,12 @@
   debug_overlay_->ClearInput();
 #endif
 
-  // Finally purge the resource provider's caches and mark that we have no
-  // resource provider.
-  resource_provider_->PurgeCaches();
   resource_provider_ = NULL;
+
+  // Force garbage collection in |javascript_engine_|.
+  if (javascript_engine_) {
+    javascript_engine_->CollectGarbage();
+  }
 }
 
 void WebModule::Impl::Resume(render_tree::ResourceProvider* resource_provider) {
@@ -850,7 +853,8 @@
       image_cache_capacity_multiplier_when_playing_video(1.0f),
       thread_priority(base::kThreadPriority_Normal),
       loader_thread_priority(base::kThreadPriority_Low),
-      animated_image_decode_thread_priority(base::kThreadPriority_Low) {}
+      animated_image_decode_thread_priority(base::kThreadPriority_Low),
+      video_playback_rate_multiplier(1.f) {}
 
 WebModule::WebModule(
     const GURL& initial_url,
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index 3e29f72..d590e3e 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -169,6 +169,10 @@
     scoped_refptr<input::Camera3D> camera_3d;
 
     script::JavaScriptEngine::Options javascript_options;
+
+    // The video playback rate will be multiplied with the following value.  Its
+    // default value is 1.0.
+    float video_playback_rate_multiplier;
   };
 
   typedef layout::LayoutManager::LayoutResults LayoutResults;
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 9f62695..c2eb52e 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-52708
\ No newline at end of file
+55341
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index ddfd269..0c93ea2 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -43,6 +43,17 @@
     'sb_enable_lib%': '<(sb_enable_lib)',
     'cobalt_enable_lib': '<(sb_enable_lib)',
 
+    # This variable defines what Cobalt's preferred strategy should be for
+    # handling internally triggered application exit requests (e.g. the user
+    # chooses to back out of the application).
+    #   'stop'    -- The application should call SbSystemRequestStop() on exit,
+    #                resulting in a complete shutdown of the application.
+    #   'suspend' -- The application should call SbSystemRequestSuspend() on
+    #                exit, resulting in the application being "minimized".
+    #   'noexit'  -- The application should never allow the user to trigger an
+    #                exit, this will be managed by the system.
+    'cobalt_user_on_exit_strategy': 'stop',
+
     # Contains the current font package selection.  This can be used to trade
     # font quality, coverage, and latency for different font package sizes.
     # The font package can be one of the following options:
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/cobalt/dom/buffer_source.h
similarity index 60%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/cobalt/dom/buffer_source.h
index 51e1f2e..a796675 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/cobalt/dom/buffer_source.h
@@ -12,9 +12,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#ifndef COBALT_DOM_BUFFER_SOURCE_H_
+#define COBALT_DOM_BUFFER_SOURCE_H_
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include "cobalt/script/union_type.h"
+
+namespace cobalt {
+namespace dom {
+
+class ArrayBuffer;
+class ArrayBufferView;
+
+typedef script::UnionType2<scoped_refptr<ArrayBufferView>,
+                           scoped_refptr<ArrayBuffer> > BufferSource;
+
+}  // namespace dom
+}  // namespace cobalt
+
+#endif  // COBALT_DOM_BUFFER_SOURCE_H_
diff --git a/src/cobalt/base/math.h b/src/cobalt/dom/buffer_source.idl
similarity index 77%
rename from src/cobalt/base/math.h
rename to src/cobalt/dom/buffer_source.idl
index 4723bfb..91cb04a 100644
--- a/src/cobalt/base/math.h
+++ b/src/cobalt/dom/buffer_source.idl
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+// https://www.w3.org/TR/WebIDL-1/#common-BufferSource
 
-#include <cmath>
-
-#endif  // COBALT_BASE_MATH_H_
+typedef (ArrayBufferView or ArrayBuffer) BufferSource;
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index 754ee9b..09a671c 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -676,8 +676,13 @@
 }
 
 void Document::PurgeCachedResources() {
+  // Set the font faces to dirty prior to purging the font cache so that they'll
+  // be restored when processing resumes.
+  are_font_faces_dirty_ = true;
+  font_cache_->PurgeCachedResources();
+
   // Set the computed style to dirty so that it'll be able to update any
-  // elements that had images purged when it resumes.
+  // elements that had images purged when processing resumes.
   is_computed_style_dirty_ = true;
 
   scoped_refptr<HTMLHtmlElement> current_html = html();
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp
index a815619..6738764 100644
--- a/src/cobalt/dom/dom.gyp
+++ b/src/cobalt/dom/dom.gyp
@@ -37,6 +37,7 @@
         'blob.cc',
         'blob.h',
         'blob_property_bag.h',
+        'buffer_source.h',
         'camera_3d.cc',
         'camera_3d.h',
         'camera_3d_impl.cc',
@@ -169,16 +170,6 @@
         'local_storage_database.h',
         'location.cc',
         'location.h',
-        'media_error.h',
-        'media_key_complete_event.cc',
-        'media_key_complete_event.h',
-        'media_key_error.h',
-        'media_key_error_event.cc',
-        'media_key_error_event.h',
-        'media_key_message_event.cc',
-        'media_key_message_event.h',
-        'media_key_needed_event.cc',
-        'media_key_needed_event.h',
         'media_query_list.cc',
         'media_query_list.h',
         'memory_info.cc',
@@ -287,6 +278,16 @@
       'conditions': [
         ['cobalt_media_source_2016==1', {
           'sources': [
+            'eme/media_encrypted_event.cc',
+            'eme/media_encrypted_event.h',
+            'eme/media_key_message_event.cc',
+            'eme/media_key_message_event.h',
+            'eme/media_key_session.cc',
+            'eme/media_key_session.h',
+            'eme/media_key_system_access.cc',
+            'eme/media_key_system_access.h',
+            'eme/media_keys.cc',
+            'eme/media_keys.h',
             'media_source/media_source.cc',
             'media_source/media_source.h',
             'media_source/source_buffer.cc',
@@ -299,6 +300,16 @@
           ],
         }, {
           'sources': [
+            'media_error.h',
+            'media_key_complete_event.cc',
+            'media_key_complete_event.h',
+            'media_key_error.h',
+            'media_key_error_event.cc',
+            'media_key_error_event.h',
+            'media_key_message_event.cc',
+            'media_key_message_event.h',
+            'media_key_needed_event.cc',
+            'media_key_needed_event.h',
             'media_source.cc',
             'media_source.h',
             'source_buffer.cc',
diff --git a/src/cobalt/dom/element.h b/src/cobalt/dom/element.h
index 1e64100..01901c9 100644
--- a/src/cobalt/dom/element.h
+++ b/src/cobalt/dom/element.h
@@ -71,6 +71,7 @@
 
   // Web API: Element
   //
+  base::Token local_name() const { return local_name_; }
 
   base::Token tag_name() const;
 
@@ -126,8 +127,6 @@
   // Custom, not in any spec.
   //
 
-  base::Token local_name() const { return local_name_; }
-
   // Returns whether the element has no children at all except comments or
   // processing instructions.
   //   https://www.w3.org/TR/selectors4/#empty-pseudo
diff --git a/src/cobalt/dom/element.idl b/src/cobalt/dom/element.idl
index 98a77a2..d168de1 100644
--- a/src/cobalt/dom/element.idl
+++ b/src/cobalt/dom/element.idl
@@ -15,6 +15,7 @@
 // https://www.w3.org/TR/dom/#element
 
 interface Element : Node {
+  readonly attribute DOMString localName;
   readonly attribute DOMString tagName;
   attribute DOMString id;
   attribute DOMString className;
diff --git a/src/cobalt/dom/element_test.cc b/src/cobalt/dom/element_test.cc
index 1e84b7a..5d1f52f 100644
--- a/src/cobalt/dom/element_test.cc
+++ b/src/cobalt/dom/element_test.cc
@@ -123,7 +123,7 @@
   EXPECT_EQ(NULL, text->AsElement());
 }
 
-TEST_F(ElementTest, TagName) {
+TEST_F(ElementTest, TagNameAndLocalName) {
   scoped_refptr<Element> element_in_html =
       new Element(document_, base::Token("eLeMeNt"));
   EXPECT_EQ("ELEMENT", element_in_html->tag_name());
diff --git a/src/cobalt/dom/html_media_element_eme.idl b/src/cobalt/dom/eme/html_media_element.idl
similarity index 80%
rename from src/cobalt/dom/html_media_element_eme.idl
rename to src/cobalt/dom/eme/html_media_element.idl
index 3b3d924..120d983 100644
--- a/src/cobalt/dom/html_media_element_eme.idl
+++ b/src/cobalt/dom/eme/html_media_element.idl
@@ -12,11 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#htmlmediaelement-extensions
+// https://www.w3.org/TR/encrypted-media/#htmlmediaelement-extensions
 
 partial interface HTMLMediaElement {
   readonly attribute MediaKeys? mediaKeys;
   attribute EventHandler onencrypted;
-  attribute EventHandler onwaitingforkey;
+  // TODO: Implement the event handler for the waitingforkey event.
+  // attribute EventHandler onwaitingforkey;
   Promise<void> setMediaKeys(MediaKeys? mediaKeys);
 };
diff --git a/src/cobalt/dom/eme/media_encrypted_event.cc b/src/cobalt/dom/eme/media_encrypted_event.cc
new file mode 100644
index 0000000..9bfe06c
--- /dev/null
+++ b/src/cobalt/dom/eme/media_encrypted_event.cc
@@ -0,0 +1,36 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/dom/eme/media_encrypted_event.h"
+
+#include "cobalt/base/tokens.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+// See step 5 in https://www.w3.org/TR/encrypted-media/#initdata-encountered.
+MediaEncryptedEvent::MediaEncryptedEvent(const std::string& type)
+    : Event(base::Token(type), kNotBubbles, kNotCancelable) {}
+
+// See step 5 in https://www.w3.org/TR/encrypted-media/#initdata-encountered.
+MediaEncryptedEvent::MediaEncryptedEvent(
+    const std::string& type, const MediaEncryptedEventInit& event_init_dict)
+    : Event(base::Token(type), kNotBubbles, kNotCancelable),
+      init_data_type_(event_init_dict.init_data_type()),
+      init_data_(event_init_dict.init_data()) {}
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
diff --git a/src/cobalt/dom/eme/media_encrypted_event.h b/src/cobalt/dom/eme/media_encrypted_event.h
new file mode 100644
index 0000000..c803777
--- /dev/null
+++ b/src/cobalt/dom/eme/media_encrypted_event.h
@@ -0,0 +1,55 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_DOM_EME_MEDIA_ENCRYPTED_EVENT_H_
+#define COBALT_DOM_EME_MEDIA_ENCRYPTED_EVENT_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "cobalt/dom/array_buffer.h"
+#include "cobalt/dom/eme/media_encrypted_event_init.h"
+#include "cobalt/dom/event.h"
+#include "cobalt/script/wrappable.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+// The MediaEncryptedEvent object is used for the encrypted event.
+//   https://www.w3.org/TR/encrypted-media/#mediaencryptedevent
+class MediaEncryptedEvent : public Event {
+ public:
+  // Web API: MediaEncryptedEvent
+  //
+
+  explicit MediaEncryptedEvent(const std::string& type);
+  MediaEncryptedEvent(const std::string& type,
+                      const MediaEncryptedEventInit& event_init_dict);
+
+  const std::string& init_data_type() const { return init_data_type_; }
+  const scoped_refptr<ArrayBuffer>& init_data() const { return init_data_; }
+
+  DEFINE_WRAPPABLE_TYPE(MediaEncryptedEvent);
+
+ private:
+  std::string init_data_type_;
+  scoped_refptr<ArrayBuffer> init_data_;
+};
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
+
+#endif  // COBALT_DOM_EME_MEDIA_ENCRYPTED_EVENT_H_
diff --git a/src/cobalt/dom/media_encrypted_event.idl b/src/cobalt/dom/eme/media_encrypted_event.idl
similarity index 80%
rename from src/cobalt/dom/media_encrypted_event.idl
rename to src/cobalt/dom/eme/media_encrypted_event.idl
index cd33c01..835165b 100644
--- a/src/cobalt/dom/media_encrypted_event.idl
+++ b/src/cobalt/dom/eme/media_encrypted_event.idl
@@ -12,12 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediaencryptedevent
-
-dictionary MediaEncryptedEventInit : EventInit {
-  DOMString initDataType = "";
-  ArrayBuffer? initData = null;
-};
+// https://www.w3.org/TR/encrypted-media/#mediaencryptedevent
 
 [Constructor(DOMString type, optional MediaEncryptedEventInit eventInitDict)]
 interface MediaEncryptedEvent : Event {
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/cobalt/dom/eme/media_encrypted_event_init.idl
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/cobalt/dom/eme/media_encrypted_event_init.idl
index 51e1f2e..25ad898 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/cobalt/dom/eme/media_encrypted_event_init.idl
@@ -12,9 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+// https://www.w3.org/TR/encrypted-media/#mediaencryptedeventinit
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
+dictionary MediaEncryptedEventInit : EventInit {
+  DOMString initDataType = "";
+  ArrayBuffer? initData = null;
 };
diff --git a/src/cobalt/dom/eme/media_key_message_event.cc b/src/cobalt/dom/eme/media_key_message_event.cc
new file mode 100644
index 0000000..0226561
--- /dev/null
+++ b/src/cobalt/dom/eme/media_key_message_event.cc
@@ -0,0 +1,33 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/dom/eme/media_key_message_event.h"
+
+#include "cobalt/base/tokens.h"
+#include "cobalt/dom/eme/media_key_message_type.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+// See step 2 in https://www.w3.org/TR/encrypted-media/#queue-message.
+MediaKeyMessageEvent::MediaKeyMessageEvent(
+    const std::string& type, const MediaKeyMessageEventInit& event_init_dict)
+    : Event(base::Token(type), kNotBubbles, kNotCancelable),
+      message_type_(event_init_dict.message_type()),
+      message_(event_init_dict.message()) {}
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
diff --git a/src/cobalt/dom/eme/media_key_message_event.h b/src/cobalt/dom/eme/media_key_message_event.h
new file mode 100644
index 0000000..aa3379e
--- /dev/null
+++ b/src/cobalt/dom/eme/media_key_message_event.h
@@ -0,0 +1,55 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_DOM_EME_MEDIA_KEY_MESSAGE_EVENT_H_
+#define COBALT_DOM_EME_MEDIA_KEY_MESSAGE_EVENT_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "cobalt/dom/array_buffer.h"
+#include "cobalt/dom/eme/media_key_message_event_init.h"
+#include "cobalt/dom/eme/media_key_message_type.h"
+#include "cobalt/dom/event.h"
+#include "cobalt/script/wrappable.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+// The MediaKeyMessageEvent object is used for the message event.
+//   https://www.w3.org/TR/encrypted-media/#mediakeymessageevent
+class MediaKeyMessageEvent : public Event {
+ public:
+  // Web IDL: MediaKeyMessageEvent
+  //
+
+  MediaKeyMessageEvent(const std::string& type,
+                       const MediaKeyMessageEventInit& event_init_dict);
+
+  MediaKeyMessageType message_type() const { return message_type_; }
+  const scoped_refptr<ArrayBuffer>& message() const { return message_; }
+
+  DEFINE_WRAPPABLE_TYPE(MediaKeyMessageEvent);
+
+ private:
+  MediaKeyMessageType message_type_;
+  scoped_refptr<ArrayBuffer> message_;
+};
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
+
+#endif  // COBALT_DOM_EME_MEDIA_KEY_MESSAGE_EVENT_H_
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/cobalt/dom/eme/media_key_message_event.idl
similarity index 69%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/cobalt/dom/eme/media_key_message_event.idl
index 51e1f2e..9e459ac 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/cobalt/dom/eme/media_key_message_event.idl
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+// https://www.w3.org/TR/encrypted-media/#mediakeymessageevent
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
+[Constructor(DOMString type, MediaKeyMessageEventInit eventInitDict)]
+interface MediaKeyMessageEvent : Event {
+  readonly attribute MediaKeyMessageType messageType;
+  readonly attribute ArrayBuffer message;
 };
diff --git a/src/cobalt/dom/media_key_message_event_init.idl b/src/cobalt/dom/eme/media_key_message_event_init.idl
similarity index 82%
rename from src/cobalt/dom/media_key_message_event_init.idl
rename to src/cobalt/dom/eme/media_key_message_event_init.idl
index 9115a44..0f6602c 100644
--- a/src/cobalt/dom/media_key_message_event_init.idl
+++ b/src/cobalt/dom/eme/media_key_message_event_init.idl
@@ -12,7 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// https://www.w3.org/TR/encrypted-media/#mediakeymessageeventinit
+
 dictionary MediaKeyMessageEventInit : EventInit {
-  MediaKeyMessageType messageType = "license-request";
-  ArrayBuffer message;
+  required MediaKeyMessageType messageType;
+  required ArrayBuffer message;
 };
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/cobalt/dom/eme/media_key_message_type.idl
similarity index 71%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/cobalt/dom/eme/media_key_message_type.idl
index 51e1f2e..1125463 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/cobalt/dom/eme/media_key_message_type.idl
@@ -12,9 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+// https://www.w3.org/TR/encrypted-media/#idl-def-mediakeymessagetype
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
+enum MediaKeyMessageType {
+  "license-request",
+  // TODO: Implement other message types.
+  // "license-renewal",
+  // "license-release",
+  // "individualization-request"
 };
diff --git a/src/cobalt/dom/eme/media_key_session.cc b/src/cobalt/dom/eme/media_key_session.cc
new file mode 100644
index 0000000..f66bf48
--- /dev/null
+++ b/src/cobalt/dom/eme/media_key_session.cc
@@ -0,0 +1,325 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/dom/eme/media_key_session.h"
+
+#include "cobalt/dom/array_buffer.h"
+#include "cobalt/dom/array_buffer_view.h"
+#include "cobalt/dom/dom_exception.h"
+#include "cobalt/dom/eme/media_key_message_event.h"
+#include "cobalt/dom/eme/media_key_message_event_init.h"
+#include "cobalt/dom/eme/media_keys.h"
+#include "cobalt/script/script_value_factory.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+// See step 3.1 of
+// https://www.w3.org/TR/encrypted-media/#dom-mediakeys-createsession.
+MediaKeySession::MediaKeySession(
+    scoped_ptr<media::DrmSystem::Session> drm_system_session,
+    script::ScriptValueFactory* script_value_factory,
+    const ClosedCallback& closed_callback)
+    : drm_system_session_(drm_system_session.Pass()),
+      script_value_factory_(script_value_factory),
+      uninitialized_(true),
+      callable_(false),
+      closed_callback_(closed_callback),
+      ALLOW_THIS_IN_INITIALIZER_LIST(closed_promise_reference_(
+          this, script_value_factory->CreateBasicPromise<void>())),
+      initiated_by_generate_request_(false) {}
+
+// Session ID should be empty for uninitialized sessions according to step 3.1
+// of https://www.w3.org/TR/encrypted-media/#dom-mediakeys-createsession.
+std::string MediaKeySession::session_id() const {
+  return drm_system_session_->id().value_or("");
+}
+
+MediaKeySession::~MediaKeySession() {}
+
+const MediaKeySession::VoidPromiseValue* MediaKeySession::closed() const {
+  return &closed_promise_reference_.referenced_value();
+}
+
+const EventTarget::EventListenerScriptValue* MediaKeySession::onmessage()
+    const {
+  return GetAttributeEventListener(base::Tokens::message());
+}
+
+void MediaKeySession::set_onmessage(
+    const EventListenerScriptValue& event_listener) {
+  SetAttributeEventListener(base::Tokens::message(), event_listener);
+}
+
+namespace {
+
+void GetBufferAndSize(const BufferSource& buffer_source, const uint8** buffer,
+                      int* buffer_size) {
+  if (buffer_source.IsType<scoped_refptr<ArrayBufferView> >()) {
+    scoped_refptr<ArrayBufferView> array_buffer_view =
+        buffer_source.AsType<scoped_refptr<ArrayBufferView> >();
+    *buffer = static_cast<const uint8*>(array_buffer_view->base_address());
+    *buffer_size = array_buffer_view->byte_length();
+  } else if (buffer_source.IsType<scoped_refptr<ArrayBuffer> >()) {
+    scoped_refptr<ArrayBuffer> array_buffer =
+        buffer_source.AsType<scoped_refptr<ArrayBuffer> >();
+    *buffer = array_buffer->data();
+    *buffer_size = array_buffer->byte_length();
+  } else {
+    NOTREACHED();
+  }
+}
+
+}  // namespace
+
+// See
+// https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-generaterequest.
+scoped_ptr<MediaKeySession::VoidPromiseValue> MediaKeySession::GenerateRequest(
+    const std::string& init_data_type, const BufferSource& init_data) {
+  scoped_ptr<VoidPromiseValue> promise =
+      script_value_factory_->CreateBasicPromise<void>();
+  VoidPromiseValue::StrongReference promise_reference(*promise);
+
+  // 1. If this object is closed, return a promise rejected with
+  //    an InvalidStateError.
+  // 2. If this object's uninitialized value is false, return a promise rejected
+  //    with an InvalidStateError.
+  if (drm_system_session_->is_closed() || !uninitialized_) {
+    promise_reference.value().Reject(
+        new DOMException(DOMException::kInvalidStateErr));
+    return promise.Pass();
+  }
+
+  // 3. Let this object's uninitialized value be false.
+  uninitialized_ = false;
+
+  const uint8* init_data_buffer;
+  int init_data_buffer_size;
+  GetBufferAndSize(init_data, &init_data_buffer, &init_data_buffer_size);
+
+  // 4. If initDataType is the empty string, return a promise rejected with
+  //    a newly created TypeError.
+  // 5. If initData is an empty array, return a promise rejected with a newly
+  //    created TypeError.
+  if (init_data_type.empty() || init_data_buffer_size == 0) {
+    promise_reference.value().Reject(script::kTypeError);
+    return promise.Pass();
+  }
+
+  // 10.2. The user agent must thoroughly validate the initialization data
+  //       before passing it to the CDM.
+  //
+  // Sanitation is the responsibility of Starboard implementers.
+
+  // 10.9. Use the CDM.
+  initiated_by_generate_request_ = true;
+  drm_system_session_->GenerateUpdateRequest(
+      init_data_type, init_data_buffer, init_data_buffer_size,
+      base::Bind(&MediaKeySession::OnSessionUpdateRequestGenerated,
+                 base::AsWeakPtr(this),
+                 base::Owned(new VoidPromiseValue::Reference(this, *promise))),
+      base::Bind(&MediaKeySession::OnSessionUpdateRequestDidNotGenerate,
+                 base::AsWeakPtr(this),
+                 base::Owned(new VoidPromiseValue::Reference(this, *promise))));
+
+  // 11. Return promise.
+  return promise.Pass();
+}
+
+// See https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-update.
+scoped_ptr<MediaKeySession::VoidPromiseValue> MediaKeySession::Update(
+    const BufferSource& response) {
+  scoped_ptr<VoidPromiseValue> promise =
+      script_value_factory_->CreateBasicPromise<void>();
+  VoidPromiseValue::StrongReference promise_reference(*promise);
+
+  // 1. If this object is closed, return a promise rejected with
+  //    an InvalidStateError.
+  // 2. If this object's callable value is false, return a promise rejected
+  //    with an InvalidStateError.
+  if (drm_system_session_->is_closed() || !callable_) {
+    promise_reference.value().Reject(
+        new DOMException(DOMException::kInvalidStateErr));
+    return promise.Pass();
+  }
+
+  const uint8* response_buffer;
+  int response_buffer_size;
+  GetBufferAndSize(response, &response_buffer, &response_buffer_size);
+
+  // 3. If response is an empty array, return a promise rejected with a newly
+  //    created TypeError.
+  if (response_buffer_size == 0) {
+    promise_reference.value().Reject(script::kTypeError);
+    return promise.Pass();
+  }
+
+  // 6.1. Let sanitized response be a validated and/or sanitized version of
+  //      response copy.
+  //
+  // Sanitation is the responsibility of Starboard implementers.
+
+  // 6.7. Use the CDM.
+  drm_system_session_->Update(
+      response_buffer, response_buffer_size,
+      base::Bind(&MediaKeySession::OnSessionUpdated, base::AsWeakPtr(this),
+                 base::Owned(new VoidPromiseValue::Reference(this, *promise))),
+      base::Bind(&MediaKeySession::OnSessionDidNotUpdate, base::AsWeakPtr(this),
+                 base::Owned(new VoidPromiseValue::Reference(this, *promise))));
+
+  // 7. Return promise.
+  return promise.Pass();
+}
+
+// See https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-close.
+scoped_ptr<MediaKeySession::VoidPromiseValue> MediaKeySession::Close() {
+  scoped_ptr<VoidPromiseValue> promise =
+      script_value_factory_->CreateBasicPromise<void>();
+  VoidPromiseValue::StrongReference promise_reference(*promise);
+
+  // 2. If session is closed, return a resolved promise.
+  if (drm_system_session_->is_closed()) {
+    promise_reference.value().Resolve();
+    return promise.Pass();
+  }
+
+  // 3. If session's callable value is false, return a promise rejected with
+  //    an InvalidStateError.
+  if (!callable_) {
+    promise_reference.value().Reject(
+        new DOMException(DOMException::kInvalidStateErr));
+    return promise.Pass();
+  }
+
+  // 5.2. Use CDM to close the key session associated with session.
+  drm_system_session_->Close();
+
+  // Let |MediaKeys| know that the session should be removed from the list
+  // of open sessions.
+  closed_callback_.Run(this);
+
+  // 5.3.1. Run the Session Closed algorithm on the session.
+  OnClosed();
+
+  // 5.3.2. Resolve promise.
+  promise_reference.value().Resolve();
+  return promise.Pass();
+}
+
+// See
+// https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-generaterequest.
+void MediaKeySession::OnSessionUpdateRequestGenerated(
+    VoidPromiseValue::Reference* promise_reference, scoped_array<uint8> message,
+    int message_size) {
+  MediaKeyMessageEventInit media_key_message_event_init;
+  // 10.9.4. If a license request for the requested license type can be
+  //         generated based on the sanitized init data:
+  // 10.9.4.1. Let message be a license request for the requested license type
+  //           generated based on the sanitized init data interpreted
+  //           per initDataType.
+  // Otherwise:
+  // 10.9.4.1. Let message be the request that needs to be processed before
+  //           a license request request for the requested license type can be
+  //           generated based on the sanitized init data.
+  media_key_message_event_init.set_message(new ArrayBuffer(
+      NULL, ArrayBuffer::kFromHeap, message.Pass(), message_size));
+  // 10.9.4.2. Let message type reflect the type of message, either
+  //           "license-request" or "individualization-request".
+  //
+  // TODO: Introduce message type parameter to |SbDrmSessionUpdateRequestFunc|
+  //       and stop pretending that all messages are license requests.
+  media_key_message_event_init.set_message_type(
+      kMediaKeyMessageTypeLicenseRequest);
+
+  // 10.3. Let this object's callable value be true.
+  callable_ = true;
+
+  // 10.4. Run the Queue a "message" Event algorithm on the session.
+  //
+  // TODO: Implement Event.isTrusted as per
+  //       https://www.w3.org/TR/dom/#dom-event-istrusted and set it to true.
+  DispatchEvent(
+      new MediaKeyMessageEvent("message", media_key_message_event_init));
+
+  // 10.5. Resolve promise.
+  //
+  // If the request was generated spontaneously by the underlying DRM system,
+  // we shouldn't resolve the promise returned by |GenerateRequest|. The promise
+  // was resolved in the first invocation of this method and now is simply
+  // hanging around.
+  if (initiated_by_generate_request_) {
+    initiated_by_generate_request_ = false;
+    promise_reference->value().Resolve();
+  }
+}
+
+// See
+// https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-generaterequest.
+void MediaKeySession::OnSessionUpdateRequestDidNotGenerate(
+    VoidPromiseValue::Reference* promise_reference) {
+  // 10.10.1. If any of the preceding steps failed, reject promise with a new
+  //          DOMException whose name is the appropriate error name.
+  //
+  // TODO: Introduce Starboard API that allows CDM to propagate error codes.
+  promise_reference->value().Reject(new DOMException(DOMException::kNone));
+}
+
+// See https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-update.
+void MediaKeySession::OnSessionUpdated(
+    VoidPromiseValue::Reference* promise_reference) {
+  // 8.1.1. If the set of keys known to the CDM for this object changed or
+  //        the status of any key(s) changed, run the Update Key Statuses
+  //        algorithm on the session.
+  //
+  // TODO: Implement key statuses.
+
+  // 8.1.2. If the expiration time for the session changed, run the Update
+  //        Expiration algorithm on the session.
+  //
+  // TODO: Implement expiration.
+
+  // 8.2. Resolve promise.
+  promise_reference->value().Resolve();
+}
+
+// See https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-update.
+void MediaKeySession::OnSessionDidNotUpdate(
+    VoidPromiseValue::Reference* promise_reference) {
+  // 8.1.3. If any of the preceding steps failed, reject promise with a new
+  //        DOMException whose name is the appropriate error name.
+  //
+  // TODO: Introduce Starboard API that allows CDM to propagate error codes.
+  promise_reference->value().Reject(new DOMException(DOMException::kNone));
+}
+
+// See https://www.w3.org/TR/encrypted-media/#session-closed.
+void MediaKeySession::OnClosed() {
+  // 2. Run the Update Key Statuses algorithm on the session, providing an empty
+  //    sequence.
+  //
+  // TODO: Implement key statuses.
+
+  // 3. Run the Update Expiration algorithm on the session, providing NaN.
+  //
+  // TODO: Implement expiration.
+
+  // 4. Let promise be the closed attribute of the session.
+  // 5. Resolve promise.
+  closed_promise_reference_.value().Resolve();
+}
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
diff --git a/src/cobalt/dom/eme/media_key_session.h b/src/cobalt/dom/eme/media_key_session.h
new file mode 100644
index 0000000..4419362
--- /dev/null
+++ b/src/cobalt/dom/eme/media_key_session.h
@@ -0,0 +1,91 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_DOM_EME_MEDIA_KEY_SESSION_H_
+#define COBALT_DOM_EME_MEDIA_KEY_SESSION_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "cobalt/dom/buffer_source.h"
+#include "cobalt/dom/event_target.h"
+#include "cobalt/media/base/drm_system.h"
+#include "cobalt/script/promise.h"
+#include "cobalt/script/script_value_factory.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+// A session provides a context for message exchange with the CDM as a result
+// of which keys are made available to the CDM.
+//   https://www.w3.org/TR/encrypted-media/#key-session
+//
+// Also see https://www.w3.org/TR/encrypted-media/#mediakeysession-interface.
+class MediaKeySession : public EventTarget {
+ public:
+  typedef script::ScriptValue<script::Promise<void> > VoidPromiseValue;
+  typedef base::Callback<void(MediaKeySession* session)> ClosedCallback;
+
+  // Custom, not in any spec.
+  MediaKeySession(scoped_ptr<media::DrmSystem::Session> drm_system_session,
+                  script::ScriptValueFactory* script_value_factory,
+                  const ClosedCallback& closed_callback);
+
+  // Web IDL: MediaKeySession.
+  std::string session_id() const;
+  const VoidPromiseValue* closed() const;
+  const EventListenerScriptValue* onmessage() const;
+  void set_onmessage(const EventListenerScriptValue& event_listener);
+  scoped_ptr<VoidPromiseValue> GenerateRequest(
+      const std::string& init_data_type, const BufferSource& init_data);
+  scoped_ptr<VoidPromiseValue> Update(const BufferSource& response);
+  scoped_ptr<VoidPromiseValue> Close();
+
+  DEFINE_WRAPPABLE_TYPE(MediaKeySession);
+
+ private:
+  ~MediaKeySession() OVERRIDE;
+
+  void OnSessionUpdateRequestGenerated(
+      VoidPromiseValue::Reference* promise_reference,
+      scoped_array<uint8> message, int message_size);
+  void OnSessionUpdateRequestDidNotGenerate(
+      VoidPromiseValue::Reference* promise_reference);
+  void OnSessionUpdated(VoidPromiseValue::Reference* promise_reference);
+  void OnSessionDidNotUpdate(VoidPromiseValue::Reference* promise_reference);
+  void OnClosed();
+
+  scoped_ptr<media::DrmSystem::Session> drm_system_session_;
+  script::ScriptValueFactory* const script_value_factory_;
+  bool uninitialized_;
+  bool callable_;
+
+  // TODO: Remove |closed_callback_| and change call sites to use closed()
+  //       promise instead, once Cobalt switches to native SpiderMonkey
+  //       promises.
+  const ClosedCallback closed_callback_;
+  const VoidPromiseValue::Reference closed_promise_reference_;
+
+  bool initiated_by_generate_request_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaKeySession);
+};
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
+
+#endif  // COBALT_DOM_EME_MEDIA_KEY_SESSION_H_
diff --git a/src/cobalt/dom/eme/media_key_session.idl b/src/cobalt/dom/eme/media_key_session.idl
new file mode 100644
index 0000000..c458e27
--- /dev/null
+++ b/src/cobalt/dom/eme/media_key_session.idl
@@ -0,0 +1,35 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// https://www.w3.org/TR/encrypted-media/#mediakeysession-interface
+
+interface MediaKeySession : EventTarget {
+  readonly attribute DOMString sessionId;
+  // TODO: Implement |expiration|.
+  // readonly attribute unrestricted double expiration;
+  readonly attribute Promise<void> closed;
+  // TODO: Implement |keyStatuses|.
+  // readonly attribute MediaKeyStatusMap keyStatuses;
+  // TODO: Implement |onkeystatuseschange|.
+  // attribute EventHandler onkeystatuseschange;
+  attribute EventHandler onmessage;
+  Promise<void> generateRequest(DOMString initDataType,
+                                BufferSource initData);
+  // TODO: Trivially implement persistent sessions.
+  // Promise<boolean> load(DOMString sessionId);
+  Promise<void> update(BufferSource response);
+  Promise<void> close();
+  // TODO: Implement |remove|.
+  // Promise<void> remove();
+};
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/cobalt/dom/eme/media_key_session_type.idl
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/cobalt/dom/eme/media_key_session_type.idl
index 51e1f2e..eb82c35 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/cobalt/dom/eme/media_key_session_type.idl
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+// https://www.w3.org/TR/encrypted-media/#idl-def-mediakeysessiontype
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
+enum MediaKeySessionType {
+  "temporary",
+  // TODO: Trivially implement persistent sessions.
+  // "persistent-license"
 };
diff --git a/src/cobalt/dom/eme/media_key_system_access.cc b/src/cobalt/dom/eme/media_key_system_access.cc
new file mode 100644
index 0000000..14c8f2c
--- /dev/null
+++ b/src/cobalt/dom/eme/media_key_system_access.cc
@@ -0,0 +1,53 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/dom/eme/media_key_system_access.h"
+
+#include "cobalt/dom/eme/media_keys.h"
+#include "cobalt/script/script_value_factory.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+MediaKeySystemAccess::MediaKeySystemAccess(
+    const std::string& key_system,
+    const MediaKeySystemConfiguration& configuration,
+    script::ScriptValueFactory* script_value_factory)
+    : key_system_(key_system),
+      configuration_(configuration),
+      script_value_factory_(script_value_factory) {}
+
+// See
+// https://www.w3.org/TR/encrypted-media/#dom-mediakeysystemaccess-createmediakeys.
+scoped_ptr<MediaKeySystemAccess::InterfacePromiseValue>
+MediaKeySystemAccess::CreateMediaKeys() const {
+  // 1. Let promise be a new promise.
+  scoped_ptr<InterfacePromiseValue> promise =
+      script_value_factory_
+          ->CreateInterfacePromise<scoped_refptr<MediaKeys> >();
+  InterfacePromiseValue::StrongReference promise_reference(*promise);
+
+  // 2.10. Let media keys be a new MediaKeys object.
+  scoped_refptr<MediaKeys> media_keys(
+      new MediaKeys(key_system_, script_value_factory_));
+
+  // 2.11. Resolve promise with media keys.
+  promise_reference.value().Resolve(media_keys);
+  return promise.Pass();
+}
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
diff --git a/src/cobalt/dom/eme/media_key_system_access.h b/src/cobalt/dom/eme/media_key_system_access.h
new file mode 100644
index 0000000..4bf3fb2
--- /dev/null
+++ b/src/cobalt/dom/eme/media_key_system_access.h
@@ -0,0 +1,64 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_DOM_EME_MEDIA_KEY_SYSTEM_ACCESS_H_
+#define COBALT_DOM_EME_MEDIA_KEY_SYSTEM_ACCESS_H_
+
+#include <string>
+
+#include "cobalt/dom/eme/media_key_system_configuration.h"
+#include "cobalt/script/promise.h"
+#include "cobalt/script/script_value_factory.h"
+#include "cobalt/script/wrappable.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+// Provides access to a key system.
+//   https://www.w3.org/TR/encrypted-media/#mediakeysystemaccess-interface
+class MediaKeySystemAccess : public script::Wrappable {
+ public:
+  typedef script::ScriptValue<script::Promise<
+      scoped_refptr<script::Wrappable> > > InterfacePromiseValue;
+
+  // Custom, not in any spec.
+  MediaKeySystemAccess(const std::string& key_system,
+                       const MediaKeySystemConfiguration& configuration,
+                       script::ScriptValueFactory* script_value_factory);
+
+  // Web API: MediaKeySystemAccess.
+  const std::string& key_system() const { return key_system_; }
+  const MediaKeySystemConfiguration& GetConfiguration() const {
+    return configuration_;
+  }
+  scoped_ptr<InterfacePromiseValue> CreateMediaKeys() const;
+
+  DEFINE_WRAPPABLE_TYPE(MediaKeySystemAccess);
+
+ private:
+  ~MediaKeySystemAccess() OVERRIDE {}
+
+  const std::string key_system_;
+  const MediaKeySystemConfiguration configuration_;
+  script::ScriptValueFactory* script_value_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaKeySystemAccess);
+};
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
+
+#endif  // COBALT_DOM_EME_MEDIA_KEY_SYSTEM_ACCESS_H_
diff --git a/src/cobalt/dom/media_key_system_access.idl b/src/cobalt/dom/eme/media_key_system_access.idl
similarity index 82%
rename from src/cobalt/dom/media_key_system_access.idl
rename to src/cobalt/dom/eme/media_key_system_access.idl
index 15f7210..c8d99d2 100644
--- a/src/cobalt/dom/media_key_system_access.idl
+++ b/src/cobalt/dom/eme/media_key_system_access.idl
@@ -12,13 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemaccess-interface
-
-enum MediaKeysRequirement {
-  "required",
-  "optional",
-  "not-allowed"
-};
+// https://www.w3.org/TR/encrypted-media/#mediakeysystemaccess-interface
 
 interface MediaKeySystemAccess {
   readonly attribute DOMString keySystem;
diff --git a/src/cobalt/dom/eme/media_key_system_configuration.idl b/src/cobalt/dom/eme/media_key_system_configuration.idl
new file mode 100644
index 0000000..5c53286
--- /dev/null
+++ b/src/cobalt/dom/eme/media_key_system_configuration.idl
@@ -0,0 +1,28 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// https://www.w3.org/TR/encrypted-media/#mediakeysystemconfiguration-dictionary
+
+// TODO: Implement default values for sequence types.
+dictionary MediaKeySystemConfiguration {
+  DOMString label = "";
+  sequence<DOMString> initDataTypes /*= []*/;
+  sequence<MediaKeySystemMediaCapability> audioCapabilities /*= []*/;
+  sequence<MediaKeySystemMediaCapability> videoCapabilities /*= []*/;
+  // TODO: Implement distinctive identifiers.
+  // MediaKeysRequirement distinctiveIdentifier = "optional";
+  // TODO: Trivially implement persistent sessions.
+  // MediaKeysRequirement persistentState = "optional";
+  // sequence<DOMString> sessionTypes;
+};
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/cobalt/dom/eme/media_key_system_media_capability.idl
similarity index 73%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/cobalt/dom/eme/media_key_system_media_capability.idl
index 51e1f2e..f78210f 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/cobalt/dom/eme/media_key_system_media_capability.idl
@@ -12,9 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+// https://www.w3.org/TR/encrypted-media/#mediakeysystemmediacapability-dictionary
 
 dictionary MediaKeySystemMediaCapability {
   DOMString contentType = "";
-  DOMString robustness = "";
+  // TODO: Implement robustness as per
+  //       https://www.w3.org/TR/encrypted-media/#dom-mediakeysystemmediacapability-robustness.
+  // DOMString robustness = "";
 };
diff --git a/src/cobalt/dom/eme/media_keys.cc b/src/cobalt/dom/eme/media_keys.cc
new file mode 100644
index 0000000..861d44d
--- /dev/null
+++ b/src/cobalt/dom/eme/media_keys.cc
@@ -0,0 +1,60 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/dom/eme/media_keys.h"
+
+#include "base/bind.h"
+#include "cobalt/dom/dom_exception.h"
+#include "cobalt/dom/eme/media_key_session.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+MediaKeys::MediaKeys(const std::string& key_system,
+                     script::ScriptValueFactory* script_value_factory)
+    : script_value_factory_(script_value_factory),
+      drm_system_(new media::DrmSystem(key_system.c_str())) {}
+
+// See https://www.w3.org/TR/encrypted-media/#dom-mediakeys-createsession.
+scoped_refptr<MediaKeySession> MediaKeys::CreateSession(
+    MediaKeySessionType session_type, script::ExceptionState* exception_state) {
+  // 1. If this object's supported session types value does not contain
+  //    sessionType, throw a NotSupportedError.
+  if (session_type != kMediaKeySessionTypeTemporary) {
+    DOMException::Raise(DOMException::kNotSupportedErr, exception_state);
+    return NULL;
+  }
+
+  // 3. Let session be a new MediaKeySession object.
+  scoped_refptr<MediaKeySession> session(new MediaKeySession(
+      drm_system_->CreateSession(), script_value_factory_,
+      base::Bind(&MediaKeys::OnSessionClosed, base::Unretained(this))));
+  open_sessions_.push_back(session);
+  return session;
+}
+
+void MediaKeys::OnSessionClosed(MediaKeySession* session) {
+  // Erase-remove idiom, see
+  // https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom.
+  open_sessions_.erase(
+      std::remove(open_sessions_.begin(), open_sessions_.end(), session),
+      open_sessions_.end());
+}
+
+MediaKeys::~MediaKeys() {}
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
diff --git a/src/cobalt/dom/eme/media_keys.h b/src/cobalt/dom/eme/media_keys.h
new file mode 100644
index 0000000..52013df
--- /dev/null
+++ b/src/cobalt/dom/eme/media_keys.h
@@ -0,0 +1,77 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_DOM_EME_MEDIA_KEYS_H_
+#define COBALT_DOM_EME_MEDIA_KEYS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "cobalt/dom/buffer_source.h"
+#include "cobalt/dom/eme/media_key_session.h"
+#include "cobalt/dom/eme/media_key_session_type.h"
+#include "cobalt/media/base/drm_system.h"
+#include "cobalt/script/script_value_factory.h"
+#include "cobalt/script/wrappable.h"
+
+namespace cobalt {
+namespace dom {
+namespace eme {
+
+// Represents a set of keys that an associated HTMLMediaElement can use
+// for decryption of media data during playback.
+//   https://www.w3.org/TR/encrypted-media/#mediakeys-interface
+class MediaKeys : public script::Wrappable {
+ public:
+  // Custom, not in any spec.
+
+  MediaKeys(const std::string& key_system,
+            script::ScriptValueFactory* script_value_factory);
+
+  media::DrmSystem* drm_system() const { return drm_system_.get(); }
+
+  // Web API: MediaKeys.
+
+  scoped_refptr<MediaKeySession> CreateSession(
+      MediaKeySessionType session_type,
+      script::ExceptionState* exception_state);
+
+  DEFINE_WRAPPABLE_TYPE(MediaKeys);
+
+ private:
+  ~MediaKeys() OVERRIDE;
+
+  void OnSessionClosed(MediaKeySession* session);
+
+  script::ScriptValueFactory* script_value_factory_;
+  scoped_ptr<media::DrmSystem> drm_system_;
+
+  // A MediaKeySession object shall not be destroyed and shall continue
+  // to receive events if it is not closed and the MediaKeys object that created
+  // it remains accessible.
+  //   https://www.w3.org/TR/encrypted-media/#mediakeysession-interface
+  //
+  // Number of sessions is expected to be very small, typically one.
+  std::vector<scoped_refptr<MediaKeySession> > open_sessions_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaKeys);
+};
+
+}  // namespace eme
+}  // namespace dom
+}  // namespace cobalt
+
+#endif  // COBALT_DOM_EME_MEDIA_KEYS_H_
diff --git a/src/cobalt/dom/media_keys.idl b/src/cobalt/dom/eme/media_keys.idl
similarity index 65%
rename from src/cobalt/dom/media_keys.idl
rename to src/cobalt/dom/eme/media_keys.idl
index 4c4aa1b..fc1a35f 100644
--- a/src/cobalt/dom/media_keys.idl
+++ b/src/cobalt/dom/eme/media_keys.idl
@@ -12,15 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeys-interface
-
-enum MediaKeySessionType {
-  "temporary",
-  "persistent-usage-record",
-  "persistent-license"
-};
+// https://www.w3.org/TR/encrypted-media/#mediakeys-interface
 
 interface MediaKeys {
-  MediaKeySession createSession(optional MediaKeySessionType sessionType = "temporary");
-  Promise<boolean> setServerCertificate(BufferSource serverCertificate);
+  [RaisesException] MediaKeySession createSession(
+      optional MediaKeySessionType sessionType = "temporary");
+  // TODO: Trivially implement server certificates.
+  // Promise<boolean> setServerCertificate(BufferSource serverCertificate);
 };
diff --git a/src/cobalt/dom/media_keys_requirement.idl b/src/cobalt/dom/eme/media_keys_requirement.idl
similarity index 100%
rename from src/cobalt/dom/media_keys_requirement.idl
rename to src/cobalt/dom/eme/media_keys_requirement.idl
diff --git a/src/cobalt/dom/navigator_eme.idl b/src/cobalt/dom/eme/navigator.idl
similarity index 69%
rename from src/cobalt/dom/navigator_eme.idl
rename to src/cobalt/dom/eme/navigator.idl
index f0219ad..1abf852 100644
--- a/src/cobalt/dom/navigator_eme.idl
+++ b/src/cobalt/dom/eme/navigator.idl
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#navigator-extension-requestmediakeysystemaccess
+// https://www.w3.org/TR/encrypted-media/#navigator-extension-requestmediakeysystemaccess
 
 partial interface Navigator {
-    Promise<MediaKeySystemAccess> requestMediaKeySystemAccess(
-        DOMString keySystem,
-        sequence<MediaKeySystemConfiguration> supportedConfigurations);
+  Promise<MediaKeySystemAccess> requestMediaKeySystemAccess(
+      DOMString keySystem,
+      sequence<MediaKeySystemConfiguration> supportedConfigurations);
 };
diff --git a/src/cobalt/dom/font_cache.cc b/src/cobalt/dom/font_cache.cc
index 28da2c0..4fff414 100644
--- a/src/cobalt/dom/font_cache.cc
+++ b/src/cobalt/dom/font_cache.cc
@@ -90,6 +90,17 @@
   }
 }
 
+void FontCache::PurgeCachedResources() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  font_face_map_->clear();
+  font_list_map_.clear();
+  inactive_font_set_.clear();
+  font_map_.clear();
+  character_fallback_typeface_maps_.clear();
+  requested_remote_typeface_cache_.clear();
+  local_typeface_map_.clear();
+}
+
 void FontCache::ProcessInactiveFontListsAndFonts() {
   DCHECK(thread_checker_.CalledOnValidThread());
   base::TimeTicks current_time = base::TimeTicks::Now();
diff --git a/src/cobalt/dom/font_cache.h b/src/cobalt/dom/font_cache.h
index 3d05696..e90adf9 100644
--- a/src/cobalt/dom/font_cache.h
+++ b/src/cobalt/dom/font_cache.h
@@ -181,6 +181,9 @@
   // the map.
   void SetFontFaceMap(scoped_ptr<FontFaceMap> font_face_map);
 
+  // Purge all caches within the font cache.
+  void PurgeCachedResources();
+
   // Process unused font lists and fonts, potentially purging them from the
   // cache if they meet the removal requirements.
   void ProcessInactiveFontListsAndFonts();
diff --git a/src/cobalt/dom/html_element_context.cc b/src/cobalt/dom/html_element_context.cc
index b7aeed0..064403a 100644
--- a/src/cobalt/dom/html_element_context.cc
+++ b/src/cobalt/dom/html_element_context.cc
@@ -35,6 +35,7 @@
       remote_typeface_cache_(NULL),
       mesh_cache_(NULL),
       dom_stat_tracker_(NULL),
+      video_playback_rate_multiplier_(1.f),
       sync_load_thread_("Synchronous Load"),
       html_element_factory_(new HTMLElementFactory()) {
   sync_load_thread_.Start();
@@ -54,7 +55,7 @@
         reduced_image_cache_capacity_manager,
     loader::font::RemoteTypefaceCache* remote_typeface_cache,
     loader::mesh::MeshCache* mesh_cache, DomStatTracker* dom_stat_tracker,
-    const std::string& language)
+    const std::string& language, float video_playback_rate_multiplier)
     : fetcher_factory_(fetcher_factory),
       css_parser_(css_parser),
       dom_parser_(dom_parser),
@@ -72,6 +73,7 @@
       mesh_cache_(mesh_cache),
       dom_stat_tracker_(dom_stat_tracker),
       language_(language),
+      video_playback_rate_multiplier_(video_playback_rate_multiplier),
       sync_load_thread_("Synchronous Load"),
       html_element_factory_(new HTMLElementFactory()) {
   sync_load_thread_.Start();
diff --git a/src/cobalt/dom/html_element_context.h b/src/cobalt/dom/html_element_context.h
index cae6ad8..2eb952f 100644
--- a/src/cobalt/dom/html_element_context.h
+++ b/src/cobalt/dom/html_element_context.h
@@ -61,7 +61,7 @@
           reduced_image_cache_capacity_manager,
       loader::font::RemoteTypefaceCache* remote_typeface_cache,
       loader::mesh::MeshCache* mesh_cache, DomStatTracker* dom_stat_tracker,
-      const std::string& language);
+      const std::string& language, float video_playback_rate_multiplier = 1.0);
   ~HTMLElementContext();
 
   loader::FetcherFactory* fetcher_factory() { return fetcher_factory_; }
@@ -107,6 +107,10 @@
 
   const std::string& language() const { return language_; }
 
+  float video_playback_rate_multiplier() const {
+    return video_playback_rate_multiplier_;
+  }
+
   base::Thread* sync_load_thread() { return &sync_load_thread_; }
 
   HTMLElementFactory* html_element_factory() {
@@ -136,6 +140,7 @@
   loader::mesh::MeshCache* const mesh_cache_;
   DomStatTracker* const dom_stat_tracker_;
   const std::string language_;
+  const float video_playback_rate_multiplier_;
 
   base::Thread sync_load_thread_;
   scoped_ptr<HTMLElementFactory> html_element_factory_;
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index 5e98f55..869d4c2 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -33,19 +33,23 @@
 #include "cobalt/dom/event.h"
 #include "cobalt/dom/html_element_context.h"
 #include "cobalt/dom/html_video_element.h"
-#include "cobalt/dom/media_key_complete_event.h"
-#include "cobalt/dom/media_key_error_event.h"
-#include "cobalt/dom/media_key_message_event.h"
-#include "cobalt/dom/media_key_needed_event.h"
 #include "cobalt/dom/media_source.h"
 #include "cobalt/dom/media_source_ready_state.h"
 #include "cobalt/loader/fetcher_factory.h"
 #include "cobalt/media/fetcher_buffered_data_source.h"
 #include "cobalt/media/web_media_player_factory.h"
+#include "cobalt/script/script_value_factory.h"
+#include "starboard/double.h"
 
 #if defined(COBALT_MEDIA_SOURCE_2016)
+#include "cobalt/dom/eme/media_encrypted_event.h"
+#include "cobalt/dom/eme/media_encrypted_event_init.h"
 #include "cobalt/media/base/media_log.h"
 #else  // defined(COBALT_MEDIA_SOURCE_2016)
+#include "cobalt/dom/media_key_complete_event.h"
+#include "cobalt/dom/media_key_error_event.h"
+#include "cobalt/dom/media_key_message_event.h"
+#include "cobalt/dom/media_key_needed_event.h"
 #include "media/base/filter_collection.h"
 #include "media/base/media_log.h"
 #endif  // defined(COBALT_MEDIA_SOURCE_2016)
@@ -80,23 +84,6 @@
 
 #endif  // LOG_MEDIA_ELEMENT_ACTIVITIES
 
-void RaiseMediaKeyException(WebMediaPlayer::MediaKeyException exception,
-                            script::ExceptionState* exception_state) {
-  DCHECK_NE(exception, WebMediaPlayer::kMediaKeyExceptionNoError);
-  switch (exception) {
-    case WebMediaPlayer::kMediaKeyExceptionInvalidPlayerState:
-      DOMException::Raise(DOMException::kInvalidStateErr, exception_state);
-      break;
-    case WebMediaPlayer::kMediaKeyExceptionKeySystemNotSupported:
-      DOMException::Raise(DOMException::kNotSupportedErr, exception_state);
-      break;
-    case WebMediaPlayer::kMediaKeyExceptionNoError:
-    default:
-      NOTREACHED();
-      break;
-  }
-}
-
 // This struct manages the user log information for HTMLMediaElement count.
 struct HTMLMediaElementCountLog {
   HTMLMediaElementCountLog() : count(0) {
@@ -122,7 +109,7 @@
     : HTMLElement(document, tag_name),
       load_state_(kWaitingForSource),
       ALLOW_THIS_IN_INITIALIZER_LIST(event_queue_(this)),
-      playback_rate_(1.0f),
+      playback_rate_(1.f),
       default_playback_rate_(1.0f),
       network_state_(kNetworkEmpty),
       ready_state_(WebMediaPlayer::kReadyStateHaveNothing),
@@ -228,6 +215,90 @@
   return result;
 }
 
+#if defined(COBALT_MEDIA_SOURCE_2016)
+
+const EventTarget::EventListenerScriptValue* HTMLMediaElement::onencrypted()
+    const {
+  return GetAttributeEventListener(base::Tokens::encrypted());
+}
+
+void HTMLMediaElement::set_onencrypted(
+    const EventListenerScriptValue& event_listener) {
+  SetAttributeEventListener(base::Tokens::encrypted(), event_listener);
+}
+
+// See https://www.w3.org/TR/encrypted-media/#dom-htmlmediaelement-setmediakeys.
+scoped_ptr<HTMLMediaElement::VoidPromiseValue> HTMLMediaElement::SetMediaKeys(
+    const scoped_refptr<eme::MediaKeys>& media_keys) {
+  scoped_ptr<VoidPromiseValue> promise = node_document()
+                                             ->html_element_context()
+                                             ->script_value_factory()
+                                             ->CreateBasicPromise<void>();
+  VoidPromiseValue::StrongReference promise_reference(*promise);
+
+  // 1. If mediaKeys and the mediaKeys attribute are the same object, return
+  //    a resolved promise.
+  if (media_keys_ == media_keys) {
+    promise_reference.value().Resolve();
+    return promise.Pass();
+  }
+
+  // 5.2. If the mediaKeys attribute is not null:
+  if (media_keys_) {
+    // 5.2.3. Stop using the CDM instance represented by the mediaKeys attribute
+    //        to decrypt media data and remove the association with the media
+    //        element.
+    //
+    // Since Starboard doesn't allow to detach SbDrmSystem from SbPlayer,
+    // re-create the entire player.
+    if (player_) {
+      ClearMediaPlayer();
+      CreateMediaPlayer();
+    }
+  }
+
+  // 5.3. If mediaKeys is not null:
+  if (media_keys) {
+    // 5.3.1. Associate the CDM instance represented by mediaKeys with
+    //        the media element for decrypting media data.
+    if (player_) {
+      player_->SetDrmSystem(media_keys->drm_system());
+    }
+  }
+
+  // 5.4. Set the mediaKeys attribute to mediaKeys.
+  media_keys_ = media_keys;
+
+  // 5.6. Resolve promise.
+  promise_reference.value().Resolve();
+
+  // 6. Return promise.
+  return promise.Pass();
+}
+
+#else  // defined(COBALT_MEDIA_SOURCE_2016)
+
+namespace {
+
+void RaiseMediaKeyException(WebMediaPlayer::MediaKeyException exception,
+                            script::ExceptionState* exception_state) {
+  DCHECK_NE(exception, WebMediaPlayer::kMediaKeyExceptionNoError);
+  switch (exception) {
+    case WebMediaPlayer::kMediaKeyExceptionInvalidPlayerState:
+      DOMException::Raise(DOMException::kInvalidStateErr, exception_state);
+      break;
+    case WebMediaPlayer::kMediaKeyExceptionKeySystemNotSupported:
+      DOMException::Raise(DOMException::kNotSupportedErr, exception_state);
+      break;
+    case WebMediaPlayer::kMediaKeyExceptionNoError:
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+}  // namespace
+
 void HTMLMediaElement::GenerateKeyRequest(
     const std::string& key_system,
     const base::optional<scoped_refptr<Uint8Array> >& init_data,
@@ -339,6 +410,8 @@
   }
 }
 
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
+
 uint16_t HTMLMediaElement::ready_state() const {
   MLOG() << ready_state_;
   return static_cast<uint16_t>(ready_state_);
@@ -420,13 +493,15 @@
 
 void HTMLMediaElement::set_playback_rate(float rate) {
   MLOG() << rate;
+
   if (playback_rate_ != rate) {
     playback_rate_ = rate;
     ScheduleOwnEvent(base::Tokens::ratechange());
   }
 
   if (player_ && PotentiallyPlaying()) {
-    player_->SetRate(rate);
+    player_->SetRate(rate *
+                     html_element_context()->video_playback_rate_multiplier());
   }
 }
 
@@ -647,15 +722,18 @@
     }
   }
 
-  player_.reset();
   player_ =
       html_element_context()->web_media_player_factory()->CreateWebMediaPlayer(
           this);
-#if !defined(COBALT_MEDIA_SOURCE_2016)
+#if defined(COBALT_MEDIA_SOURCE_2016)
+  if (media_keys_) {
+    player_->SetDrmSystem(media_keys_->drm_system());
+  }
+#else   // defined(COBALT_MEDIA_SOURCE_2016)
   if (media_source_) {
     media_source_->SetPlayer(player_.get());
   }
-#endif  // !defined(COBALT_MEDIA_SOURCE_2016)
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
   node_document()->OnDOMMutation();
   InvalidateLayoutBoxesOfNodeAndAncestors();
 }
@@ -1293,7 +1371,9 @@
       // Set rate, muted before calling play in case they were set before the
       // media engine was setup. The media engine should just stash the rate and
       // muted values since it isn't already playing.
-      player_->SetRate(playback_rate_);
+      player_->SetRate(
+          playback_rate_ *
+          html_element_context()->video_playback_rate_multiplier());
       player_->SetVolume(muted_ ? 0 : volume_);
 
       player_->Play();
@@ -1332,7 +1412,7 @@
 
 bool HTMLMediaElement::EndedPlayback() const {
   float dur = duration();
-  if (!player_ || isnan(dur)) {
+  if (!player_ || SbDoubleIsNan(dur)) {
     return false;
   }
 
@@ -1450,7 +1530,8 @@
   // When the current playback position reaches the end of the media resource
   // when the direction of playback is forwards, then the user agent must follow
   // these steps:
-  if (!isnan(dur) && (0.0f != dur) && now >= dur && playback_rate_ > 0) {
+  if (!SbDoubleIsNan(dur) && (0.0f != dur) && now >= dur &&
+      playback_rate_ > 0) {
     // If the media element has a loop attribute specified and does not have a
     // current media controller,
     if (loop()) {
@@ -1547,13 +1628,50 @@
 }
 
 #if defined(COBALT_MEDIA_SOURCE_2016)
-void HTMLMediaElement::EncryptedMediaInitData(
-    media::EmeInitDataType /*init_data_type*/,
-    const unsigned char* /*init_data*/, unsigned int /*init_data_length*/) {
-  // TODO: Implement as per EME 2017.
-  NOTIMPLEMENTED();
+
+namespace {
+
+// Initialization data types are defined in
+// https://www.w3.org/TR/eme-initdata-registry/#registry.
+std::string ToInitDataTypeString(media::EmeInitDataType init_data_type) {
+  switch (init_data_type) {
+    case media::kEmeInitDataTypeWebM:
+      return "webm";
+    case media::kEmeInitDataTypeCenc:
+      return "cenc";
+    case media::kEmeInitDataTypeKeyIds:
+      return "keyids";
+    default:
+      LOG(WARNING) << "Unknown EME initialization data type.";
+      return "";
+  }
 }
-#endif  // defined(COBALT_MEDIA_SOURCE_2016)
+
+}  // namespace
+
+// See https://www.w3.org/TR/encrypted-media/#initdata-encountered.
+void HTMLMediaElement::EncryptedMediaInitDataEncountered(
+    media::EmeInitDataType init_data_type, const unsigned char* init_data,
+    unsigned int init_data_length) {
+  // TODO: Implement "4. If the media data is CORS-same-origin and not mixed
+  //       content".
+
+  // 5. Queue a task to create an event named encrypted that does not bubble
+  //    and is not cancellable using the MediaEncryptedEvent interface [...],
+  //    and dispatch it at the media element.
+  //
+  // TODO: Implement Event.isTrusted as per
+  //       https://www.w3.org/TR/dom/#dom-event-istrusted and set it to true.
+  eme::MediaEncryptedEventInit media_encrypted_event_init;
+  media_encrypted_event_init.set_init_data_type(
+      ToInitDataTypeString(init_data_type));
+  media_encrypted_event_init.set_init_data(
+      new ArrayBuffer(NULL, init_data, init_data_length));
+  event_queue_.Enqueue(
+      new eme::MediaEncryptedEvent("encrypted", media_encrypted_event_init));
+}
+
+#else  // defined(COBALT_MEDIA_SOURCE_2016)
 
 void HTMLMediaElement::KeyAdded(const std::string& key_system,
                                 const std::string& session_id) {
@@ -1616,6 +1734,8 @@
       new Uint8Array(NULL, init_data, init_data_length, NULL)));
 }
 
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
+
 void HTMLMediaElement::ClearMediaSource() {
 #if defined(COBALT_MEDIA_SOURCE_2016)
   if (media_source_) {
diff --git a/src/cobalt/dom/html_media_element.h b/src/cobalt/dom/html_media_element.h
index 73b7a8e..154d73c 100644
--- a/src/cobalt/dom/html_media_element.h
+++ b/src/cobalt/dom/html_media_element.h
@@ -31,6 +31,7 @@
 #include "cobalt/script/exception_state.h"
 #include "googleurl/src/gurl.h"
 #if defined(COBALT_MEDIA_SOURCE_2016)
+#include "cobalt/dom/eme/media_keys.h"
 #include "cobalt/media/player/web_media_player.h"
 #else  // defined(COBALT_MEDIA_SOURCE_2016)
 #include "cobalt/dom/media_source.h"
@@ -49,12 +50,10 @@
 #else   // defined(COBALT_MEDIA_SOURCE_2016)
 typedef ::media::WebMediaPlayer WebMediaPlayer;
 typedef ::media::WebMediaPlayerClient WebMediaPlayerClient;
-#endif  // defined(WebMediaPlayerDelegate)
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
 
 // The HTMLMediaElement is the base of HTMLAudioElement and HTMLVideoElement.
 //   https://www.w3.org/TR/html5/embedded-content-0.html#media-element
-// It also implements methods defined in Encrypted Media Extensions.
-//   https://dvcs.w3.org/hg/html-media/raw-file/eme-v0.1b/encrypted-media/encrypted-media.html
 class HTMLMediaElement : public HTMLElement, private WebMediaPlayerClient {
  public:
   HTMLMediaElement(Document* document, base::Token tag_name);
@@ -83,6 +82,18 @@
   std::string CanPlayType(const std::string& mimeType);
   std::string CanPlayType(const std::string& mimeType,
                           const std::string& key_system);
+
+#if defined(COBALT_MEDIA_SOURCE_2016)
+  const EventListenerScriptValue* onencrypted() const;
+  void set_onencrypted(const EventListenerScriptValue& event_listener);
+
+  const scoped_refptr<eme::MediaKeys>& media_keys() const {
+    return media_keys_;
+  }
+  typedef script::ScriptValue<script::Promise<void> > VoidPromiseValue;
+  scoped_ptr<VoidPromiseValue> SetMediaKeys(
+      const scoped_refptr<eme::MediaKeys>& media_keys);
+#else   // defined(COBALT_MEDIA_SOURCE_2016)
   void GenerateKeyRequest(
       const std::string& key_system,
       const base::optional<scoped_refptr<Uint8Array> >& init_data,
@@ -95,6 +106,7 @@
   void CancelKeyRequest(const std::string& key_system,
                         const base::optional<std::string>& session_id,
                         script::ExceptionState* exception_state);
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
 
   // Ready state
   enum ReadyState {
@@ -232,10 +244,10 @@
   std::string SourceURL() const OVERRIDE;
   bool PreferDecodeToTexture() const OVERRIDE;
 #if defined(COBALT_MEDIA_SOURCE_2016)
-  void EncryptedMediaInitData(media::EmeInitDataType init_data_type,
-                              const unsigned char* init_data,
-                              unsigned int init_data_length) OVERRIDE;
-#endif  // defined(COBALT_MEDIA_SOURCE_2016)
+  void EncryptedMediaInitDataEncountered(
+      media::EmeInitDataType init_data_type, const unsigned char* init_data,
+      unsigned int init_data_length) OVERRIDE;
+#else   // defined(COBALT_MEDIA_SOURCE_2016)
   void KeyAdded(const std::string& key_system,
                 const std::string& session_id) OVERRIDE;
   void KeyError(const std::string& key_system, const std::string& session_id,
@@ -246,6 +258,7 @@
   void KeyNeeded(const std::string& key_system, const std::string& session_id,
                  const unsigned char* init_data,
                  unsigned int init_data_length) OVERRIDE;
+#endif  // !defined(COBALT_MEDIA_SOURCE_2016)
   void ClearMediaSource();
 #if !defined(COBALT_MEDIA_SOURCE_2016)
   void SetSourceState(MediaSourceReadyState ready_state);
@@ -312,6 +325,10 @@
   base::optional<loader::image::ReducedCacheCapacityManager::Request>
       reduced_image_cache_capacity_request_;
 
+#if defined(COBALT_MEDIA_SOURCE_2016)
+  scoped_refptr<eme::MediaKeys> media_keys_;
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
+
   DISALLOW_COPY_AND_ASSIGN(HTMLMediaElement);
 };
 
diff --git a/src/cobalt/dom/html_media_element.idl b/src/cobalt/dom/html_media_element.idl
index 425ae67..a4b7c04 100644
--- a/src/cobalt/dom/html_media_element.idl
+++ b/src/cobalt/dom/html_media_element.idl
@@ -59,12 +59,4 @@
   attribute boolean controls;
   [RaisesException] attribute double volume;
   attribute boolean muted;
-
-  // Encrypted Media Extensions methods
-  [RaisesException] void generateKeyRequest(DOMString keySystem,
-                                            Uint8Array? initData);
-  [RaisesException] void addKey(DOMString keySystem, Uint8Array key,
-                                Uint8Array? initData, DOMString? sessionId);
-  [RaisesException] void cancelKeyRequest(DOMString keySystem,
-                                          DOMString? sessionId);
 };
diff --git a/src/cobalt/dom/html_media_element_eme_01b.idl b/src/cobalt/dom/html_media_element_eme_01b.idl
new file mode 100644
index 0000000..0112a8e
--- /dev/null
+++ b/src/cobalt/dom/html_media_element_eme_01b.idl
@@ -0,0 +1,24 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// https://dvcs.w3.org/hg/html-media/raw-file/eme-v0.1b/encrypted-media/encrypted-media.html#extensions
+
+partial interface HTMLMediaElement {
+  [RaisesException] void generateKeyRequest(DOMString keySystem,
+                                            Uint8Array? initData);
+  [RaisesException] void addKey(DOMString keySystem, Uint8Array key,
+                                Uint8Array? initData, DOMString? sessionId);
+  [RaisesException] void cancelKeyRequest(DOMString keySystem,
+                                          DOMString? sessionId);
+};
diff --git a/src/cobalt/dom/media_key_message_event.idl b/src/cobalt/dom/media_key_message_event.idl
index 2b06c5f..c7738d3 100644
--- a/src/cobalt/dom/media_key_message_event.idl
+++ b/src/cobalt/dom/media_key_message_event.idl
@@ -12,20 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-/*
-enum MediaKeyMessageType {
-  "license-request",
-  "license-renewal",
-  "license-release",
-  "individualization-request"
-};
-
-[Constructor (DOMString type, optional MediaKeyMessageEventInit eventInitDict)]
-interface MediaKeyMessageEvent : Event {
-  readonly attribute MediaKeyMessageType messageType;
-  readonly attribute ArrayBuffer message;
-};
-*/
+// https://dvcs.w3.org/hg/html-media/raw-file/eme-v0.1b/encrypted-media/encrypted-media.html#dom-mediakeymessageevent
 
 interface MediaKeyMessageEvent : Event {
   readonly attribute DOMString keySystem;
diff --git a/src/cobalt/dom/media_key_needed_event.idl b/src/cobalt/dom/media_key_needed_event.idl
index c69f2c7..d9eda1e 100644
--- a/src/cobalt/dom/media_key_needed_event.idl
+++ b/src/cobalt/dom/media_key_needed_event.idl
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// https://dvcs.w3.org/hg/html-media/raw-file/eme-v0.1b/encrypted-media/encrypted-media.html#dom-mediakeyneededevent
+
 interface MediaKeyNeededEvent : Event {
   readonly attribute DOMString keySystem;
   readonly attribute DOMString sessionId;
diff --git a/src/cobalt/dom/media_key_session.idl b/src/cobalt/dom/media_key_session.idl
deleted file mode 100644
index 90b6344..0000000
--- a/src/cobalt/dom/media_key_session.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysession-interface
-
-interface MediaKeySession : EventTarget {
-  readonly attribute DOMString sessionId;
-  readonly attribute unrestricted double expiration;
-  readonly attribute Promise<void> closed;
-  readonly attribute MediaKeyStatusMap keyStatuses;
-  attribute EventHandler onkeystatuseschange;
-  attribute EventHandler onmessage;
-  Promise<void> generateRequest(DOMString initDataType, BufferSource initData);
-  Promise<boolean> load(DOMString sessionId);
-  Promise<void> update(BufferSource response);
-  Promise<void> close();
-  Promise<void> remove();
-};
diff --git a/src/cobalt/dom/media_key_status.idl b/src/cobalt/dom/media_key_status.idl
deleted file mode 100644
index 583215a..0000000
--- a/src/cobalt/dom/media_key_status.idl
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeystatusmap-interface
-
-enum MediaKeyStatus {
-    "usable",
-    "expired",
-    "released",
-    "output-restricted",
-    "output-downscaled",
-    "status-pending",
-    "internal-error"
-};
diff --git a/src/cobalt/dom/media_key_status_map.h b/src/cobalt/dom/media_key_status_map.h
deleted file mode 100644
index 414b0f6..0000000
--- a/src/cobalt/dom/media_key_status_map.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef COBALT_DOM_MEDIA_KEY_STATUS_MAP_H_
-#define COBALT_DOM_MEDIA_KEY_STATUS_MAP_H_
-
-#include "base/basictypes.h"
-#include "cobalt/dom/array_buffer.h"
-#include "cobalt/dom/array_buffer_view.h"
-#include "cobalt/script/union_type.h"
-#include "cobalt/script/value_handle.h"
-#include "cobalt/script/wrappable.h"
-
-namespace cobalt {
-namespace dom {
-
-class MediaKeyStatusMap : public script::Wrappable {
- public:
-  typedef script::UnionType2<scoped_refptr<ArrayBufferView>,
-                             scoped_refptr<ArrayBuffer> > BufferSource;
-  uint32_t size() const { return 0; }
-  bool Has(BufferSource keyId) const { return false; }
-  const script::ValueHandleHolder* Get(BufferSource keyId) const {
-    return NULL;
-  }
-
-  DEFINE_WRAPPABLE_TYPE(MediaKeyStatusMap);
-
- private:
-};
-
-}  // namespace dom
-}  // namespace cobalt
-
-#endif  // COBALT_DOM_MEDIA_KEY_STATUS_MAP_H_
diff --git a/src/cobalt/dom/media_key_status_map.idl b/src/cobalt/dom/media_key_status_map.idl
deleted file mode 100644
index a3bb962..0000000
--- a/src/cobalt/dom/media_key_status_map.idl
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeystatusmap-interface
-
-enum MediaKeyStatus {
-    "usable",
-    "expired",
-    "released",
-    "output-restricted",
-    "output-downscaled",
-    "status-pending",
-    "internal-error"
-};
-
-//callback MediaKeyStatusMapForEachCallback =
-//    void(MediaKeyStatus status, BufferSource source, MediaKeyStatusMap map);
-
-// https://www.w3.org/TR/WebIDL-1/#common-BufferSource
-typedef (ArrayBufferView or ArrayBuffer) BufferSource;
-
-interface MediaKeyStatusMap {
-  readonly attribute unsigned long size;
-  boolean has(BufferSource keyId);
-  any get(BufferSource keyId);
-
-  // iterable<BufferSource, MediaKeyStatus>;
-  //object entries();
-  //void forEach(function MediaKeyStatusMapForEachCallback);
-  //object keys();
-  //object values();
-  //Iterator @@iterator();
-};
diff --git a/src/cobalt/dom/media_key_system_configuration.idl b/src/cobalt/dom/media_key_system_configuration.idl
deleted file mode 100644
index 0ac303b..0000000
--- a/src/cobalt/dom/media_key_system_configuration.idl
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemconfiguration-dictionary
-
-dictionary MediaKeySystemConfiguration {
-  DOMString                               label = "";
-  sequence<DOMString>                     initDataTypes = [];
-  sequence<MediaKeySystemMediaCapability> audioCapabilities = [];
-  sequence<MediaKeySystemMediaCapability> videoCapabilities = [];
-  MediaKeysRequirement                    distinctiveIdentifier = "optional";
-  MediaKeysRequirement                    persistentState = "optional";
-  sequence<DOMString>                     sessionTypes;
-};
diff --git a/src/cobalt/dom/media_source.cc b/src/cobalt/dom/media_source.cc
index 20cc705..d8330cb 100644
--- a/src/cobalt/dom/media_source.cc
+++ b/src/cobalt/dom/media_source.cc
@@ -31,6 +31,7 @@
 #include "cobalt/dom/dom_settings.h"
 #include "cobalt/dom/event.h"
 #include "cobalt/media/can_play_type_handler.h"
+#include "starboard/double.h"
 
 namespace cobalt {
 namespace dom {
@@ -100,7 +101,7 @@
 
 void MediaSource::set_duration(double duration,
                                script::ExceptionState* exception_state) {
-  if (duration < 0.0 || isnan(duration)) {
+  if (duration < 0.0 || SbDoubleIsNan(duration)) {
     DOMException::Raise(DOMException::kInvalidAccessErr, exception_state);
     return;
   }
diff --git a/src/cobalt/dom/media_source/media_source.cc b/src/cobalt/dom/media_source/media_source.cc
index c87fdb5..c3fab91 100644
--- a/src/cobalt/dom/media_source/media_source.cc
+++ b/src/cobalt/dom/media_source/media_source.cc
@@ -58,6 +58,7 @@
 #include "cobalt/dom/dom_settings.h"
 #include "cobalt/dom/event.h"
 #include "cobalt/media/base/pipeline_status.h"
+#include "starboard/double.h"
 #include "starboard/media.h"
 
 namespace cobalt {
@@ -141,7 +142,7 @@
 
 void MediaSource::set_duration(double duration,
                                script::ExceptionState* exception_state) {
-  if (duration < 0.0 || isnan(duration)) {
+  if (duration < 0.0 || SbDoubleIsNan(duration)) {
     DOMException::Raise(DOMException::kIndexSizeErr, exception_state);
     return;
   }
diff --git a/src/cobalt/dom/navigator.cc b/src/cobalt/dom/navigator.cc
index 185385c..b567262 100644
--- a/src/cobalt/dom/navigator.cc
+++ b/src/cobalt/dom/navigator.cc
@@ -14,7 +14,12 @@
 
 #include "cobalt/dom/navigator.h"
 
+#include "cobalt/dom/dom_exception.h"
+#if defined(COBALT_MEDIA_SOURCE_2016)
+#include "cobalt/dom/eme/media_key_system_access.h"
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
 #include "cobalt/media_session/media_session_client.h"
+#include "cobalt/script/script_value_factory.h"
 
 using cobalt::media_session::MediaSession;
 
@@ -47,10 +52,75 @@
   return plugins_;
 }
 
-const scoped_refptr<cobalt::media_session::MediaSession>&
-Navigator::media_session() const {
+const scoped_refptr<media_session::MediaSession>& Navigator::media_session()
+    const {
   return media_session_;
 }
 
+#if defined(COBALT_MEDIA_SOURCE_2016)
+
+namespace {
+
+// TODO: Implement "3.1.1.1 Get Supported Configuration" using
+//       SbMediaCanPlayMimeAndKeySystem().
+//       https://www.w3.org/TR/encrypted-media/#get-supported-configuration
+bool MaybeGetSupportedConfiguration(
+    const std::string& /*key_system*/,
+    const eme::MediaKeySystemConfiguration& candidate_configuration,
+    eme::MediaKeySystemConfiguration* supported_configuration) {
+  *supported_configuration = candidate_configuration;
+  return true;
+}
+
+}  // namespace
+
+// See
+// https://www.w3.org/TR/encrypted-media/#dom-navigator-requestmediakeysystemaccess.
+scoped_ptr<Navigator::InterfacePromiseValue>
+Navigator::RequestMediaKeySystemAccess(
+    const std::string& key_system,
+    const script::Sequence<eme::MediaKeySystemConfiguration>&
+        supported_configurations) {
+  scoped_ptr<InterfacePromiseValue> promise =
+      script_value_factory_
+          ->CreateInterfacePromise<scoped_refptr<eme::MediaKeySystemAccess> >();
+  InterfacePromiseValue::StrongReference promise_reference(*promise);
+
+  // 1. If |keySystem| is the empty string, return a promise rejected
+  //    with a newly created TypeError.
+  // 2. If |supportedConfigurations| is empty, return a promise rejected
+  //    with a newly created TypeError.
+  if (key_system.empty() || supported_configurations.empty()) {
+    promise_reference.value().Reject(script::kTypeError);
+    return promise.Pass();
+  }
+
+  // 6.3. For each value in |supportedConfigurations|:
+  for (size_t configuration_index = 0;
+       configuration_index < supported_configurations.size();
+       ++configuration_index) {
+    // 6.3.3. If supported configuration is not NotSupported:
+    eme::MediaKeySystemConfiguration supported_configuration;
+    if (MaybeGetSupportedConfiguration(
+            key_system, supported_configurations.at(configuration_index),
+            &supported_configuration)) {
+      // 6.3.3.1. Let access be a new MediaKeySystemAccess object.
+      scoped_refptr<eme::MediaKeySystemAccess> media_key_system_access(
+          new eme::MediaKeySystemAccess(key_system, supported_configuration,
+                                        script_value_factory_));
+      // 6.3.3.2. Resolve promise.
+      promise_reference.value().Resolve(media_key_system_access);
+      return promise.Pass();
+    }
+  }
+
+  // 6.4. Reject promise with a NotSupportedError.
+  promise_reference.value().Reject(
+      new DOMException(DOMException::kNotSupportedErr));
+  return promise.Pass();
+}
+
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
+
 }  // namespace dom
 }  // namespace cobalt
diff --git a/src/cobalt/dom/navigator.h b/src/cobalt/dom/navigator.h
index a962803..740f9eb 100644
--- a/src/cobalt/dom/navigator.h
+++ b/src/cobalt/dom/navigator.h
@@ -18,9 +18,13 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
+#if defined(COBALT_MEDIA_SOURCE_2016)
+#include "cobalt/dom/eme/media_key_system_configuration.h"
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
 #include "cobalt/dom/mime_type_array.h"
 #include "cobalt/dom/plugin_array.h"
 #include "cobalt/media_session/media_session.h"
+#include "cobalt/script/promise.h"
 #include "cobalt/script/script_value_factory.h"
 #include "cobalt/script/wrappable.h"
 
@@ -54,6 +58,16 @@
   const scoped_refptr<cobalt::media_session::MediaSession>& media_session()
       const;
 
+#if defined(COBALT_MEDIA_SOURCE_2016)
+  // Web API: extension defined in Encrypted Media Extensions (16 March 2017).
+  typedef script::ScriptValue<script::Promise<
+      scoped_refptr<script::Wrappable> > > InterfacePromiseValue;
+  scoped_ptr<InterfacePromiseValue> RequestMediaKeySystemAccess(
+      const std::string& key_system,
+      const script::Sequence<eme::MediaKeySystemConfiguration>&
+          supported_configurations);
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
+
   DEFINE_WRAPPABLE_TYPE(Navigator);
 
  private:
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index a270c9d..554ce06 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -97,7 +97,8 @@
                system_window::SystemWindow* system_window,
                const scoped_refptr<input::Camera3D>& camera_3d,
                const scoped_refptr<MediaSession>& media_session,
-               int csp_insecure_allowed_token, int dom_max_element_depth)
+               int csp_insecure_allowed_token, int dom_max_element_depth,
+               float video_playback_rate_multiplier)
     : width_(width),
       height_(height),
       html_element_context_(new HTMLElementContext(
@@ -105,7 +106,8 @@
           web_media_player_factory, script_runner, script_value_factory,
           media_source_registry, resource_provider, animated_image_tracker,
           image_cache, reduced_image_cache_capacity_manager,
-          remote_typeface_cache, mesh_cache, dom_stat_tracker, language)),
+          remote_typeface_cache, mesh_cache, dom_stat_tracker, language,
+          video_playback_rate_multiplier)),
       performance_(new Performance(new base::SystemMonotonicClock())),
       ALLOW_THIS_IN_INITIALIZER_LIST(document_(new Document(
           html_element_context_.get(),
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h
index 7a90c00..0fc144b 100644
--- a/src/cobalt/dom/window.h
+++ b/src/cobalt/dom/window.h
@@ -133,7 +133,8 @@
       system_window::SystemWindow* system_window,
       const scoped_refptr<input::Camera3D>& camera_3d,
       const scoped_refptr<cobalt::media_session::MediaSession>& media_session,
-      int csp_insecure_allowed_token = 0, int dom_max_element_depth = 0);
+      int csp_insecure_allowed_token = 0, int dom_max_element_depth = 0,
+      float video_playback_rate_multiplier = 1.f);
 
   // Web API: Window
   //
diff --git a/src/cobalt/h5vcc/h5vcc.gyp b/src/cobalt/h5vcc/h5vcc.gyp
index 6c5c7b6..1e71529 100644
--- a/src/cobalt/h5vcc/h5vcc.gyp
+++ b/src/cobalt/h5vcc/h5vcc.gyp
@@ -90,6 +90,9 @@
           },
         }],
       ],
+      'defines': [
+        'COBALT_USER_ON_EXIT_STRATEGY="<(cobalt_user_on_exit_strategy)"',
+      ],
     },
 
     {
diff --git a/src/cobalt/h5vcc/h5vcc_system.cc b/src/cobalt/h5vcc/h5vcc_system.cc
index 60e396d..2b96110 100644
--- a/src/cobalt/h5vcc/h5vcc_system.cc
+++ b/src/cobalt/h5vcc/h5vcc_system.cc
@@ -64,5 +64,21 @@
 // return false to indicate the client should launch their own dialog.
 bool H5vccSystem::TriggerHelp() const { return false; }
 
+uint32 H5vccSystem::user_on_exit_strategy() const {
+  // Convert from the Cobalt gyp setting variable's enum options to the H5VCC
+  // interface enum options.
+  std::string exit_strategy_str(COBALT_USER_ON_EXIT_STRATEGY);
+  if (exit_strategy_str == "stop") {
+    return static_cast<UserOnExitStrategy>(kUserOnExitStrategyClose);
+  } else if (exit_strategy_str == "suspend") {
+    return static_cast<UserOnExitStrategy>(kUserOnExitStrategyMinimize);
+  } else if (exit_strategy_str == "noexit") {
+    return static_cast<UserOnExitStrategy>(kUserOnExitStrategyNoExit);
+  } else {
+    NOTREACHED() << "Unknown gyp-defined exit strategy.";
+    return static_cast<UserOnExitStrategy>(kUserOnExitStrategyClose);
+  }
+}
+
 }  // namespace h5vcc
 }  // namespace cobalt
diff --git a/src/cobalt/h5vcc/h5vcc_system.h b/src/cobalt/h5vcc/h5vcc_system.h
index e192581..5928ed8 100644
--- a/src/cobalt/h5vcc/h5vcc_system.h
+++ b/src/cobalt/h5vcc/h5vcc_system.h
@@ -35,6 +35,14 @@
 
   bool TriggerHelp() const;
 
+  enum UserOnExitStrategy {
+    kUserOnExitStrategyClose,
+    kUserOnExitStrategyMinimize,
+    kUserOnExitStrategyNoExit,
+  };
+
+  uint32 user_on_exit_strategy() const;
+
   DEFINE_WRAPPABLE_TYPE(H5vccSystem);
 
  private:
diff --git a/src/cobalt/h5vcc/h5vcc_system.idl b/src/cobalt/h5vcc/h5vcc_system.idl
index a1612e4..787116d 100644
--- a/src/cobalt/h5vcc/h5vcc_system.idl
+++ b/src/cobalt/h5vcc/h5vcc_system.idl
@@ -19,4 +19,21 @@
   readonly attribute DOMString region;
   readonly attribute DOMString version;
   boolean triggerHelp();
+
+  // enum UserOnExitStrategy
+  //
+  // When a user requests to leave the application, window.close() should be
+  // called.
+  const unsigned long USER_ON_EXIT_STRATEGY_CLOSE = 0;
+  // When a user requests to leave the application, window.minimize() should be
+  // called.
+  const unsigned long USER_ON_EXIT_STRATEGY_MINIMIZE = 1;
+  // The user should not be allowed to initiate an application exit request.
+  const unsigned long USER_ON_EXIT_STRATEGY_NO_EXIT = 2;
+
+  // This variable defines what Cobalt's preferred strategy should be for
+  // handling internally triggered application exit requests (e.g. the user
+  // chooses to back out of the application).  See the comments in the
+  // enum above for more information about possible values.
+  readonly attribute unsigned long userOnExitStrategy;
 };
diff --git a/src/cobalt/layout/box.h b/src/cobalt/layout/box.h
index 42cfc71..3484227 100644
--- a/src/cobalt/layout/box.h
+++ b/src/cobalt/layout/box.h
@@ -21,7 +21,6 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
-#include "cobalt/base/math.h"
 #include "cobalt/cssom/css_computed_style_declaration.h"
 #include "cobalt/cssom/css_style_declaration.h"
 #include "cobalt/dom/node.h"
diff --git a/src/cobalt/layout/layout_unit.h b/src/cobalt/layout/layout_unit.h
index d65f08d..c3b3520 100644
--- a/src/cobalt/layout/layout_unit.h
+++ b/src/cobalt/layout/layout_unit.h
@@ -23,7 +23,6 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "cobalt/base/math.h"
 
 namespace cobalt {
 namespace layout {
diff --git a/src/cobalt/layout/line_box.cc b/src/cobalt/layout/line_box.cc
index e4f3eea..452f2b0 100644
--- a/src/cobalt/layout/line_box.cc
+++ b/src/cobalt/layout/line_box.cc
@@ -17,7 +17,6 @@
 #include <algorithm>
 #include <limits>
 
-#include "cobalt/base/math.h"
 #include "cobalt/cssom/keyword_value.h"
 #include "cobalt/layout/box.h"
 #include "cobalt/layout/used_style.h"
diff --git a/src/cobalt/layout/text_box.cc b/src/cobalt/layout/text_box.cc
index a13b1c0..0dd7e44 100644
--- a/src/cobalt/layout/text_box.cc
+++ b/src/cobalt/layout/text_box.cc
@@ -17,7 +17,6 @@
 #include <algorithm>
 #include <limits>
 
-#include "cobalt/base/math.h"
 #include "cobalt/cssom/keyword_value.h"
 #include "cobalt/cssom/shadow_value.h"
 #include "cobalt/layout/render_tree_animations.h"
diff --git a/src/cobalt/loader/image/animated_webp_image.cc b/src/cobalt/loader/image/animated_webp_image.cc
index a6a9373..d43449f 100644
--- a/src/cobalt/loader/image/animated_webp_image.cc
+++ b/src/cobalt/loader/image/animated_webp_image.cc
@@ -16,7 +16,8 @@
 
 #include "cobalt/loader/image/animated_webp_image.h"
 
-#include "cobalt/loader/image/webp_image_decoder.h"
+#include "cobalt/base/polymorphic_downcast.h"
+#include "cobalt/loader/image/image_decoder.h"
 #include "cobalt/render_tree/brush.h"
 #include "cobalt/render_tree/composition_node.h"
 #include "cobalt/render_tree/image_node.h"
@@ -170,11 +171,22 @@
   }
 }
 
+namespace {
+
+void RecordImage(scoped_refptr<render_tree::Image>* image_pointer,
+                 const scoped_refptr<loader::image::Image>& image) {
+  image::StaticImage* static_image =
+      base::polymorphic_downcast<loader::image::StaticImage*>(image.get());
+  DCHECK(static_image);
+  *image_pointer = static_image->image();
+}
+
+}  // namespace
+
 bool AnimatedWebPImage::DecodeOneFrame(int frame_index) {
   TRACK_MEMORY_SCOPE("Rendering");
   base::AutoLock lock(lock_);
   WebPIterator webp_iterator;
-  WEBPImageDecoder webp_image_decoder(resource_provider_);
   scoped_refptr<render_tree::Image> next_frame_image;
 
   // Decode the current frame.
@@ -185,24 +197,18 @@
     if (!webp_iterator.complete) {
       return false;
     }
-    webp_image_decoder.DecodeChunk(webp_iterator.fragment.bytes,
-                                   webp_iterator.fragment.size);
-    if (!webp_image_decoder.FinishWithSuccess()) {
+
+    ImageDecoder image_decoder(
+        resource_provider_, base::Bind(&RecordImage, &next_frame_image),
+        ImageDecoder::ErrorCallback(), ImageDecoder::kImageTypeWebP);
+    image_decoder.DecodeChunk(
+        reinterpret_cast<const char*>(webp_iterator.fragment.bytes),
+        webp_iterator.fragment.size);
+    image_decoder.Finish();
+    if (!next_frame_image) {
       LOG(ERROR) << "Failed to decode WebP image frame.";
       return false;
     }
-
-    scoped_ptr<render_tree::ImageData> next_frame_data = AllocateImageData(
-        math::Size(webp_iterator.width, webp_iterator.height));
-    DCHECK(next_frame_data);
-    {
-      TRACE_EVENT0("cobalt::loader::image", "SbMemoryCopy");
-      SbMemoryCopy(next_frame_data->GetMemory(),
-                   webp_image_decoder.GetOriginalMemory(),
-                   webp_iterator.width * webp_iterator.height *
-                       render_tree::BytesPerPixel(pixel_format_));
-    }
-    next_frame_image = resource_provider_->CreateImage(next_frame_data.Pass());
   }
 
   // Alpha blend the current frame on top of the buffer.
diff --git a/src/cobalt/loader/image/image_decoder.cc b/src/cobalt/loader/image/image_decoder.cc
index 831a574..a44f373 100644
--- a/src/cobalt/loader/image/image_decoder.cc
+++ b/src/cobalt/loader/image/image_decoder.cc
@@ -51,27 +51,18 @@
   result->append(message);
 }
 
-// The various types of images we support decoding.
-enum ImageType {
-  kImageTypeInvalid,
-  kImageTypeGIF,
-  kImageTypeJPEG,
-  kImageTypePNG,
-  kImageTypeWebP,
-};
-
 // Determine the ImageType of an image from its signature.
-ImageType DetermineImageType(const uint8* header) {
+ImageDecoder::ImageType DetermineImageType(const uint8* header) {
   if (!memcmp(header, "\xFF\xD8\xFF", 3)) {
-    return kImageTypeJPEG;
+    return ImageDecoder::kImageTypeJPEG;
   } else if (!memcmp(header, "GIF87a", 6) || !memcmp(header, "GIF89a", 6)) {
-    return kImageTypeGIF;
+    return ImageDecoder::kImageTypeGIF;
   } else if (!memcmp(header, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8)) {
-    return kImageTypePNG;
+    return ImageDecoder::kImageTypePNG;
   } else if (!memcmp(header, "RIFF", 4) && !memcmp(header + 8, "WEBPVP", 6)) {
-    return kImageTypeWebP;
+    return ImageDecoder::kImageTypeWebP;
   } else {
-    return kImageTypeInvalid;
+    return ImageDecoder::kImageTypeInvalid;
   }
 }
 
@@ -83,9 +74,22 @@
     : resource_provider_(resource_provider),
       success_callback_(success_callback),
       error_callback_(error_callback),
+      image_type_(kImageTypeInvalid),
       state_(resource_provider_ ? kWaitingForHeader : kSuspended),
       is_deletion_pending_(false) {
-  TRACE_EVENT0("cobalt::loader::image", "ImageDecoder::ImageDecoder()");
+  signature_cache_.position = 0;
+}
+
+ImageDecoder::ImageDecoder(render_tree::ResourceProvider* resource_provider,
+                           const SuccessCallback& success_callback,
+                           const ErrorCallback& error_callback,
+                           ImageType image_type)
+    : resource_provider_(resource_provider),
+      success_callback_(success_callback),
+      error_callback_(error_callback),
+      image_type_(image_type),
+      state_(resource_provider_ ? kWaitingForHeader : kSuspended),
+      is_deletion_pending_(false) {
   signature_cache_.position = 0;
 }
 
@@ -269,17 +273,17 @@
 namespace {
 #if defined(STARBOARD)
 #if SB_VERSION(3) && SB_HAS(GRAPHICS)
-const char* GetMimeTypeFromImageType(ImageType image_type) {
+const char* GetMimeTypeFromImageType(ImageDecoder::ImageType image_type) {
   switch (image_type) {
-    case kImageTypeJPEG:
+    case ImageDecoder::kImageTypeJPEG:
       return "image/jpeg";
-    case kImageTypePNG:
+    case ImageDecoder::kImageTypePNG:
       return "image/png";
-    case kImageTypeGIF:
+    case ImageDecoder::kImageTypeGIF:
       return "image/gif";
-    case kImageTypeWebP:
+    case ImageDecoder::kImageTypeWebP:
       return "image/webp";
-    case kImageTypeInvalid:
+    case ImageDecoder::kImageTypeInvalid:
       return NULL;
     default: { NOTREACHED(); }
   }
@@ -288,7 +292,7 @@
 
 // If |mime_type| is empty, |image_type| will be used to deduce the mime type.
 scoped_ptr<ImageDataDecoder> MaybeCreateStarboardDecoder(
-    const std::string& mime_type, ImageType image_type,
+    const std::string& mime_type, ImageDecoder::ImageType image_type,
     render_tree::ResourceProvider* resource_provider) {
   // clang-format off
   const SbDecodeTargetFormat kPreferredFormats[] = {
@@ -331,12 +335,13 @@
 #endif  // defined(STARBOARD)
 
 scoped_ptr<ImageDataDecoder> CreateImageDecoderFromImageType(
-    ImageType image_type, render_tree::ResourceProvider* resource_provider) {
+    ImageDecoder::ImageType image_type,
+    render_tree::ResourceProvider* resource_provider) {
   // Call different types of decoders by matching the image signature.
   if (s_use_stub_image_decoder) {
     return make_scoped_ptr<ImageDataDecoder>(
         new StubImageDecoder(resource_provider));
-  } else if (image_type == kImageTypeJPEG) {
+  } else if (image_type == ImageDecoder::kImageTypeJPEG) {
 #if defined(USE_PS3_JPEG_IMAGE_DECODER)
     return make_scoped_ptr<ImageDataDecoder>(
         new JPEGImageDecoderPS3(resource_provider));
@@ -344,13 +349,13 @@
     return make_scoped_ptr<ImageDataDecoder>(
         new JPEGImageDecoder(resource_provider));
 #endif  // defined(USE_PS3_JPEG_IMAGE_DECODER)
-  } else if (image_type == kImageTypePNG) {
+  } else if (image_type == ImageDecoder::kImageTypePNG) {
     return make_scoped_ptr<ImageDataDecoder>(
         new PNGImageDecoder(resource_provider));
-  } else if (image_type == kImageTypeWebP) {
+  } else if (image_type == ImageDecoder::kImageTypeWebP) {
     return make_scoped_ptr<ImageDataDecoder>(
         new WEBPImageDecoder(resource_provider));
-  } else if (image_type == kImageTypeGIF) {
+  } else if (image_type == ImageDecoder::kImageTypeGIF) {
     return make_scoped_ptr<ImageDataDecoder>(
         new DummyGIFImageDecoder(resource_provider));
   } else {
@@ -374,17 +379,19 @@
     return false;
   }
 
-  const ImageType image_type = DetermineImageType(signature_cache_.data);
+  if (image_type_ == kImageTypeInvalid) {
+    image_type_ = DetermineImageType(signature_cache_.data);
+  }
 
 #if defined(STARBOARD)
 #if SB_VERSION(3) && SB_HAS(GRAPHICS)
   decoder_ =
-      MaybeCreateStarboardDecoder(mime_type_, image_type, resource_provider_);
+      MaybeCreateStarboardDecoder(mime_type_, image_type_, resource_provider_);
 #endif  // SB_VERSION(3) && SB_HAS(GRAPHICS)
 #endif  // defined(STARBOARD)
 
   if (!decoder_) {
-    decoder_ = CreateImageDecoderFromImageType(image_type, resource_provider_);
+    decoder_ = CreateImageDecoderFromImageType(image_type_, resource_provider_);
   }
 
   if (!decoder_) {
diff --git a/src/cobalt/loader/image/image_decoder.h b/src/cobalt/loader/image/image_decoder.h
index 2127a07..8004dc9 100644
--- a/src/cobalt/loader/image/image_decoder.h
+++ b/src/cobalt/loader/image/image_decoder.h
@@ -28,19 +28,31 @@
 namespace loader {
 namespace image {
 
-// This class handles decoding any image type. When the image type is determined
-// by the signature in the data being received, an image data decoder specific
+// This class handles decoding any image. If image type is not given, it is
+// determined by the signature in the data. Then an image data decoder specific
 // to that image type is created to parse the data. When the decoding is
 // complete, the image decoder retrieves the data and uses it to create the
 // image.
 class ImageDecoder : public Decoder {
  public:
+  // The various types of images we support decoding.
+  enum ImageType {
+    kImageTypeInvalid,
+    kImageTypeGIF,
+    kImageTypeJPEG,
+    kImageTypePNG,
+    kImageTypeWebP,
+  };
+
   typedef base::Callback<void(const scoped_refptr<Image>&)> SuccessCallback;
   typedef base::Callback<void(const std::string&)> ErrorCallback;
 
   ImageDecoder(render_tree::ResourceProvider* resource_provider,
                const SuccessCallback& success_callback,
                const ErrorCallback& error_callback);
+  ImageDecoder(render_tree::ResourceProvider* resource_provider,
+               const SuccessCallback& success_callback,
+               const ErrorCallback& error_callback, ImageType image_type);
 
   // From Decoder.
   LoadResponseType OnResponseStarted(
@@ -84,6 +96,7 @@
   render_tree::ResourceProvider* resource_provider_;
   const SuccessCallback success_callback_;
   const ErrorCallback error_callback_;
+  ImageType image_type_;
   scoped_ptr<ImageDataDecoder> decoder_;
   SignatureCache signature_cache_;
   State state_;
diff --git a/src/cobalt/math/linear_interpolator.h b/src/cobalt/math/linear_interpolator.h
new file mode 100644
index 0000000..728f70f
--- /dev/null
+++ b/src/cobalt/math/linear_interpolator.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COBALT_MATH_LINEAR_INTERPOLATOR_H_
+#define COBALT_MATH_LINEAR_INTERPOLATOR_H_
+
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace math {
+
+// LinearInterpolator effectively generates outputs based on a table. This can
+// be used for function approximation (ie. sine) or arbitrary functions that
+// need specific values at specific inputs, and interpolated values otherwise.
+// KeyT and ValueT can be any builtin integer and float point type.
+// It's recommended that double types are used unless speed is required, then
+// use other types.
+//
+// Performance:
+//  This table increases the computation on the order of O(n) of the number
+//  of interpolation points. However in practice the number of interpolation
+//  points is small enough (<20) where this linear search is faster than binary
+//  lookup.
+//
+// Discontinuous values:
+//  This table supports discontinuous values. To enable this feature, insert a
+//  pair of duplicate keys, each with a different value. See example below. 
+//
+// Example (continuous):
+//  LinearInterpolator<float, float> interp;
+//  interp.Add(0, 0);
+//  interp.Add(1, 2);
+//  EXPECT_FLOAT_EQ(0.f, interp.Map(0.0f));
+//  EXPECT_FLOAT_EQ(1.f, interp.Map(0.5f));
+//  EXPECT_FLOAT_EQ(2.f, interp.Map(1.0f));
+//
+// Example (discontinuous):
+//  LinearInterpolator<double, float> interp;
+//  interp.Add(0, 0);
+//  interp.Add(1, 1);  // Discontinuity at input = 1.
+//  interp.Add(1, 3);
+//  interp.Add(2, 4);
+//  static const double kErrorThreshold = .1f;
+//  static const double kEpsilon = std::numeric_limits<double>::epsilon()*4.0;
+//  EXPECT_NEAR(1.0, interp.Map(1.f - kEpsilon), kErrorThreshold);
+//  EXPECT_FLOAT_EQ(3, interp.Map(1.f));
+//  EXPECT_NEAR(3.0, interp.Map(1.f + kEpsilon), kErrorThreshold);
+template <typename KeyT, typename ValueT>
+class LinearInterpolator {
+ public:
+  ValueT Map(const KeyT& key) const {
+    return Interp(key);
+  }
+
+  // Adds a key to the table. For a continuous piecewise line-curve each key
+  // added must be greater in value than the last key added.
+  // If duplicate keys are entered sequentially then this will introduce
+  // a discontinuity - a big jump in the returned value from Map() when the
+  // input crosses the discontinuity point.
+  void Add(const KeyT& key, const ValueT& val) {
+    if (!table_.empty()) {
+      DCHECK_LE(table_.back().first, key) << "Keys are not in order.";
+    }
+    table_.push_back(std::pair<KeyT, ValueT>(key, val));
+  }
+  void Clear() {
+    table_.clear();
+  }
+
+ private:
+  ValueT Interp(const KeyT& k) const {
+    if (table_.empty()) {
+      return ValueT(0);
+    }
+
+    // Contains the indices which reference keys before and after the key.
+    std::pair<size_t, size_t> indices = SelectInterpPoints(k);
+
+    // Singular value, no interpolation needed.
+    if (indices.first == indices.second) {
+      return table_[indices.first].second;
+    }
+
+    // Perform the interpolation with the given key & value lines.
+    const std::pair<KeyT, ValueT>& curr = table_[indices.first];
+    const std::pair<KeyT, ValueT>& next = table_[indices.second];
+
+    // Duplicate keys, select the second value. This prevents
+    // LinearInterpolation() from dividing by 0 for duplicate keys.
+    if (curr.first == next.first) {
+      return next.second;
+    }
+
+    return LinearInterpolation(k, curr.first, next.first,
+                               curr.second, next.second);
+  }
+
+  // Linearly walk through the table looking for a pair of interpolation
+  // points. Linear walking must be used because this table uses duplicate
+  // keys generate discontinuous outputs.
+  std::pair<size_t, size_t> SelectInterpPoints(const KeyT& k) const {
+    DCHECK(!table_.empty());
+    if (k < table_[0].first) {
+      return std::pair<size_t, size_t>(0, 0);
+    }
+
+    for (size_t i = 0; i < table_.size() - 1; ++i) {
+      const std::pair<KeyT, ValueT>& curr = table_[i];
+      const std::pair<KeyT, ValueT>& next = table_[i+1];
+
+      if (curr.first <= k && k < next.first) {
+        return std::pair<size_t, size_t>(i, i+1);
+      }
+    }
+
+    return std::pair<size_t, size_t>(table_.size() - 1, table_.size() - 1);
+  }
+
+  // Maps a value in the range [x1, x2] to the range [y1, y2].
+  static const ValueT LinearInterpolation(const KeyT& t,
+                                          const KeyT& x1, const KeyT& x2,
+                                          const ValueT& y1, const ValueT& y2) {
+    ValueT return_val =
+        static_cast<ValueT>((t - x1) * (y2 - y1) / (x2 - x1) + y1);
+    return return_val;
+  }
+
+  typedef std::vector<std::pair<KeyT, ValueT> > VectorType;
+  VectorType table_;
+};
+
+}  // namespace math
+}  // namespace cobalt
+
+#endif  // COBALT_MATH_LINEAR_INTERPOLATOR_H_
diff --git a/src/cobalt/math/linear_interpolator_unittest.cc b/src/cobalt/math/linear_interpolator_unittest.cc
new file mode 100644
index 0000000..399baf4
--- /dev/null
+++ b/src/cobalt/math/linear_interpolator_unittest.cc
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "cobalt/math/linear_interpolator.h"
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cobalt {
+namespace math {
+
+TEST(LinearInterpolator, SimpleInterpolation) {
+  LinearInterpolator<float, float> interp;
+  interp.Add(0, 0);
+  interp.Add(1, 2);
+
+  // Expect that value of 0.0f maps to 0.0f
+  EXPECT_FLOAT_EQ(0.f, interp.Map(0.0f));
+  // Expect that value of 0.5f maps to 1.0f
+  EXPECT_FLOAT_EQ(1.f, interp.Map(0.5f));
+  // Expect that value of 1.5f maps to 2.0f
+  EXPECT_FLOAT_EQ(2.f, interp.Map(1.0f));
+}
+
+// Tests the expectation that clearing the interpolator works.
+TEST(LinearInterpolator, Clear) {
+  LinearInterpolator<int, int> interp;
+  interp.Add(-1, 0);
+  interp.Add(1, 2);
+
+  interp.Clear();
+
+  EXPECT_FLOAT_EQ(0, interp.Map(-1));
+  EXPECT_FLOAT_EQ(0, interp.Map(1));
+}
+
+// Tests the expectation that interpolating on one value in the table works
+// as expected: to always return that value.
+TEST(LinearInterpolator, InterpolateSingularValue) {
+  LinearInterpolator<size_t, size_t> interp;
+  interp.Add(2, 10);
+
+  EXPECT_EQ(10, interp.Map(2));
+  EXPECT_EQ(10, interp.Map(1));
+  EXPECT_EQ(10, interp.Map(3));
+}
+
+// Tests the expectation that we can introduce an discontinuity by passing
+// in duplicate keys.
+TEST(LinearInterpolator, Discontinuity) {
+  LinearInterpolator<double, float> interp;
+  interp.Add(0, 0);
+  interp.Add(1, 1);  // Discontinuity at input = 1.
+  interp.Add(1, 3);
+  interp.Add(2, 4);
+
+  static const double kErrorThreshold = .1f;
+  static const double kEpsilon = std::numeric_limits<double>::epsilon()*4.0;
+
+  EXPECT_NEAR(1.0, interp.Map(1.f - kEpsilon), kErrorThreshold);
+  // Expect that at the discontinuity point value of 1, that the value that
+  // the interpolator produces is 3.
+  EXPECT_FLOAT_EQ(3, interp.Map(1.f));
+  EXPECT_NEAR(3.0, interp.Map(1.f + kEpsilon), kErrorThreshold);
+}
+
+// Tests that extrapolation is forbidden with this interpolator.
+TEST(LinearInterpolator, ExtrapolationForbidden) {
+  LinearInterpolator<float, float> interp;
+  interp.Add(0, 0);
+  interp.Add(1, 2);
+
+  // Expect that values less than the minimal key value is clamped.
+  EXPECT_FLOAT_EQ(0.0f, interp.Map(-1.0f));
+  // Expect that values greater than the maximum key value is clamped.
+  EXPECT_FLOAT_EQ(2.0f, interp.Map(2.0f));
+}
+
+// Some more real world values.
+TEST(LinearInterpolator, UseComplexFloat) {
+  LinearInterpolator<float, float> interp;
+  interp.Add(0, 0);
+  interp.Add(41, 1);
+  interp.Add(1023, 15);
+
+  EXPECT_FLOAT_EQ(0.0f, interp.Map(0.f));
+  EXPECT_FLOAT_EQ(0.5f, interp.Map(41.f/2.f));
+  EXPECT_FLOAT_EQ(1.0f, interp.Map(41.f));
+  EXPECT_FLOAT_EQ(15.f, interp.Map(1023.f));
+}
+
+// Tests that this interpolator works with integer keys and float values.
+TEST(LinearInterpolator, UseIntegerKeyWithFloatValue) {
+  LinearInterpolator<int, float> interp;
+  interp.Add(0, 0.f);
+  interp.Add(10, 1.f);
+  interp.Add(100, 2.f);
+
+  EXPECT_FLOAT_EQ(0.0f, interp.Map(0));
+  EXPECT_FLOAT_EQ(0.5f, interp.Map(5));
+  EXPECT_FLOAT_EQ(1.0f, interp.Map(10));
+  EXPECT_FLOAT_EQ(2.0f, interp.Map(100));
+}
+
+// Tests that this interpolator works with integer keys and int values.
+TEST(LinearInterpolator, UseIntegerKeyWithIntegerValue) {
+  LinearInterpolator<int, int> interp;
+  interp.Add(0, 0);
+  interp.Add(10, 100);
+  interp.Add(100, 1000);
+
+  EXPECT_EQ(0, interp.Map(0));
+  EXPECT_EQ(50, interp.Map(5));
+  EXPECT_EQ(100, interp.Map(10));
+  EXPECT_EQ(550, interp.Map(55));
+  EXPECT_EQ(1000, interp.Map(100));
+}
+
+}  // namespace math
+}  // namespace cobalt
diff --git a/src/cobalt/math/math.gyp b/src/cobalt/math/math.gyp
index 692d7ec..f457fdd 100644
--- a/src/cobalt/math/math.gyp
+++ b/src/cobalt/math/math.gyp
@@ -18,6 +18,7 @@
         'insets_base.h',
         'insets_f.cc',
         'insets_f.h',
+        'linear_interpolator.h',
         'matrix3_f.cc',
         'matrix3_f.h',
         'matrix_interpolation.cc',
@@ -75,6 +76,7 @@
         'box_unittest.cc',
         'cubic_bezier_unittest.cc',
         'insets_unittest.cc',
+        'linear_interpolator_unittest.cc',
         'matrix3_unittest.cc',
         'matrix_interpolation_unittest.cc',
         'point3_unittest.cc',
diff --git a/src/cobalt/media/base/drm_system.cc b/src/cobalt/media/base/drm_system.cc
index 38a0be8..639051f 100644
--- a/src/cobalt/media/base/drm_system.cc
+++ b/src/cobalt/media/base/drm_system.cc
@@ -20,72 +20,179 @@
 namespace cobalt {
 namespace media {
 
-DrmSystem::DrmSystem(const char* key_system, DrmSystemClient* client)
-    : client_(client),
-      wrapped_drm_system_(SbDrmCreateSystem(key_system, this,
+DrmSystem::Session::Session(DrmSystem* drm_system)
+    : drm_system_(drm_system), closed_(false) {}
+
+DrmSystem::Session::~Session() {
+  if (id_ && !closed_) {
+    // Auto-closing semantics is derived from EME spec.
+    //
+    // If a MediaKeySession object is not closed when it becomes inaccessible
+    // to the page, the CDM shall close the key session associated with
+    // the object.
+    //   https://www.w3.org/TR/encrypted-media/#mediakeysession-interface
+    Close();
+  }
+}
+
+void DrmSystem::Session::GenerateUpdateRequest(
+    const std::string& type, const uint8* init_data, int init_data_length,
+    const SessionUpdateRequestGeneratedCallback&
+        session_update_request_generated_callback,
+    const SessionUpdateRequestDidNotGenerateCallback&
+        session_update_request_did_not_generate_callback) {
+  update_request_generated_callback_ =
+      session_update_request_generated_callback;
+  drm_system_->GenerateSessionUpdateRequest(
+      this, type, init_data, init_data_length,
+      session_update_request_generated_callback,
+      session_update_request_did_not_generate_callback);
+}
+
+void DrmSystem::Session::Update(
+    const uint8* key, int key_length,
+    const SessionUpdatedCallback& session_updated_callback,
+    const SessionDidNotUpdateCallback& session_did_not_update_callback) {
+  drm_system_->UpdateSession(*id_, key, key_length, session_updated_callback,
+                             session_did_not_update_callback);
+}
+
+void DrmSystem::Session::Close() {
+  drm_system_->CloseSession(*id_);
+  closed_ = true;
+}
+
+DrmSystem::DrmSystem(const char* key_system)
+    : wrapped_drm_system_(SbDrmCreateSystem(key_system, this,
                                             OnSessionUpdateRequestGeneratedFunc,
                                             OnSessionUpdatedFunc)),
-      message_loop_(MessageLoop::current()) {
+      message_loop_(MessageLoop::current()),
+      ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
+      weak_this_(weak_ptr_factory_.GetWeakPtr()),
+      next_session_update_request_ticket_(0),
+      next_session_update_ticket_(0) {
   DCHECK_NE(kSbDrmSystemInvalid, wrapped_drm_system_);
 }
 
 DrmSystem::~DrmSystem() { SbDrmDestroySystem(wrapped_drm_system_); }
 
-void DrmSystem::GenerateSessionUpdateRequest(int ticket,
-                                             const std::string& type,
-                                             const uint8_t* init_data,
-                                             int init_data_length) {
+scoped_ptr<DrmSystem::Session> DrmSystem::CreateSession() {
+  return make_scoped_ptr(new Session(this));
+}
+
+void DrmSystem::GenerateSessionUpdateRequest(
+    Session* session, const std::string& type, const uint8_t* init_data,
+    int init_data_length, const SessionUpdateRequestGeneratedCallback&
+                              session_update_request_generated_callback,
+    const SessionUpdateRequestDidNotGenerateCallback&
+        session_update_request_did_not_generate_callback) {
+  // Store the context of the call.
+  SessionUpdateRequest session_update_request;
+  session_update_request.session = session;
+  session_update_request.generated_callback =
+      session_update_request_generated_callback;
+  session_update_request.did_not_generate_callback =
+      session_update_request_did_not_generate_callback;
+  int ticket = next_session_update_request_ticket_++;
+  ticket_to_session_update_request_map_.insert(
+      std::make_pair(ticket, session_update_request));
+
   SbDrmGenerateSessionUpdateRequest(wrapped_drm_system_, ticket, type.c_str(),
                                     init_data, init_data_length);
 }
 
-void DrmSystem::UpdateSession(int ticket, const std::string& session_id,
-                              const uint8_t* key, int key_length) {
+void DrmSystem::UpdateSession(
+    const std::string& session_id, const uint8_t* key, int key_length,
+    const SessionUpdatedCallback& session_updated_callback,
+    const SessionDidNotUpdateCallback& session_did_not_update_callback) {
+  // Store the context of the call.
+  SessionUpdate session_update;
+  session_update.updated_callback = session_updated_callback;
+  session_update.did_not_update_callback = session_did_not_update_callback;
+  int ticket = next_session_update_ticket_++;
+  ticket_to_session_update_map_.insert(std::make_pair(ticket, session_update));
+
   SbDrmUpdateSession(wrapped_drm_system_, ticket, key, key_length,
                      session_id.c_str(), session_id.size());
 }
 
 void DrmSystem::CloseSession(const std::string& session_id) {
+  id_to_session_map_.erase(session_id);
   SbDrmCloseSession(wrapped_drm_system_, session_id.c_str(), session_id.size());
 }
 
-void DrmSystem::OnSessionUpdateRequestGenerated(int ticket,
-                                                const void* session_id,
-                                                int session_id_size,
-                                                const void* content,
-                                                int content_size) {
-  if (session_id) {
-    std::string session_id_copy(
-        static_cast<const char*>(session_id),
-        static_cast<const char*>(session_id) + session_id_size);
+void DrmSystem::OnSessionUpdateRequestGenerated(
+    int ticket, const base::optional<std::string>& session_id,
+    scoped_array<uint8> message, int message_size) {
+  if (SbDrmTicketIsValid(ticket)) {
+    // Called back as a result of |SbDrmGenerateSessionUpdateRequest|.
 
-    scoped_array<uint8> content_copy(new uint8[content_size]);
-    SbMemoryCopy(content_copy.get(), content, content_size);
+    // Restore the context of |GenerateSessionUpdateRequest|.
+    TicketToSessionUpdateRequestMap::iterator session_update_request_iterator =
+        ticket_to_session_update_request_map_.find(ticket);
+    if (session_update_request_iterator ==
+        ticket_to_session_update_request_map_.end()) {
+      LOG(ERROR) << "Unknown session update request ticket: " << ticket << ".";
+      return;
+    }
+    const SessionUpdateRequest& session_update_request =
+        session_update_request_iterator->second;
 
-    message_loop_->PostTask(
-        FROM_HERE,
-        base::Bind(&DrmSystemClient::OnSessionUpdateRequestGenerated,
-                   base::Unretained(client_), ticket, session_id_copy,
-                   base::Passed(&content_copy), content_size));
+    // Interpret the result.
+    if (session_id) {
+      // Successful request generation.
+
+      // Enable session lookup by id which is used by spontaneous callbacks.
+      session_update_request.session->set_id(*session_id);
+      id_to_session_map_.insert(
+          std::make_pair(*session_id, session_update_request.session));
+
+      session_update_request.generated_callback.Run(message.Pass(),
+                                                    message_size);
+    } else {
+      // Failure during request generation.
+      session_update_request.did_not_generate_callback.Run();
+    }
+
+    // Sweep the context of |GenerateSessionUpdateRequest|.
+    ticket_to_session_update_request_map_.erase(
+        session_update_request_iterator);
   } else {
-    message_loop_->PostTask(
-        FROM_HERE,
-        base::Bind(&DrmSystemClient::OnSessionUpdateRequestDidNotGenerate,
-                   base::Unretained(client_), ticket));
+    // Called back spontaneously by the underlying DRM system.
+
+    // Find the session by ID.
+    IdToSessionMap::iterator session_iterator =
+        id_to_session_map_.find(*session_id);
+    if (session_iterator == id_to_session_map_.end()) {
+      LOG(ERROR) << "Unknown session id: " << *session_id << ".";
+      return;
+    }
+    Session* session = session_iterator->second;
+
+    session->update_request_generated_callback().Run(message.Pass(),
+                                                     message_size);
   }
 }
 
-void DrmSystem::OnSessionUpdated(int ticket, const void* /*session_id*/,
-                                 int /*session_id_size*/, bool succeeded) {
-  if (succeeded) {
-    message_loop_->PostTask(FROM_HERE,
-                            base::Bind(&DrmSystemClient::OnSessionUpdated,
-                                       base::Unretained(client_), ticket));
-  } else {
-    message_loop_->PostTask(FROM_HERE,
-                            base::Bind(&DrmSystemClient::OnSessionDidNotUpdate,
-                                       base::Unretained(client_), ticket));
+void DrmSystem::OnSessionUpdated(int ticket, bool succeeded) {
+  // Restore the context of |UpdateSession|.
+  TicketToSessionUpdateMap::iterator session_update_iterator =
+      ticket_to_session_update_map_.find(ticket);
+  if (session_update_iterator == ticket_to_session_update_map_.end()) {
+    LOG(ERROR) << "Unknown session update ticket: " << ticket << ".";
+    return;
   }
+  const SessionUpdate& session_update = session_update_iterator->second;
+
+  // Interpret the result.
+  if (succeeded) {
+    session_update.updated_callback.Run();
+  } else {
+    session_update.did_not_update_callback.Run();
+  }
+
+  // Sweep the context of |UpdateSession|.
+  ticket_to_session_update_map_.erase(session_update_iterator);
 }
 
 // static
@@ -97,20 +204,35 @@
   DrmSystem* drm_system = static_cast<DrmSystem*>(context);
   DCHECK_EQ(wrapped_drm_system, drm_system->wrapped_drm_system_);
 
-  drm_system->OnSessionUpdateRequestGenerated(
-      ticket, session_id, session_id_size, content, content_size);
+  base::optional<std::string> session_id_copy;
+  scoped_array<uint8> content_copy;
+  if (session_id) {
+    session_id_copy =
+        std::string(static_cast<const char*>(session_id),
+                    static_cast<const char*>(session_id) + session_id_size);
+
+    content_copy.reset(new uint8[content_size]);
+    SbMemoryCopy(content_copy.get(), content, content_size);
+  }
+
+  drm_system->message_loop_->PostTask(
+      FROM_HERE, base::Bind(&DrmSystem::OnSessionUpdateRequestGenerated,
+                            drm_system->weak_this_, ticket, session_id_copy,
+                            base::Passed(&content_copy), content_size));
 }
 
 // static
 void DrmSystem::OnSessionUpdatedFunc(SbDrmSystem wrapped_drm_system,
                                      void* context, int ticket,
-                                     const void* session_id,
-                                     int session_id_size, bool succeeded) {
+                                     const void* /*session_id*/,
+                                     int /*session_id_size*/, bool succeeded) {
   DCHECK(context);
   DrmSystem* drm_system = static_cast<DrmSystem*>(context);
   DCHECK_EQ(wrapped_drm_system, drm_system->wrapped_drm_system_);
 
-  drm_system->OnSessionUpdated(ticket, session_id, session_id_size, succeeded);
+  drm_system->message_loop_->PostTask(
+      FROM_HERE, base::Bind(&DrmSystem::OnSessionUpdated,
+                            drm_system->weak_this_, ticket, succeeded));
 }
 
 }  // namespace media
diff --git a/src/cobalt/media/base/drm_system.h b/src/cobalt/media/base/drm_system.h
index 018c428..8596241 100644
--- a/src/cobalt/media/base/drm_system.h
+++ b/src/cobalt/media/base/drm_system.h
@@ -17,8 +17,11 @@
 
 #include <string>
 
+#include "base/hash_tables.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/message_loop.h"
-#include "cobalt/media/base/drm_system_client.h"
+#include "base/optional.h"
 #include "starboard/drm.h"
 
 #if SB_API_VERSION < 4
@@ -30,32 +33,122 @@
 
 // A C++ wrapper around |SbDrmSystem|.
 //
-// Ensures that calls to |DrmSystemClient| are always asynchronous and performed
+// Ensures that callbacks are always asynchronous and performed
 // from the same thread where |DrmSystem| was instantiated.
 class DrmSystem {
  public:
-  DrmSystem(const char* key_system, DrmSystemClient* client);
+  typedef base::Callback<void(scoped_array<uint8> message, int message_size)>
+      SessionUpdateRequestGeneratedCallback;
+  typedef base::Callback<void()> SessionUpdateRequestDidNotGenerateCallback;
+  typedef base::Callback<void()> SessionUpdatedCallback;
+  typedef base::Callback<void()> SessionDidNotUpdateCallback;
+
+  // Flyweight that provides RAII semantics for sessions.
+  // Most of logic is implemented by |DrmSystem|.
+  class Session {
+   public:
+    ~Session();
+
+    const base::optional<std::string>& id() const { return id_; }
+
+    // Wraps |SbDrmGenerateSessionUpdateRequest|.
+    //
+    // |session_update_request_generated_callback| is called upon a successful
+    //     request generation. IMPORTANT: It may be called multiple times after
+    //     a single call to |CreateSessionAndGenerateUpdateRequest|, for example
+    //     when the underlying DRM system needs to update a license.
+    //
+    // |session_update_request_did_not_generate_callback| is called upon a
+    //     failure during request generation. Unlike its successful counterpart,
+    //     never called spontaneously.
+    void GenerateUpdateRequest(
+        const std::string& type, const uint8* init_data, int init_data_length,
+        const SessionUpdateRequestGeneratedCallback&
+            session_update_request_generated_callback,
+        const SessionUpdateRequestDidNotGenerateCallback&
+            session_update_request_did_not_generate_callback);
+
+    // Wraps |SbDrmUpdateSession|.
+    //
+    // |session_updated_callback| is called upon a successful session update.
+    // |session_did_not_update_callback| is called upon a failure during session
+    //     update.
+    void Update(
+        const uint8* key, int key_length,
+        const SessionUpdatedCallback& session_updated_callback,
+        const SessionDidNotUpdateCallback& session_did_not_update_callback);
+
+    // Wraps |SbDrmCloseSession|.
+    void Close();
+    bool is_closed() const { return closed_; }
+
+   private:
+    // Private API for |DrmSystem|.
+    explicit Session(DrmSystem* drm_system);
+    void set_id(const std::string& id) { id_ = id; }
+    const SessionUpdateRequestGeneratedCallback&
+    update_request_generated_callback() const {
+      return update_request_generated_callback_;
+    }
+
+    DrmSystem* const drm_system_;
+    bool closed_;
+    base::optional<std::string> id_;
+    // Supports spontaneous invocations of |SbDrmSessionUpdateRequestFunc|.
+    SessionUpdateRequestGeneratedCallback update_request_generated_callback_;
+
+    friend class DrmSystem;
+
+    DISALLOW_COPY_AND_ASSIGN(Session);
+  };
+
+  explicit DrmSystem(const char* key_system);
   ~DrmSystem();
 
   SbDrmSystem wrapped_drm_system() { return wrapped_drm_system_; }
 
-  // Wraps |SbDrmGenerateSessionUpdateRequest|.
-  void GenerateSessionUpdateRequest(int ticket, const std::string& type,
-                                    const uint8* init_data,
-                                    int init_data_length);
-  // Wraps |SbDrmUpdateSession|.
-  void UpdateSession(int ticket, const std::string& session_id,
-                     const uint8* key, int key_length);
-  // Wraps |SbDrmCloseSession|.
-  void CloseSession(const std::string& session_id);
+  scoped_ptr<Session> CreateSession();
 
  private:
-  void OnSessionUpdateRequestGenerated(int ticket, const void* session_id,
-                                       int session_id_size, const void* content,
-                                       int content_size);
-  void OnSessionUpdated(int ticket, const void* session_id, int session_id_size,
-                        bool succeeded);
+  // Stores context of |GenerateSessionUpdateRequest|.
+  struct SessionUpdateRequest {
+    Session* session;
+    SessionUpdateRequestGeneratedCallback generated_callback;
+    SessionUpdateRequestDidNotGenerateCallback did_not_generate_callback;
+  };
+  typedef base::hash_map<int, SessionUpdateRequest>
+      TicketToSessionUpdateRequestMap;
 
+  typedef base::hash_map<std::string, Session*> IdToSessionMap;
+
+  // Stores context of |Session::Update|.
+  struct SessionUpdate {
+    SessionUpdatedCallback updated_callback;
+    SessionDidNotUpdateCallback did_not_update_callback;
+  };
+  typedef base::hash_map<int, SessionUpdate> TicketToSessionUpdateMap;
+
+  // Private API for |Session|.
+  void GenerateSessionUpdateRequest(
+      Session* session, const std::string& type, const uint8_t* init_data,
+      int init_data_length, const SessionUpdateRequestGeneratedCallback&
+                                session_update_request_generated_callback,
+      const SessionUpdateRequestDidNotGenerateCallback&
+          session_update_request_did_not_generate_callback);
+  void UpdateSession(
+      const std::string& session_id, const uint8_t* key, int key_length,
+      const SessionUpdatedCallback& session_updated_callback,
+      const SessionDidNotUpdateCallback& session_did_not_update_callback);
+  void CloseSession(const std::string& session_id);
+
+  // Called on the constructor thread, parameters are copied and owned by these
+  // methods.
+  void OnSessionUpdateRequestGenerated(
+      int ticket, const base::optional<std::string>& session_id,
+      scoped_array<uint8> message, int message_size);
+  void OnSessionUpdated(int ticket, bool succeeded);
+
+  // Called on any thread, parameters need to be copied immediately.
   static void OnSessionUpdateRequestGeneratedFunc(
       SbDrmSystem wrapped_drm_system, void* context, int ticket,
       const void* session_id, int session_id_size, const void* content,
@@ -65,10 +158,26 @@
                                    const void* session_id,
                                    int session_id_length, bool succeeded);
 
-  DrmSystemClient* const client_;
   const SbDrmSystem wrapped_drm_system_;
   MessageLoop* const message_loop_;
 
+  // Factory should only be used to create the initial weak pointer. All
+  // subsequent weak pointers are created by copying the initial one. This is
+  // required to keep weak pointers bound to the constructor thread.
+  base::WeakPtrFactory<DrmSystem> weak_ptr_factory_;
+  base::WeakPtr<DrmSystem> weak_this_;
+
+  // Supports concurrent calls to |GenerateSessionUpdateRequest|.
+  int next_session_update_request_ticket_;
+  TicketToSessionUpdateRequestMap ticket_to_session_update_request_map_;
+
+  // Supports spontaneous invocations of |SbDrmSessionUpdateRequestFunc|.
+  IdToSessionMap id_to_session_map_;
+
+  // Supports concurrent calls to |Session::Update|.
+  int next_session_update_ticket_;
+  TicketToSessionUpdateMap ticket_to_session_update_map_;
+
   DISALLOW_COPY_AND_ASSIGN(DrmSystem);
 };
 
diff --git a/src/cobalt/media/base/drm_system_client.h b/src/cobalt/media/base/drm_system_client.h
deleted file mode 100644
index a0fddfe..0000000
--- a/src/cobalt/media/base/drm_system_client.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2017 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef COBALT_MEDIA_BASE_DRM_SYSTEM_CLIENT_H_
-#define COBALT_MEDIA_BASE_DRM_SYSTEM_CLIENT_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-
-namespace cobalt {
-namespace media {
-
-// An interface to be implemented by clients of |DrmSystem|.
-//
-// Calls to |DrmSystemClient| are always performed from the same thread
-// where |DrmSystem| was instantiated.
-class DrmSystemClient {
- public:
-  // When called as a result of |DrmSystem::GenerateSessionUpdateRequest|, this
-  // method denotes a successful request generation.
-  //
-  // This method may be called multiple times after a single call to
-  // |GenerateSessionUpdateRequest|, for example when the underlying DRM system
-  // needs to update a license. In this case |ticket| will be
-  // |kSbDrmTicketInvalid|.
-  virtual void OnSessionUpdateRequestGenerated(int ticket,
-                                               const std::string& session_id,
-                                               scoped_array<uint8> message,
-                                               int message_size) = 0;
-  // Called as a result of |GenerateSessionUpdateRequest| and denotes a failure
-  // during request generation.
-  //
-  // Unlike its successful counterpart, never called spontaneously.
-  virtual void OnSessionUpdateRequestDidNotGenerate(int ticket) = 0;
-
-  // Called as a result of |UpdateSession| and denotes a successful session
-  // update.
-  virtual void OnSessionUpdated(int ticket) = 0;
-  // Called as a result of |UpdateSession| and denotes a failure during session
-  // update.
-  virtual void OnSessionDidNotUpdate(int ticket) = 0;
-
- protected:
-  virtual ~DrmSystemClient() {}
-};
-
-}  // namespace media
-}  // namespace cobalt
-
-#endif  // COBALT_MEDIA_BASE_DRM_SYSTEM_CLIENT_H_
diff --git a/src/cobalt/media/media2.gyp b/src/cobalt/media/media2.gyp
index 18c1683..982b364 100644
--- a/src/cobalt/media/media2.gyp
+++ b/src/cobalt/media/media2.gyp
@@ -65,7 +65,6 @@
         'base/demuxer_stream_provider.h',
         'base/drm_system.cc',
         'base/drm_system.h',
-        'base/drm_system_client.h',
         'base/encryption_scheme.cc',
         'base/encryption_scheme.h',
         'base/hdr_metadata.cc',
diff --git a/src/cobalt/media/media_module.cc b/src/cobalt/media/media_module.cc
index d92a105..d444ea8 100644
--- a/src/cobalt/media/media_module.cc
+++ b/src/cobalt/media/media_module.cc
@@ -86,6 +86,8 @@
 void MediaModule::SuspendTask() {
   DCHECK(message_loop_->BelongsToCurrentThread());
 
+  suspended_ = true;
+
   for (Players::iterator iter = players_.begin(); iter != players_.end();
        ++iter) {
     DCHECK(!iter->second);
@@ -105,6 +107,8 @@
       iter->first->Resume();
     }
   }
+
+  suspended_ = false;
 }
 
 void MediaModule::RegisterPlayerTask(WebMediaPlayer* player) {
@@ -115,6 +119,10 @@
 
   // Track debug state for the most recently added WebMediaPlayer instance.
   RegisterDebugState(player);
+
+  if (suspended_) {
+    player->Suspend();
+  }
 }
 
 void MediaModule::UnregisterPlayerTask(WebMediaPlayer* player) {
diff --git a/src/cobalt/media/media_module.h b/src/cobalt/media/media_module.h
index f45ef44..f4b10c2 100644
--- a/src/cobalt/media/media_module.h
+++ b/src/cobalt/media/media_module.h
@@ -118,7 +118,7 @@
 
  protected:
   explicit MediaModule(const math::Size& output_size)
-      : thread_("media_module"), output_size_(output_size) {
+      : thread_("media_module"), output_size_(output_size), suspended_(false) {
     thread_.Start();
     message_loop_ = thread_.message_loop_proxy();
   }
@@ -140,6 +140,7 @@
   scoped_refptr<base::MessageLoopProxy> message_loop_;
   Players players_;
   math::Size output_size_;
+  bool suspended_;
 };
 
 }  // namespace media
diff --git a/src/cobalt/media/player/web_media_player.h b/src/cobalt/media/player/web_media_player.h
index 6cd7800..f81d2ad 100644
--- a/src/cobalt/media/player/web_media_player.h
+++ b/src/cobalt/media/player/web_media_player.h
@@ -165,27 +165,6 @@
     return false;
   }
 
-  // Returns whether keySystem is supported. If true, the result will be
-  // reported by an event.
-  virtual MediaKeyException GenerateKeyRequest(
-      const std::string& /* key_system */, const unsigned char* /* init_data */,
-      unsigned /* init_data_length */) {
-    return kMediaKeyExceptionKeySystemNotSupported;
-  }
-  virtual MediaKeyException AddKey(const std::string& /* key_system */,
-                                   const unsigned char* /* key */,
-                                   unsigned /* key_length */,
-                                   const unsigned char* /* init_data */,
-                                   unsigned /* init_data_length */,
-                                   const std::string& /* session_id */) {
-    return kMediaKeyExceptionKeySystemNotSupported;
-  }
-  virtual MediaKeyException CancelKeyRequest(
-      const std::string& /* key_system */,
-      const std::string& /* session_id */) {
-    return kMediaKeyExceptionKeySystemNotSupported;
-  }
-
   virtual SetBoundsCB GetSetBoundsCB() { return SetBoundsCB(); }
 
   // Instruct WebMediaPlayer to enter/exit fullscreen.
@@ -213,21 +192,6 @@
 //       as |NetworkStateChanged|, |SourceOpened|, |EncryptedMediaInitData|.
 class WebMediaPlayerClient {
  public:
-  enum MediaKeyErrorCode {
-    kMediaKeyErrorCodeUnknown = 1,
-    kMediaKeyErrorCodeClient,
-    kMediaKeyErrorCodeService,
-    kMediaKeyErrorCodeOutput,
-    kMediaKeyErrorCodeHardwareChange,
-    kMediaKeyErrorCodeDomain,
-    kUnknownError = kMediaKeyErrorCodeUnknown,
-    kClientError = kMediaKeyErrorCodeClient,
-    kServiceError = kMediaKeyErrorCodeService,
-    kOutputError = kMediaKeyErrorCodeOutput,
-    kHardwareChangeError = kMediaKeyErrorCodeHardwareChange,
-    kDomainError = kMediaKeyErrorCodeDomain,
-  };
-
   virtual void NetworkStateChanged() = 0;
   virtual void ReadyStateChanged() = 0;
   virtual void TimeChanged() = 0;
@@ -248,34 +212,9 @@
   // Notifies the client that a video is encrypted. Client is supposed to call
   // |WebMediaPlayer::SetDrmSystem| as soon as possible to avoid stalling
   // playback.
-  virtual void EncryptedMediaInitData(EmeInitDataType init_data_type,
-                                      const unsigned char* init_data,
-                                      unsigned init_data_length) = 0;
-  // TODO: Make the EME related functions pure virtual again once
-  // we have proper EME implementation. Currently empty implementation are
-  // provided to make media temporarily work.
-  virtual void KeyAdded(const std::string& /* key_system */,
-                        const std::string& /* session_id */) {
-    NOTIMPLEMENTED();
-  }
-  virtual void KeyError(const std::string& /* key_system */,
-                        const std::string& /* session_id */, MediaKeyErrorCode,
-                        unsigned short /* system_code */) {
-    NOTIMPLEMENTED();
-  }
-  virtual void KeyMessage(const std::string& /* key_system */,
-                          const std::string& /* session_id */,
-                          const unsigned char* /* message */,
-                          unsigned /* message_length */,
-                          const std::string& /* default_url */) {
-    NOTIMPLEMENTED();
-  }
-  virtual void KeyNeeded(const std::string& /* key_system */,
-                         const std::string& /* session_id */,
-                         const unsigned char* /* init_data */,
-                         unsigned /* init_data_length */) {
-    NOTIMPLEMENTED();
-  }
+  virtual void EncryptedMediaInitDataEncountered(EmeInitDataType init_data_type,
+                                                 const unsigned char* init_data,
+                                                 unsigned init_data_length) = 0;
   // TODO: Revisit the necessity of the following functions.
   virtual void CloseHelperPlugin() { NOTREACHED(); }
   virtual void DisableAcceleratedCompositing() {}
diff --git a/src/cobalt/media/player/web_media_player_impl.cc b/src/cobalt/media/player/web_media_player_impl.cc
index 7bff85f..c8477bd 100644
--- a/src/cobalt/media/player/web_media_player_impl.cc
+++ b/src/cobalt/media/player/web_media_player_impl.cc
@@ -213,7 +213,8 @@
   chunk_demuxer_.reset(new ChunkDemuxer(
       buffer_allocator_,
       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
-      BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnEncryptedMediaInitData),
+      BIND_TO_RENDER_LOOP(
+          &WebMediaPlayerImpl::OnEncryptedMediaInitDataEncountered),
       media_log_, true));
 
   supports_save_ = false;
@@ -757,12 +758,12 @@
   *is_seeking = state_.seeking;
 }
 
-void WebMediaPlayerImpl::OnEncryptedMediaInitData(
+void WebMediaPlayerImpl::OnEncryptedMediaInitDataEncountered(
     EmeInitDataType init_data_type, const std::vector<uint8_t>& init_data) {
   DCHECK_EQ(main_loop_, MessageLoop::current());
 
-  GetClient()->EncryptedMediaInitData(init_data_type, &init_data[0],
-                                      init_data.size());
+  GetClient()->EncryptedMediaInitDataEncountered(init_data_type, &init_data[0],
+                                                 init_data.size());
 }
 
 WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() {
diff --git a/src/cobalt/media/player/web_media_player_impl.h b/src/cobalt/media/player/web_media_player_impl.h
index 9df3e68..3babef5 100644
--- a/src/cobalt/media/player/web_media_player_impl.h
+++ b/src/cobalt/media/player/web_media_player_impl.h
@@ -209,8 +209,8 @@
 
   void GetMediaTimeAndSeekingState(base::TimeDelta* media_time,
                                    bool* is_seeking) const;
-  void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
-                                const std::vector<uint8_t>& init_data);
+  void OnEncryptedMediaInitDataEncountered(
+      EmeInitDataType init_data_type, const std::vector<uint8_t>& init_data);
 
   // Getter method to |client_|.
   WebMediaPlayerClient* GetClient();
diff --git a/src/cobalt/media/sandbox/web_media_player_helper.cc b/src/cobalt/media/sandbox/web_media_player_helper.cc
index 2adef29..adb3afe 100644
--- a/src/cobalt/media/sandbox/web_media_player_helper.cc
+++ b/src/cobalt/media/sandbox/web_media_player_helper.cc
@@ -47,9 +47,9 @@
 #endif  // defined(COBALT_MEDIA_SOURCE_2016)
   std::string SourceURL() const OVERRIDE { return ""; }
 #if defined(COBALT_MEDIA_SOURCE_2016)
-  void EncryptedMediaInitData(EmeInitDataType init_data_type,
-                              const unsigned char* init_data,
-                              unsigned init_data_length) OVERRIDE {}
+  void EncryptedMediaInitDataEncountered(EmeInitDataType init_data_type,
+                                         const unsigned char* init_data,
+                                         unsigned init_data_length) OVERRIDE {}
 #endif  // defined(COBALT_MEDIA_SOURCE_2016)
 };
 
diff --git a/src/cobalt/render_tree/mock_resource_provider.h b/src/cobalt/render_tree/mock_resource_provider.h
index 0fba09f..1d13b6c 100644
--- a/src/cobalt/render_tree/mock_resource_provider.h
+++ b/src/cobalt/render_tree/mock_resource_provider.h
@@ -164,8 +164,6 @@
       Mesh::DrawMode draw_mode) {
     return make_scoped_refptr(CreateMeshMock(vertices.get(), draw_mode));
   }
-
-  virtual void PurgeCaches() {}
 };
 
 }  // namespace render_tree
diff --git a/src/cobalt/render_tree/resource_provider.h b/src/cobalt/render_tree/resource_provider.h
index be1c28e..4a648d1 100644
--- a/src/cobalt/render_tree/resource_provider.h
+++ b/src/cobalt/render_tree/resource_provider.h
@@ -210,17 +210,13 @@
                              render_tree::FontProvider* font_provider,
                              render_tree::FontVector* maybe_used_fonts) = 0;
 
-  // Cconsumes a list of vertices and returns
-  // a Mesh instance.
+  // Consumes a list of vertices and returns a Mesh instance.
   virtual scoped_refptr<Mesh> CreateMesh(
       scoped_ptr<std::vector<Mesh::Vertex> > vertices,
       Mesh::DrawMode draw_mode) = 0;
 
   virtual scoped_refptr<Image> DrawOffscreenImage(
       const scoped_refptr<render_tree::Node>& root) = 0;
-
-  // Purges any caches being used by the render_tree consumer.
-  virtual void PurgeCaches() = 0;
 };
 
 }  // namespace render_tree
diff --git a/src/cobalt/render_tree/resource_provider_stub.h b/src/cobalt/render_tree/resource_provider_stub.h
index 0f70147..5d33cd0 100644
--- a/src/cobalt/render_tree/resource_provider_stub.h
+++ b/src/cobalt/render_tree/resource_provider_stub.h
@@ -331,8 +331,6 @@
     UNREFERENCED_PARAMETER(root);
     return scoped_refptr<Image>(NULL);
   }
-
-  void PurgeCaches() OVERRIDE {}
 };
 
 }  // namespace render_tree
diff --git a/src/cobalt/renderer/backend/backend.gyp b/src/cobalt/renderer/backend/backend.gyp
index d1f4aa2..b2f6e71 100644
--- a/src/cobalt/renderer/backend/backend.gyp
+++ b/src/cobalt/renderer/backend/backend.gyp
@@ -16,7 +16,11 @@
   'targets': [
     {
       'target_name': 'renderer_backend',
-      'type': 'none',
+      'type': 'static_library',
+      'sources': [
+        'render_target.cc',
+        'render_target.h',
+      ],
 
       'dependencies': [
         '<(DEPTH)/cobalt/base/base.gyp:base',
diff --git a/src/cobalt/renderer/backend/egl/graphics_context.cc b/src/cobalt/renderer/backend/egl/graphics_context.cc
index 7b8b9bd..1211584 100644
--- a/src/cobalt/renderer/backend/egl/graphics_context.cc
+++ b/src/cobalt/renderer/backend/egl/graphics_context.cc
@@ -245,7 +245,22 @@
     // that can be bound using eglMakeCurrent.
     DCHECK_EQ(surface->GetPlatformHandle(), 0);
 
-    EGL_CALL(eglMakeCurrent(display_, egl_surface, egl_surface, context_));
+    eglMakeCurrent(display_, egl_surface, egl_surface, context_);
+    EGLint make_current_error = eglGetError();
+    if (make_current_error != EGL_SUCCESS) {
+      LOG(ERROR) << "eglMakeCurrent ERROR: " << make_current_error;
+      if (make_current_error == EGL_BAD_ALLOC ||
+          make_current_error == EGL_BAD_NATIVE_WINDOW) {
+        LOG(ERROR) << "eglMakeCurrent raised either EGL_BAD_ALLOC or "
+                      "EGL_BAD_NATIVE_WINDOW, continuing with null surface "
+                      "under the assumption that our window surface has become "
+                      "invalid due to a suspend or shutdown being triggered.";
+        egl_surface = null_surface_->GetSurface();
+        EGL_CALL(eglMakeCurrent(display_, egl_surface, egl_surface, context_));
+      } else {
+        NOTREACHED() << "Unexpected error when calling eglMakeCurrent().";
+      }
+    }
 
     // Minimize calls to glBindFramebuffer. Normally, nothing keeps their
     // framebuffer object bound, so 0 is normally bound at this point --
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/cobalt/renderer/backend/render_target.cc
similarity index 62%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/cobalt/renderer/backend/render_target.cc
index 51e1f2e..3126b97 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/cobalt/renderer/backend/render_target.cc
@@ -12,9 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "cobalt/renderer/backend/render_target.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include "starboard/atomic.h"
+
+namespace cobalt {
+namespace renderer {
+namespace backend {
+
+SbAtomic32 RenderTarget::serial_counter_ = 1;
+
+RenderTarget::RenderTarget() {
+  serial_number_ = SbAtomicBarrier_Increment(&serial_counter_, 1);
+}
+
+}  // namespace backend
+}  // namespace renderer
+}  // namespace cobalt
diff --git a/src/cobalt/renderer/backend/render_target.h b/src/cobalt/renderer/backend/render_target.h
index ebaa335..fef9bc6 100644
--- a/src/cobalt/renderer/backend/render_target.h
+++ b/src/cobalt/renderer/backend/render_target.h
@@ -34,6 +34,8 @@
 // after rendering is completed.
 class RenderTarget : public base::RefCountedThreadSafe<RenderTarget> {
  public:
+  RenderTarget();
+
   // Return metadata about the render target such as dimensions and format.
   virtual const math::Size& GetSize() = 0;
 
@@ -41,10 +43,16 @@
   // passed into platform-specific code.
   virtual intptr_t GetPlatformHandle() = 0;
 
+  // Each render is assigned a unique serial number on construction.
+  int32_t GetSerialNumber() const { return serial_number_; }
+
  protected:
   // Concrete child classes should declare their destructors as private.
   friend class base::RefCountedThreadSafe<RenderTarget>;
   virtual ~RenderTarget() {}
+
+  static SbAtomic32 serial_counter_;
+  int32_t serial_number_;
 };
 
 }  // namespace backend
diff --git a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
index d7cf41c..1c5e2d4 100644
--- a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
@@ -34,13 +34,13 @@
   return coord_mapping.output_bounds.size().GetArea() * 4;
 }
 
-CachedSoftwareRasterizer::CachedSoftwareRasterizer(SbBlitterDevice device,
-                                                   SbBlitterContext context,
-                                                   int cache_capacity)
+CachedSoftwareRasterizer::CachedSoftwareRasterizer(
+    SbBlitterDevice device, SbBlitterContext context, int cache_capacity,
+    bool purge_skia_font_caches_on_destruction)
     : cache_capacity_(cache_capacity),
       device_(device),
       context_(context),
-      software_rasterizer_(0),
+      software_rasterizer_(0, purge_skia_font_caches_on_destruction),
       cache_memory_usage_(
           "Memory.CachedSoftwareRasterizer.CacheUsage", 0,
           "Total memory occupied by cached software-rasterized surfaces."),
@@ -56,6 +56,7 @@
     DCHECK(iter->second.cached);
     SbBlitterDestroySurface(iter->second.surface);
   }
+  surface_map_.clear();
 }
 
 void CachedSoftwareRasterizer::OnStartNewFrame() {
diff --git a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.h b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.h
index 99cefba..ce37064 100644
--- a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.h
@@ -73,7 +73,8 @@
   };
 
   CachedSoftwareRasterizer(SbBlitterDevice device, SbBlitterContext context,
-                           int cache_capacity);
+                           int cache_capacity,
+                           bool purge_skia_font_caches_on_destruction);
   ~CachedSoftwareRasterizer();
 
   // Should be called once per frame.  This method will remove from the cache
diff --git a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
index a67044e..2ed5599 100644
--- a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
@@ -46,7 +46,8 @@
                 int skia_atlas_width, int skia_atlas_height,
                 int scratch_surface_size_in_bytes,
                 int surface_cache_size_in_bytes,
-                int software_surface_cache_size_in_bytes);
+                int software_surface_cache_size_in_bytes,
+                bool purge_skia_font_caches_on_destruction);
   ~Impl();
 
   void Submit(const scoped_refptr<render_tree::Node>& render_tree,
@@ -99,7 +100,8 @@
                                int skia_atlas_width, int skia_atlas_height,
                                int scratch_surface_size_in_bytes,
                                int surface_cache_size_in_bytes,
-                               int software_surface_cache_size_in_bytes)
+                               int software_surface_cache_size_in_bytes,
+                               bool purge_skia_font_caches_on_destruction)
     : context_(base::polymorphic_downcast<backend::GraphicsContextBlitter*>(
           graphics_context)),
       submit_count_(0),
@@ -109,7 +111,8 @@
                              scratch_surface_size_in_bytes),
       software_surface_cache_(context_->GetSbBlitterDevice(),
                               context_->GetSbBlitterContext(),
-                              software_surface_cache_size_in_bytes)
+                              software_surface_cache_size_in_bytes,
+                              purge_skia_font_caches_on_destruction)
 #if defined(ENABLE_DEBUG_CONSOLE)
       ,
       toggle_highlight_software_draws_(false),
@@ -294,15 +297,14 @@
 #endif  // #if defined(COBALT_RENDER_DIRTY_REGION_ONLY)
 
 HardwareRasterizer::HardwareRasterizer(
-    backend::GraphicsContext* graphics_context,
-    int skia_atlas_width, int skia_atlas_height,
-    int scratch_surface_size_in_bytes, int surface_cache_size_in_bytes,
-    int software_surface_cache_size_in_bytes)
-    : impl_(new Impl(graphics_context,
-                     skia_atlas_width, skia_atlas_height,
-                     scratch_surface_size_in_bytes,
-                     surface_cache_size_in_bytes,
-                     software_surface_cache_size_in_bytes)) {}
+    backend::GraphicsContext* graphics_context, int skia_atlas_width,
+    int skia_atlas_height, int scratch_surface_size_in_bytes,
+    int surface_cache_size_in_bytes, int software_surface_cache_size_in_bytes,
+    bool purge_skia_font_caches_on_destruction)
+    : impl_(new Impl(graphics_context, skia_atlas_width, skia_atlas_height,
+                     scratch_surface_size_in_bytes, surface_cache_size_in_bytes,
+                     software_surface_cache_size_in_bytes,
+                     purge_skia_font_caches_on_destruction)) {}
 
 HardwareRasterizer::~HardwareRasterizer() {}
 
diff --git a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h
index 20afd3e..e830221 100644
--- a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h
@@ -40,7 +40,8 @@
                               int skia_atlas_width, int skia_atlas_height,
                               int scratch_surface_size_in_bytes,
                               int surface_cache_size_in_bytes,
-                              int software_surface_cache_size_in_bytes);
+                              int software_surface_cache_size_in_bytes,
+                              bool purge_skia_font_caches_on_destruction);
   virtual ~HardwareRasterizer();
 
   // Consume the render tree and output the results to the render target passed
diff --git a/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc b/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc
index f72fafa..2315836 100644
--- a/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc
@@ -213,8 +213,6 @@
       new SinglePlaneImage(root, submit_offscreen_callback_, device_));
 }
 
-void ResourceProvider::PurgeCaches() { skia_resource_provider_->PurgeCaches(); }
-
 }  // namespace blitter
 }  // namespace rasterizer
 }  // namespace renderer
diff --git a/src/cobalt/renderer/rasterizer/blitter/resource_provider.h b/src/cobalt/renderer/rasterizer/blitter/resource_provider.h
index bf67280..3f01c64 100644
--- a/src/cobalt/renderer/rasterizer/blitter/resource_provider.h
+++ b/src/cobalt/renderer/rasterizer/blitter/resource_provider.h
@@ -113,8 +113,6 @@
   scoped_refptr<render_tree::Image> DrawOffscreenImage(
       const scoped_refptr<render_tree::Node>& root) OVERRIDE;
 
-  void PurgeCaches() OVERRIDE;
-
  private:
   SbBlitterDevice device_;
 
diff --git a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc
index f8e683c..33dc2d1 100644
--- a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.cc
@@ -29,11 +29,13 @@
 namespace rasterizer {
 namespace blitter {
 
-SoftwareRasterizer::SoftwareRasterizer(backend::GraphicsContext* context,
-                                       int surface_cache_size)
+SoftwareRasterizer::SoftwareRasterizer(
+    backend::GraphicsContext* context, int surface_cache_size,
+    bool purge_skia_font_caches_on_destruction)
     : context_(base::polymorphic_downcast<backend::GraphicsContextBlitter*>(
           context)),
-      skia_rasterizer_(surface_cache_size) {}
+      skia_rasterizer_(surface_cache_size,
+                       purge_skia_font_caches_on_destruction) {}
 
 void SoftwareRasterizer::Submit(
     const scoped_refptr<render_tree::Node>& render_tree,
diff --git a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h
index b868493..5c5d533 100644
--- a/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/blitter/software_rasterizer.h
@@ -38,7 +38,8 @@
 class SoftwareRasterizer : public Rasterizer {
  public:
   explicit SoftwareRasterizer(backend::GraphicsContext* context,
-                              int surface_cache_size);
+                              int surface_cache_size,
+                              bool purge_skia_font_caches_on_destruction);
 
   void Submit(const scoped_refptr<render_tree::Node>& render_tree,
               const scoped_refptr<backend::RenderTarget>& render_target,
diff --git a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
index 2cc8005..10c3a9d 100644
--- a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
@@ -46,7 +46,8 @@
                 int skia_atlas_width, int skia_atlas_height,
                 int skia_cache_size_in_bytes,
                 int scratch_surface_cache_size_in_bytes,
-                int surface_cache_size_in_bytes);
+                int surface_cache_size_in_bytes,
+                bool purge_skia_font_caches_on_destruction);
   ~Impl();
 
   void Submit(const scoped_refptr<render_tree::Node>& render_tree,
@@ -85,11 +86,13 @@
                                int skia_atlas_width, int skia_atlas_height,
                                int skia_cache_size_in_bytes,
                                int scratch_surface_cache_size_in_bytes,
-                               int surface_cache_size_in_bytes)
+                               int surface_cache_size_in_bytes,
+                               bool purge_skia_font_caches_on_destruction)
     : fallback_rasterizer_(new skia::HardwareRasterizer(
           graphics_context, skia_atlas_width, skia_atlas_height,
           skia_cache_size_in_bytes, scratch_surface_cache_size_in_bytes,
-          0 /* fallback rasterizer should not use a surface cache */)),
+          0 /* fallback rasterizer should not use a surface cache */,
+          purge_skia_font_caches_on_destruction)),
       graphics_context_(
           base::polymorphic_downcast<backend::GraphicsContextEGL*>(
               graphics_context)) {
@@ -271,11 +274,13 @@
 HardwareRasterizer::HardwareRasterizer(
     backend::GraphicsContext* graphics_context, int skia_atlas_width,
     int skia_atlas_height, int skia_cache_size_in_bytes,
-    int scratch_surface_cache_size_in_bytes, int surface_cache_size_in_bytes)
-    : impl_(new Impl(graphics_context, skia_atlas_width, skia_atlas_height,
-                     skia_cache_size_in_bytes,
-                     scratch_surface_cache_size_in_bytes,
-                     surface_cache_size_in_bytes)) {}
+    int scratch_surface_cache_size_in_bytes, int surface_cache_size_in_bytes,
+    bool purge_skia_font_caches_on_destruction)
+    : impl_(new Impl(
+          graphics_context, skia_atlas_width, skia_atlas_height,
+          skia_cache_size_in_bytes, scratch_surface_cache_size_in_bytes,
+          surface_cache_size_in_bytes, purge_skia_font_caches_on_destruction)) {
+}
 
 void HardwareRasterizer::Submit(
     const scoped_refptr<render_tree::Node>& render_tree,
diff --git a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.h b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.h
index dc5c9b4..dc03019 100644
--- a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.h
@@ -49,7 +49,8 @@
                               int skia_atlas_width, int skia_atlas_height,
                               int skia_cache_size_in_bytes,
                               int scratch_surface_cache_size_in_bytes,
-                              int surface_cache_size_in_bytes);
+                              int surface_cache_size_in_bytes,
+                              bool purge_skia_font_caches_on_destruction);
 
   void Submit(const scoped_refptr<render_tree::Node>& render_tree,
               const scoped_refptr<backend::RenderTarget>& render_target,
diff --git a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc
index 319f6ed..c567846 100644
--- a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.cc
@@ -30,11 +30,13 @@
 namespace rasterizer {
 namespace egl {
 
-SoftwareRasterizer::SoftwareRasterizer(backend::GraphicsContext* context,
-                                       int surface_cache_size)
+SoftwareRasterizer::SoftwareRasterizer(
+    backend::GraphicsContext* context, int surface_cache_size,
+    bool purge_skia_font_caches_on_destruction)
     : context_(
           base::polymorphic_downcast<backend::GraphicsContextEGL*>(context)),
-      skia_rasterizer_(surface_cache_size) {}
+      skia_rasterizer_(surface_cache_size,
+                       purge_skia_font_caches_on_destruction) {}
 
 void SoftwareRasterizer::Submit(
     const scoped_refptr<render_tree::Node>& render_tree,
diff --git a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h
index ce906c0..afb3c0b 100644
--- a/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/egl/software_rasterizer.h
@@ -38,7 +38,8 @@
 class SoftwareRasterizer : public Rasterizer {
  public:
   explicit SoftwareRasterizer(backend::GraphicsContext* context,
-                              int surface_cache_size);
+                              int surface_cache_size,
+                              bool purge_skia_font_caches_on_destruction);
 
   void Submit(const scoped_refptr<render_tree::Node>& render_tree,
               const scoped_refptr<backend::RenderTarget>& render_target,
diff --git a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
index 8ac80c8..5ce02f6 100644
--- a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
@@ -35,7 +35,8 @@
        int skia_atlas_width, int skia_atlas_height,
        int skia_cache_size_in_bytes,
        int scratch_surface_cache_size_in_bytes,
-       int surface_cache_size_in_bytes);
+       int surface_cache_size_in_bytes,
+       bool purge_skia_font_caches_on_destruction);
   ~Impl();
 
   void Submit(const scoped_refptr<render_tree::Node>& render_tree,
@@ -62,14 +63,16 @@
                                int skia_atlas_width, int skia_atlas_height,
                                int skia_cache_size_in_bytes,
                                int scratch_surface_cache_size_in_bytes,
-                               int surface_cache_size_in_bytes)
+                               int surface_cache_size_in_bytes,
+                               bool purge_skia_font_caches_on_destruction)
     : graphics_context_(
           base::polymorphic_downcast<backend::GraphicsContextEGL*>(
               graphics_context)),
       hardware_rasterizer_(graphics_context, skia_atlas_width,
                            skia_atlas_height, skia_cache_size_in_bytes,
                            scratch_surface_cache_size_in_bytes,
-                           surface_cache_size_in_bytes) {
+                           surface_cache_size_in_bytes,
+                           purge_skia_font_caches_on_destruction) {
   options_.flags = skia::HardwareRasterizer::kSubmitFlags_Clear;
   graphics_context_->MakeCurrent();
 
@@ -120,11 +123,13 @@
 ExternalRasterizer::ExternalRasterizer(
     backend::GraphicsContext* graphics_context, int skia_atlas_width,
     int skia_atlas_height, int skia_cache_size_in_bytes,
-    int scratch_surface_cache_size_in_bytes, int surface_cache_size_in_bytes)
+    int scratch_surface_cache_size_in_bytes, int surface_cache_size_in_bytes,
+    bool purge_skia_font_caches_on_destruction)
     : impl_(new Impl(graphics_context, skia_atlas_width, skia_atlas_height,
                      skia_cache_size_in_bytes,
                      scratch_surface_cache_size_in_bytes,
-                     surface_cache_size_in_bytes)) {}
+                     surface_cache_size_in_bytes,
+                     purge_skia_font_caches_on_destruction)) {}
 
 ExternalRasterizer::~ExternalRasterizer() {}
 
diff --git a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.h b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.h
index 49ffc32..16f6f66 100644
--- a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.h
@@ -37,7 +37,8 @@
                      int skia_atlas_width, int skia_atlas_height,
                      int skia_cache_size_in_bytes,
                      int scratch_surface_cache_size_in_bytes,
-                     int surface_cache_size_in_bytes);
+                     int surface_cache_size_in_bytes,
+                     bool purge_skia_font_caches_on_destruction);
   virtual ~ExternalRasterizer();
 
   void Submit(const scoped_refptr<render_tree::Node>& render_tree,
diff --git a/src/cobalt/renderer/rasterizer/lib/imported/graphics.h b/src/cobalt/renderer/rasterizer/lib/imported/graphics.h
index 125f85f..cde0573 100644
--- a/src/cobalt/renderer/rasterizer/lib/imported/graphics.h
+++ b/src/cobalt/renderer/rasterizer/lib/imported/graphics.h
@@ -18,20 +18,21 @@
 #ifndef COBALT_RENDERER_RASTERIZER_LIB_IMPORTED_GRAPHICS_H_
 #define COBALT_RENDERER_RASTERIZER_LIB_IMPORTED_GRAPHICS_H_
 
-// TODO: Use starboard/types.h instead.
-#include <stdint.h>
+#include "starboard/export.h"
+#include "starboard/types.h"
+
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 // Invoked from the rasterization thread after the GL context has been created.
-void CbLibOnGraphicsContextCreated();
+SB_IMPORT_PLATFORM void CbLibOnGraphicsContextCreated();
 
 // Invoked as often as the platform can swap buffers from the rasterization
 // thread. |render_tree_texture_handle| corresponds to a GLint texture ID for
 // the current RenderTree.
-void CbLibRenderFrame(intptr_t render_tree_texture_handle);
+SB_IMPORT_PLATFORM void CbLibRenderFrame(intptr_t render_tree_texture_handle);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/src/cobalt/renderer/rasterizer/lib/imported/graphics_stub.cc b/src/cobalt/renderer/rasterizer/lib/imported/graphics_stub.cc
new file mode 100644
index 0000000..5d9ece0
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/lib/imported/graphics_stub.cc
@@ -0,0 +1,8 @@
+#include "cobalt/renderer/rasterizer/lib/imported/graphics.h"
+
+// Empty implementations so that 'lib' targets can be compiled into executables
+// by the builder without missing symbol definitions.
+void CbLibOnGraphicsContextCreated() {}
+void CbLibRenderFrame(intptr_t render_tree_texture_handle) {
+  (void)render_tree_texture_handle;
+}
diff --git a/src/cobalt/renderer/rasterizer/lib/lib.gyp b/src/cobalt/renderer/rasterizer/lib/lib.gyp
index 3ff61a8..df38bb4 100644
--- a/src/cobalt/renderer/rasterizer/lib/lib.gyp
+++ b/src/cobalt/renderer/rasterizer/lib/lib.gyp
@@ -25,6 +25,15 @@
         'external_rasterizer.cc',
         'renderer_module_default_options_lib.cc'
       ],
+      'all_dependent_settings': {
+        'target_conditions': [
+          ['_type=="executable" and _toolset=="target"', {
+            'sources': [
+              'imported/graphics_stub.cc',
+            ],
+          }],
+        ],
+      },
        'dependencies': [
          '<(DEPTH)/base/base.gyp:base',
          '<(DEPTH)/cobalt/render_tree/render_tree.gyp:render_tree',
diff --git a/src/cobalt/renderer/rasterizer/lib/renderer_module_default_options_lib.cc b/src/cobalt/renderer/rasterizer/lib/renderer_module_default_options_lib.cc
index 955ea45..4caa615 100644
--- a/src/cobalt/renderer/rasterizer/lib/renderer_module_default_options_lib.cc
+++ b/src/cobalt/renderer/rasterizer/lib/renderer_module_default_options_lib.cc
@@ -24,12 +24,12 @@
     const RendererModule::Options& options) {
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::lib::ExternalRasterizer(
-        graphics_context,
-        options.skia_glyph_texture_atlas_dimensions.width(),
-        options.skia_glyph_texture_atlas_dimensions.height(),
-        options.skia_cache_size_in_bytes,
-        options.scratch_surface_cache_size_in_bytes,
-        options.surface_cache_size_in_bytes));
+          graphics_context, options.skia_glyph_texture_atlas_dimensions.width(),
+          options.skia_glyph_texture_atlas_dimensions.height(),
+          options.skia_cache_size_in_bytes,
+          options.scratch_surface_cache_size_in_bytes,
+          options.surface_cache_size_in_bytes,
+          options.purge_skia_font_caches_on_destruction));
 }
 }  // namespace
 
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
index e569def..b90a09a 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
@@ -56,8 +56,8 @@
  public:
   Impl(backend::GraphicsContext* graphics_context, int skia_atlas_width,
        int skia_atlas_height, int skia_cache_size_in_bytes,
-       int scratch_surface_cache_size_in_bytes,
-       int surface_cache_size_in_bytes);
+       int scratch_surface_cache_size_in_bytes, int surface_cache_size_in_bytes,
+       bool purge_skia_font_caches_on_destruction);
   ~Impl();
 
   void AdvanceFrame();
@@ -82,8 +82,7 @@
   // Note: We cannot store a SkAutoTUnref<SkSurface> in the map because it is
   // not copyable; so we must manually manage our references when adding /
   // removing SkSurfaces from it.
-  typedef base::linked_hash_map<
-    backend::RenderTarget*, SkSurface*> SkSurfaceMap;
+  typedef base::linked_hash_map<int32_t, SkSurface*> SkSurfaceMap;
   class CachedScratchSurfaceHolder
       : public RenderTreeNodeVisitor::ScratchSurface {
    public:
@@ -364,7 +363,8 @@
                                int skia_atlas_width, int skia_atlas_height,
                                int skia_cache_size_in_bytes,
                                int scratch_surface_cache_size_in_bytes,
-                               int surface_cache_size_in_bytes)
+                               int surface_cache_size_in_bytes,
+                               bool purge_skia_font_caches_on_destruction)
     : graphics_context_(
           base::polymorphic_downcast<backend::GraphicsContextEGL*>(
               graphics_context)) {
@@ -404,7 +404,8 @@
   resource_provider_.reset(new HardwareResourceProvider(
       graphics_context_, gr_context_,
       base::Bind(&HardwareRasterizer::Impl::SubmitOffscreenToRenderTarget,
-                 base::Unretained(this))));
+                 base::Unretained(this)),
+      purge_skia_font_caches_on_destruction));
 
   graphics_context_->ReleaseCurrentContext();
 
@@ -589,7 +590,8 @@
 SkCanvas* HardwareRasterizer::Impl::GetCanvasFromRenderTarget(
     const scoped_refptr<backend::RenderTarget>& render_target) {
   SkSurface* sk_output_surface;
-  SkSurfaceMap::iterator iter = sk_output_surface_map_.find(render_target);
+  int32_t surface_map_key = render_target->GetSerialNumber();
+  SkSurfaceMap::iterator iter = sk_output_surface_map_.find(surface_map_key);
   if (iter == sk_output_surface_map_.end()) {
     // Remove the least recently used SkSurface from the map if we exceed the
     // max allowed saved surfaces.
@@ -613,13 +615,13 @@
     // Create an SkSurface from the render target so that we can acquire a
     // SkCanvas object from it in Submit().
     sk_output_surface = CreateSkiaRenderTargetSurface(skia_render_target);
-    sk_output_surface_map_[render_target] = sk_output_surface;
+    sk_output_surface_map_[surface_map_key] = sk_output_surface;
   } else {
-    sk_output_surface = sk_output_surface_map_[render_target];
+    sk_output_surface = sk_output_surface_map_[surface_map_key];
     // Mark this RenderTarget/SkCanvas pair as the most recently used by
     // popping it and re-adding it.
     sk_output_surface_map_.erase(iter);
-    sk_output_surface_map_[render_target] = sk_output_surface;
+    sk_output_surface_map_[surface_map_key] = sk_output_surface;
   }
   return sk_output_surface->getCanvas();
 }
@@ -627,6 +629,9 @@
 void HardwareRasterizer::Impl::RasterizeRenderTreeToCanvas(
     const scoped_refptr<render_tree::Node>& render_tree, SkCanvas* canvas) {
   TRACE_EVENT0("cobalt::renderer", "RasterizeRenderTreeToCanvas");
+  // TODO: This trace uses the name in the current benchmark to keep it work as
+  // expected. Remove after switching to webdriver benchmark.
+  TRACE_EVENT0("cobalt::renderer", "VisitRenderTree");
   RenderTreeNodeVisitor::CreateScratchSurfaceFunction
       create_scratch_surface_function =
           base::Bind(&HardwareRasterizer::Impl::CreateScratchSurface,
@@ -650,11 +655,13 @@
 HardwareRasterizer::HardwareRasterizer(
     backend::GraphicsContext* graphics_context, int skia_atlas_width,
     int skia_atlas_height, int skia_cache_size_in_bytes,
-    int scratch_surface_cache_size_in_bytes, int surface_cache_size_in_bytes)
-    : impl_(new Impl(graphics_context, skia_atlas_width, skia_atlas_height,
-                     skia_cache_size_in_bytes,
-                     scratch_surface_cache_size_in_bytes,
-                     surface_cache_size_in_bytes)) {}
+    int scratch_surface_cache_size_in_bytes, int surface_cache_size_in_bytes,
+    bool purge_skia_font_caches_on_destruction)
+    : impl_(new Impl(
+          graphics_context, skia_atlas_width, skia_atlas_height,
+          skia_cache_size_in_bytes, scratch_surface_cache_size_in_bytes,
+          surface_cache_size_in_bytes, purge_skia_font_caches_on_destruction)) {
+}
 
 HardwareRasterizer::~HardwareRasterizer() {}
 
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.h b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.h
index 7343ca0..aba9fd4 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.h
@@ -54,7 +54,8 @@
                               int skia_atlas_width, int skia_atlas_height,
                               int skia_cache_size_in_bytes,
                               int scratch_surface_cache_size_in_bytes,
-                              int surface_cache_size_in_bytes);
+                              int surface_cache_size_in_bytes,
+                              bool purge_skia_font_caches_on_destruction);
   virtual ~HardwareRasterizer();
 
   // Consume the render tree and output the results to the render target passed
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
index 504faab..e8a4a08 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -47,10 +47,13 @@
 
 HardwareResourceProvider::HardwareResourceProvider(
     backend::GraphicsContextEGL* cobalt_context, GrContext* gr_context,
-    SubmitOffscreenCallback submit_offscreen_callback)
+    SubmitOffscreenCallback submit_offscreen_callback,
+    bool purge_skia_font_caches_on_destruction)
     : cobalt_context_(cobalt_context),
       gr_context_(gr_context),
       submit_offscreen_callback_(submit_offscreen_callback),
+      purge_skia_font_caches_on_destruction_(
+          purge_skia_font_caches_on_destruction),
       self_message_loop_(MessageLoop::current()) {
   // Initialize the font manager now to ensure that it doesn't get initialized
   // on multiple threads simultaneously later.
@@ -68,6 +71,17 @@
            SB_HAS(GRAPHICS)
 }
 
+HardwareResourceProvider::~HardwareResourceProvider() {
+  if (purge_skia_font_caches_on_destruction_) {
+    text_shaper_.PurgeCaches();
+
+    SkAutoTUnref<SkFontMgr> font_manager(SkFontMgr::RefDefault());
+    SkFontMgr_Cobalt* cobalt_font_manager =
+        base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager.get());
+    cobalt_font_manager->PurgeCaches();
+  }
+}
+
 void HardwareResourceProvider::Finish() {
   // Wait for any resource-related to complete (by waiting for all tasks to
   // complete).
@@ -380,13 +394,6 @@
       self_message_loop_));
 }
 
-void HardwareResourceProvider::PurgeCaches() {
-  SkAutoTUnref<SkFontMgr> font_manager(SkFontMgr::RefDefault());
-  SkFontMgr_Cobalt* cobalt_font_manager =
-      base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager.get());
-  cobalt_font_manager->PurgeCaches();
-}
-
 }  // namespace skia
 }  // namespace rasterizer
 }  // namespace renderer
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
index 5fe7814..d5540a8 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
@@ -39,7 +39,9 @@
  public:
   HardwareResourceProvider(backend::GraphicsContextEGL* cobalt_context,
                            GrContext* gr_context,
-                           SubmitOffscreenCallback submit_offscreen_callback);
+                           SubmitOffscreenCallback submit_offscreen_callback,
+                           bool purge_skia_font_caches_on_destruction);
+  ~HardwareResourceProvider() OVERRIDE;
 
   void Finish() OVERRIDE;
 
@@ -136,12 +138,11 @@
   scoped_refptr<render_tree::Image> DrawOffscreenImage(
       const scoped_refptr<render_tree::Node>& root) OVERRIDE;
 
-  void PurgeCaches() OVERRIDE;
-
  private:
   backend::GraphicsContextEGL* cobalt_context_;
   GrContext* gr_context_;
   SubmitOffscreenCallback submit_offscreen_callback_;
+  const bool purge_skia_font_caches_on_destruction_;
 
   TextShaper text_shaper_;
 
diff --git a/src/cobalt/renderer/rasterizer/skia/harfbuzz_font.cc b/src/cobalt/renderer/rasterizer/skia/harfbuzz_font.cc
index 0434fe2..05cde83 100644
--- a/src/cobalt/renderer/rasterizer/skia/harfbuzz_font.cc
+++ b/src/cobalt/renderer/rasterizer/skia/harfbuzz_font.cc
@@ -195,42 +195,32 @@
   SkSafeUnref(skia_face);
 }
 
-// Wrapper class for a HarfBuzz face created from a given Skia face.
-class HarfBuzzFace {
- public:
-  HarfBuzzFace() : face_(NULL) {}
-
-  ~HarfBuzzFace() {
-    if (face_) {
-      hb_face_destroy(face_);
-    }
-  }
-
-  void Init(SkTypeface* skia_face) {
-    face_ = hb_face_create_for_tables(GetFontTable, skia_face, UnrefSkTypeface);
-    DCHECK(face_);
-  }
-
-  hb_face_t* get() { return face_; }
-
- private:
-  hb_face_t* face_;
-};
-
 }  // namespace
 
-// Creates a HarfBuzz font from the given Skia font.
-hb_font_t* CreateHarfBuzzFont(Font* skia_font) {
-  static std::map<SkFontID, HarfBuzzFace> face_caches;
+HarfBuzzFontProvider::HarfBuzzFace::HarfBuzzFace() : face_(NULL) {}
 
+HarfBuzzFontProvider::HarfBuzzFace::~HarfBuzzFace() {
+  if (face_) {
+    hb_face_destroy(face_);
+  }
+}
+
+void HarfBuzzFontProvider::HarfBuzzFace::Init(SkTypeface* skia_face) {
+  face_ = hb_face_create_for_tables(GetFontTable, skia_face, UnrefSkTypeface);
+  DCHECK(face_);
+}
+
+hb_face_t* HarfBuzzFontProvider::HarfBuzzFace::get() { return face_; }
+
+hb_font_t* HarfBuzzFontProvider::GetHarfBuzzFont(Font* skia_font) {
   // Retrieve the typeface from the cache. In the case where it does not already
   // exist, it will be NULL and we must create it.
-  HarfBuzzFace& face_cache = face_caches[skia_font->GetTypefaceId()];
-  if (face_cache.get() == NULL) {
-    face_cache.Init(skia_font->GetSkTypeface());
+  HarfBuzzFace& face = face_cache_[skia_font->GetTypefaceId()];
+  if (face.get() == NULL) {
+    face.Init(skia_font->GetSkTypeface());
   }
 
-  hb_font_t* harfbuzz_font = hb_font_create(face_cache.get());
+  hb_font_t* harfbuzz_font = hb_font_create(face.get());
   const int scale = SkScalarToFixed(skia_font->size());
   hb_font_set_scale(harfbuzz_font, scale, scale);
   hb_font_set_funcs(harfbuzz_font, g_font_funcs.Get().get(), skia_font, NULL);
@@ -238,6 +228,8 @@
   return harfbuzz_font;
 }
 
+void HarfBuzzFontProvider::PurgeCaches() { face_cache_.clear(); }
+
 }  // namespace skia
 }  // namespace rasterizer
 }  // namespace renderer
diff --git a/src/cobalt/renderer/rasterizer/skia/harfbuzz_font.h b/src/cobalt/renderer/rasterizer/skia/harfbuzz_font.h
index 16b07e4..607c302 100644
--- a/src/cobalt/renderer/rasterizer/skia/harfbuzz_font.h
+++ b/src/cobalt/renderer/rasterizer/skia/harfbuzz_font.h
@@ -15,20 +15,40 @@
 #ifndef COBALT_RENDERER_RASTERIZER_SKIA_HARFBUZZ_FONT_H_
 #define COBALT_RENDERER_RASTERIZER_SKIA_HARFBUZZ_FONT_H_
 
+#include <map>
+
 #include "cobalt/renderer/rasterizer/skia/font.h"
 
 #include "third_party/harfbuzz-ng/src/hb.h"
 
-class SkTypeface;
-
 namespace cobalt {
 namespace renderer {
 namespace rasterizer {
 namespace skia {
 
-class Font;
+class HarfBuzzFontProvider {
+ public:
+  // Returns the HarfBuzz font that corresponds to the given Skia font.
+  hb_font_t* GetHarfBuzzFont(Font* skia_font);
+  void PurgeCaches();
 
-hb_font_t* CreateHarfBuzzFont(Font* skia_font);
+ private:
+  // Wrapper class for a HarfBuzz face created from a given Skia face.
+  class HarfBuzzFace {
+   public:
+    HarfBuzzFace();
+    ~HarfBuzzFace();
+
+    void Init(SkTypeface* skia_face);
+
+    hb_face_t* get();
+
+   private:
+    hb_face_t* face_;
+  };
+
+  std::map<SkFontID, HarfBuzzFace> face_cache_;
+};
 
 }  // namespace skia
 }  // namespace rasterizer
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
index 36d4b6f..d26d31e 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
@@ -63,6 +63,13 @@
 void SkFontMgr_Cobalt::PurgeCaches() {
   SkGraphics::PurgeFontCache();
   local_typeface_stream_manager_.PurgeUnusedMemoryChunks();
+
+  // Lock the family mutex prior to purging each family's unreferenced
+  // typefaces.
+  SkAutoMutexAcquire scoped_mutex(family_mutex_);
+  for (int i = 0; i < families_.count(); ++i) {
+    families_[i]->PurgeUnreferencedTypefaces();
+  }
 }
 
 SkTypeface* SkFontMgr_Cobalt::MatchFaceName(const char face_name[]) {
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc
index 2b5718b..6196cc6 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc
@@ -415,8 +415,8 @@
 
   SkAutoTUnref<SkFileMemoryChunkStream> stream(stream_provider->OpenStream());
   if (GenerateStyleFaceInfo(style_entry, stream)) {
-    LOG(ERROR) << "Scanned font from file: " << style_entry->face_name.c_str()
-               << "(" << style_entry->face_style << ")";
+    LOG(INFO) << "Scanned font from file: " << style_entry->face_name.c_str()
+              << "(" << style_entry->face_style << ")";
     style_entry->typeface.reset(
         SkNEW_ARGS(SkTypeface_CobaltStreamProvider,
                    (stream_provider, style_entry->face_index,
@@ -427,3 +427,14 @@
                << style_entry->font_file_path.c_str();
   }
 }
+
+void SkFontStyleSet_Cobalt::PurgeUnreferencedTypefaces() {
+  // Walk each of the styles looking for any that have a non-NULL typeface.
+  // These are purged if they are unreferenced outside of the style set.
+  for (int i = 0; i < styles_.count(); ++i) {
+    SkAutoTUnref<SkTypeface>& typeface = styles_[i]->typeface;
+    if (typeface.get() != NULL && typeface->getRefCnt() == 1) {
+      typeface.reset(NULL);
+    }
+  }
+}
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h
index 7d6648a..2180d1a 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h
@@ -36,8 +36,7 @@
 // for specific characters during fallback.
 //
 // Both the character map of the style set and the typeface of each individual
-// entry are lazily loaded the first time that they are needed. After this, they
-// are retained in memory.
+// entry are lazily loaded the first time that they are needed.
 class SkFontStyleSet_Cobalt : public SkFontStyleSet {
  public:
   struct SkFontStyleSetEntry_Cobalt : public SkRefCnt {
@@ -118,6 +117,9 @@
       SkFontStyleSetEntry_Cobalt* style,
       SkFileMemoryChunkStreamProvider* stream_provider = NULL);
 
+  // Purge typefaces that are only referenced internally.
+  void PurgeUnreferencedTypefaces();
+
   // NOTE: The following variables can safely be accessed outside of the mutex.
   SkFileMemoryChunkStreamManager* const local_typeface_stream_manager_;
   SkMutex* const manager_owned_mutex_;
diff --git a/src/cobalt/renderer/rasterizer/skia/software_rasterizer.cc b/src/cobalt/renderer/rasterizer/skia/software_rasterizer.cc
index 0f1968a..bcc5e04 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/skia/software_rasterizer.cc
@@ -64,7 +64,8 @@
 
 class SoftwareRasterizer::Impl {
  public:
-  explicit Impl(int surface_cache_size);
+  explicit Impl(int surface_cache_size,
+                bool purge_skia_font_caches_on_destruction);
 
   // Consume the render tree and output the results to the render target passed
   // into the constructor.
@@ -80,8 +81,10 @@
   base::optional<common::SurfaceCache> surface_cache_;
 };
 
-SoftwareRasterizer::Impl::Impl(int surface_cache_size)
-    : resource_provider_(new SoftwareResourceProvider()) {
+SoftwareRasterizer::Impl::Impl(int surface_cache_size,
+                               bool purge_skia_font_caches_on_destruction)
+    : resource_provider_(
+          new SoftwareResourceProvider(purge_skia_font_caches_on_destruction)) {
   TRACE_EVENT0("cobalt::renderer", "SoftwareRasterizer::SoftwareRasterizer()");
 
   if (surface_cache_size > 0) {
@@ -135,8 +138,9 @@
   return resource_provider_.get();
 }
 
-SoftwareRasterizer::SoftwareRasterizer(int surface_cache_size)
-    : impl_(new Impl(surface_cache_size)) {}
+SoftwareRasterizer::SoftwareRasterizer(int surface_cache_size,
+                                       bool purge_caches_on_destruction)
+    : impl_(new Impl(surface_cache_size, purge_caches_on_destruction)) {}
 
 SoftwareRasterizer::~SoftwareRasterizer() {}
 
diff --git a/src/cobalt/renderer/rasterizer/skia/software_rasterizer.h b/src/cobalt/renderer/rasterizer/skia/software_rasterizer.h
index c0c2a7a..f935de4 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/skia/software_rasterizer.h
@@ -35,7 +35,8 @@
 // class can send the results to a display or render target.
 class SoftwareRasterizer {
  public:
-  explicit SoftwareRasterizer(int surface_cache_size);
+  explicit SoftwareRasterizer(int surface_cache_size,
+                              bool purge_skia_font_caches_on_destruction);
   ~SoftwareRasterizer();
 
   // Consume the render tree and output the results to the render target passed
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
index 32d795e..30a4cd8 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
@@ -37,12 +37,26 @@
 namespace rasterizer {
 namespace skia {
 
-SoftwareResourceProvider::SoftwareResourceProvider() {
+SoftwareResourceProvider::SoftwareResourceProvider(
+    bool purge_skia_font_caches_on_destruction)
+    : purge_skia_font_caches_on_destruction_(
+          purge_skia_font_caches_on_destruction) {
   // Initialize the font manager now to ensure that it doesn't get initialized
   // on multiple threads simultaneously later.
   SkSafeUnref(SkFontMgr::RefDefault());
 }
 
+SoftwareResourceProvider::~SoftwareResourceProvider() {
+  if (purge_skia_font_caches_on_destruction_) {
+    text_shaper_.PurgeCaches();
+
+    SkAutoTUnref<SkFontMgr> font_manager(SkFontMgr::RefDefault());
+    SkFontMgr_Cobalt* cobalt_font_manager =
+        base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager.get());
+    cobalt_font_manager->PurgeCaches();
+  }
+}
+
 bool SoftwareResourceProvider::PixelFormatSupported(
     render_tree::PixelFormat pixel_format) {
   return RenderTreeSurfaceFormatToSkia(pixel_format) == kN32_SkColorType;
@@ -233,13 +247,6 @@
   return scoped_refptr<render_tree::Image>(NULL);
 }
 
-void SoftwareResourceProvider::PurgeCaches() {
-  SkAutoTUnref<SkFontMgr> font_manager(SkFontMgr::RefDefault());
-  SkFontMgr_Cobalt* cobalt_font_manager =
-      base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager.get());
-  cobalt_font_manager->PurgeCaches();
-}
-
 }  // namespace skia
 }  // namespace rasterizer
 }  // namespace renderer
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
index 1f0d1f4..67e8e2d 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
+++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
@@ -31,7 +31,8 @@
 // are to be consumed by this skia software rasterizer.
 class SoftwareResourceProvider : public render_tree::ResourceProvider {
  public:
-  SoftwareResourceProvider();
+  explicit SoftwareResourceProvider(bool purge_skia_font_caches_on_destruction);
+  ~SoftwareResourceProvider() OVERRIDE;
 
   void Finish() OVERRIDE{};
 
@@ -121,9 +122,9 @@
   scoped_refptr<render_tree::Image> DrawOffscreenImage(
       const scoped_refptr<render_tree::Node>& root) OVERRIDE;
 
-  void PurgeCaches() OVERRIDE;
-
  private:
+  const bool purge_skia_font_caches_on_destruction_;
+
   TextShaper text_shaper_;
 };
 
diff --git a/src/cobalt/renderer/rasterizer/skia/text_shaper.cc b/src/cobalt/renderer/rasterizer/skia/text_shaper.cc
index 5d8ee0f..e307c8e 100644
--- a/src/cobalt/renderer/rasterizer/skia/text_shaper.cc
+++ b/src/cobalt/renderer/rasterizer/skia/text_shaper.cc
@@ -119,6 +119,11 @@
                    NULL, NULL, maybe_used_fonts);
 }
 
+void TextShaper::PurgeCaches() {
+  base::AutoLock lock(shaping_mutex_);
+  harfbuzz_font_provider_.PurgeCaches();
+}
+
 float TextShaper::ShapeText(const char16* text_buffer, size_t text_length,
                             const std::string& language, bool is_rtl,
                             render_tree::FontProvider* font_provider,
@@ -285,7 +290,8 @@
                                  float* total_width) {
   TryAddFontToUsedFonts(script_run.font, maybe_used_fonts);
 
-  hb_font_t* harfbuzz_font = CreateHarfBuzzFont(script_run.font);
+  hb_font_t* harfbuzz_font =
+      harfbuzz_font_provider_.GetHarfBuzzFont(script_run.font);
 
   // Ensure that the local text buffer is large enough to hold the normalized
   // string.
diff --git a/src/cobalt/renderer/rasterizer/skia/text_shaper.h b/src/cobalt/renderer/rasterizer/skia/text_shaper.h
index 982e1d3..e111ce6 100644
--- a/src/cobalt/renderer/rasterizer/skia/text_shaper.h
+++ b/src/cobalt/renderer/rasterizer/skia/text_shaper.h
@@ -25,6 +25,7 @@
 #include "cobalt/render_tree/font_provider.h"
 #include "cobalt/renderer/rasterizer/skia/font.h"
 #include "cobalt/renderer/rasterizer/skia/glyph_buffer.h"
+#include "cobalt/renderer/rasterizer/skia/harfbuzz_font.h"
 
 #include "third_party/harfbuzz-ng/src/hb.h"
 #include "third_party/harfbuzz-ng/src/hb-icu.h"
@@ -90,6 +91,10 @@
                      render_tree::FontProvider* font_provider,
                      render_tree::FontVector* maybe_used_fonts);
 
+  // Purges any caches being used by the text shaper; currently, this consists
+  // of the HarfBuzzFontProvider's cache.
+  void PurgeCaches();
+
  private:
   // Internal class used for tracking the vertical bounds of a text buffer
   // during shaping when bounds are requested (i.e. the passed in |maybe_bounds|
@@ -155,8 +160,8 @@
                                    render_tree::FontVector* maybe_used_fonts,
                                    float* current_width);
 
-  // Shape a simple text run, relying on the skia::Font objects provided by
-  // the FontProvider to determine the shaping data.
+  // Shape a simple text run, relying on the skia::Font objects provided by the
+  // FontProvider to determine the shaping data.
   void ShapeSimpleRun(const char16* text_buffer, size_t text_length,
                       render_tree::FontProvider* font_provider,
                       SkTextBlobBuilder* maybe_builder,
@@ -181,6 +186,9 @@
   // the same time.
   base::Lock shaping_mutex_;
 
+  // Provides fonts needed by HarfBuzz during complex shaping.
+  HarfBuzzFontProvider harfbuzz_font_provider_;
+
   // The allocated glyph and positions data. This is retained in between shaping
   // calls to prevent constantly needing to allocate the arrays. In the case
   // where a larger array is needed than the current size, larger arrays are
diff --git a/src/cobalt/renderer/render_tree_pixel_tester.cc b/src/cobalt/renderer/render_tree_pixel_tester.cc
index eb92656..a428a17 100644
--- a/src/cobalt/renderer/render_tree_pixel_tester.cc
+++ b/src/cobalt/renderer/render_tree_pixel_tester.cc
@@ -69,6 +69,11 @@
 
   // Create the rasterizer using the platform default RenderModule options.
   RendererModule::Options render_module_options;
+
+  // Don't purge the Skia font caches on destruction. Doing so will result in
+  // too much font thrashing during the tests.
+  render_module_options.purge_skia_font_caches_on_destruction = false;
+
   rasterizer_ = render_module_options.create_rasterizer_function.Run(
       graphics_context_.get(), render_module_options);
 }
diff --git a/src/cobalt/renderer/renderer_module.cc b/src/cobalt/renderer/renderer_module.cc
index 28cbe93..084390e 100644
--- a/src/cobalt/renderer/renderer_module.cc
+++ b/src/cobalt/renderer/renderer_module.cc
@@ -24,7 +24,8 @@
 namespace renderer {
 
 RendererModule::Options::Options()
-    : skia_glyph_texture_atlas_dimensions(2048, 2048) {
+    : skia_glyph_texture_atlas_dimensions(2048, 2048),
+      purge_skia_font_caches_on_destruction(true) {
   // Call into platform-specific code for setting up render module options.
   SetPerPlatformDefaultOptions();
 }
diff --git a/src/cobalt/renderer/renderer_module.h b/src/cobalt/renderer/renderer_module.h
index 0e92c82..70d0364 100644
--- a/src/cobalt/renderer/renderer_module.h
+++ b/src/cobalt/renderer/renderer_module.h
@@ -77,6 +77,12 @@
     // buffer will not be frequently swapped.
     bool submit_even_if_render_tree_is_unchanged;
 
+    // If this flag is set to true, which is the default value, then all of
+    // Skia's font caches are purged during destruction. These caches have
+    // lifespans that are uncoupled from the resource provider's, and will not
+    // be purged on destruction when this is set to false.
+    bool purge_skia_font_caches_on_destruction;
+
     // On modes with a 3D camera controllable by user input, fetch the affine
     // transforms needed to render the scene from the camera's view.
     GetCameraTransformCallback get_camera_transform;
diff --git a/src/cobalt/renderer/renderer_module_default_options_starboard.cc b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
index fc3f3e0..0251fee 100644
--- a/src/cobalt/renderer/renderer_module_default_options_starboard.cc
+++ b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
@@ -38,7 +38,8 @@
 #if COBALT_FORCE_SOFTWARE_RASTERIZER
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::egl::SoftwareRasterizer(
-          graphics_context, options.surface_cache_size_in_bytes));
+          graphics_context, options.surface_cache_size_in_bytes,
+          options.purge_skia_font_caches_on_destruction));
 #elif defined(COBALT_FORCE_DIRECT_GLES_RASTERIZER)
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::egl::HardwareRasterizer(
@@ -46,7 +47,8 @@
           options.skia_glyph_texture_atlas_dimensions.height(),
           options.skia_cache_size_in_bytes,
           options.scratch_surface_cache_size_in_bytes,
-          options.surface_cache_size_in_bytes));
+          options.surface_cache_size_in_bytes,
+          options.purge_skia_font_caches_on_destruction));
 #else
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::skia::HardwareRasterizer(
@@ -54,13 +56,15 @@
           options.skia_glyph_texture_atlas_dimensions.height(),
           options.skia_cache_size_in_bytes,
           options.scratch_surface_cache_size_in_bytes,
-          options.surface_cache_size_in_bytes));
+          options.surface_cache_size_in_bytes,
+          options.purge_skia_font_caches_on_destruction));
 #endif  // COBALT_FORCE_SOFTWARE_RASTERIZER
 #elif SB_HAS(BLITTER)
 #if COBALT_FORCE_SOFTWARE_RASTERIZER
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::blitter::SoftwareRasterizer(
-          graphics_context, options.surface_cache_size_in_bytes));
+          graphics_context, options.surface_cache_size_in_bytes,
+          options.purge_skia_font_caches_on_destruction));
 #else
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::blitter::HardwareRasterizer(
@@ -68,7 +72,8 @@
           options.skia_glyph_texture_atlas_dimensions.height(),
           options.scratch_surface_cache_size_in_bytes,
           options.surface_cache_size_in_bytes,
-          options.software_surface_cache_size_in_bytes));
+          options.software_surface_cache_size_in_bytes,
+          options.purge_skia_font_caches_on_destruction));
 #endif  // COBALT_FORCE_SOFTWARE_RASTERIZER
 #else
 #error "Either GLES2 or the Starboard Blitter API must be available."
diff --git a/src/cobalt/renderer/renderer_module_default_options_win.cc b/src/cobalt/renderer/renderer_module_default_options_win.cc
index 5809d2c..163fe2b 100644
--- a/src/cobalt/renderer/renderer_module_default_options_win.cc
+++ b/src/cobalt/renderer/renderer_module_default_options_win.cc
@@ -27,13 +27,15 @@
 #if COBALT_FORCE_SOFTWARE_RASTERIZER
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::egl::SoftwareRasterizer(
-          graphics_context, options.surface_cache_size_in_bytes));
+          graphics_context, options.surface_cache_size_in_bytes,
+          options.purge_skia_font_caches_on_destruction));
 #else
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::skia::HardwareRasterizer(
           graphics_context, options.skia_cache_size_in_bytes,
           options.scratch_surface_cache_size_in_bytes,
-          options.surface_cache_size_in_bytes));
+          options.surface_cache_size_in_bytes,
+          options.purge_skia_font_caches_on_destruction));
 #endif  // #if COBALT_FORCE_SOFTWARE_RASTERIZER
 }
 }  // namespace
diff --git a/src/cobalt/script/mozjs-45/conversion_helpers.h b/src/cobalt/script/mozjs-45/conversion_helpers.h
index 95a752e..c8e4c93 100644
--- a/src/cobalt/script/mozjs-45/conversion_helpers.h
+++ b/src/cobalt/script/mozjs-45/conversion_helpers.h
@@ -154,19 +154,19 @@
 // https://heycam.github.io/webidl/#abstract-opdef-converttoint
 template <>
 inline const double UpperBound<int64_t>() {
-  const double kInt64UpperBound = static_cast<double>((1ull << 53) - 1);
+  const double kInt64UpperBound = static_cast<double>((1ll << 53) - 1);
   return kInt64UpperBound;
 }
 
 template <>
 inline const double LowerBound<int64_t>() {
-  const double kInt64LowerBound = static_cast<double>(-(1ull << 53) + 1);
+  const double kInt64LowerBound = static_cast<double>(-(1ll << 53) + 1);
   return kInt64LowerBound;
 }
 
 template <>
 inline const double UpperBound<uint64_t>() {
-  const double kUInt64UpperBound = static_cast<double>((1ull << 53) - 1);
+  const double kUInt64UpperBound = static_cast<double>((1ll << 53) - 1);
   return kUInt64UpperBound;
 }
 
diff --git a/src/cobalt/script/mozjs-45/mozjs-45.gyp b/src/cobalt/script/mozjs-45/mozjs-45.gyp
index d0f416c..6959bcd 100644
--- a/src/cobalt/script/mozjs-45/mozjs-45.gyp
+++ b/src/cobalt/script/mozjs-45/mozjs-45.gyp
@@ -80,8 +80,7 @@
 
     {
       # This target takes specified files and embeds them as header files for
-      # inclusion into the binary. The script currently requires all resources
-      # to be embedded to live in the same directory.
+      # inclusion into the binary.
       'target_name': 'embed_mozjs_resources_as_header_files',
       'type': 'none',
       # Because we generate a header, we must set the hard_dependency flag.
@@ -92,6 +91,9 @@
       },
       'sources': [
         '<(DEPTH)/third_party/promise-polyfill/promise.min.js',
+        '<(DEPTH)/cobalt/streams/embedded_scripts/byte_length_queuing_strategy.js',
+        '<(DEPTH)/cobalt/streams/embedded_scripts/count_queuing_strategy.js',
+        '<(DEPTH)/cobalt/streams/embedded_scripts/readable_stream.js',
       ],
       'actions': [
         {
diff --git a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
index 2f5af46..2bd7c41 100644
--- a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
@@ -269,6 +269,19 @@
   return success;
 }
 
+void MozjsGlobalEnvironment::EvaluateEmbeddedScript(
+    const unsigned char* data, size_t size, const char* filename) {
+  TRACK_MEMORY_SCOPE("Javascript");
+  std::string source(reinterpret_cast<const char*>(data), size);
+  scoped_refptr<SourceCode> source_code =
+      new MozjsSourceCode(source, base::SourceLocation(filename, 1, 1));
+  std::string result;
+  bool success = EvaluateScript(source_code, &result);
+  if (!success) {
+    DLOG(FATAL) << result;
+  }
+}
+
 std::vector<StackFrame> MozjsGlobalEnvironment::GetStackTrace(int max_frames) {
   DCHECK(thread_checker_.CalledOnValidThread());
   return util::GetStackTrace(context_, max_frames);
@@ -351,17 +364,22 @@
 }
 
 void MozjsGlobalEnvironment::EvaluateAutomatics() {
-  TRACK_MEMORY_SCOPE("Javascript");
-  std::string source(
-      reinterpret_cast<const char*>(MozjsEmbeddedResources::promise_min_js),
-      sizeof(MozjsEmbeddedResources::promise_min_js));
-  scoped_refptr<SourceCode> source_code =
-      new MozjsSourceCode(source, base::SourceLocation("promise.min.js", 1, 1));
-  std::string result;
-  bool success = EvaluateScript(source_code, &result);
-  if (!success) {
-    DLOG(FATAL) << result;
-  }
+  EvaluateEmbeddedScript(
+      MozjsEmbeddedResources::promise_min_js,
+      sizeof(MozjsEmbeddedResources::promise_min_js),
+      "promise.min.js");
+  EvaluateEmbeddedScript(
+      MozjsEmbeddedResources::byte_length_queuing_strategy_js,
+      sizeof(MozjsEmbeddedResources::byte_length_queuing_strategy_js),
+      "byte_length_queuing_strategy.js");
+  EvaluateEmbeddedScript(
+      MozjsEmbeddedResources::count_queuing_strategy_js,
+      sizeof(MozjsEmbeddedResources::count_queuing_strategy_js),
+      "count_queuing_strategy.js");
+  EvaluateEmbeddedScript(
+      MozjsEmbeddedResources::readable_stream_js,
+      sizeof(MozjsEmbeddedResources::readable_stream_js),
+      "readable_stream.js");
 }
 
 InterfaceData* MozjsGlobalEnvironment::GetInterfaceData(intptr_t key) {
diff --git a/src/cobalt/script/mozjs-45/mozjs_global_environment.h b/src/cobalt/script/mozjs-45/mozjs_global_environment.h
index c6cfb2a..0a5a573 100644
--- a/src/cobalt/script/mozjs-45/mozjs_global_environment.h
+++ b/src/cobalt/script/mozjs-45/mozjs_global_environment.h
@@ -149,6 +149,9 @@
   bool EvaluateScriptInternal(const scoped_refptr<SourceCode>& source_code,
                               JS::MutableHandleValue out_result);
 
+  void EvaluateEmbeddedScript(const unsigned char* data, size_t size,
+                              const char* filename);
+
   static void TraceFunction(JSTracer* trace, void* data);
 
   // Helper struct to ensure the context is destroyed in the correct order
diff --git a/src/cobalt/script/mozjs-45/native_promise.h b/src/cobalt/script/mozjs-45/native_promise.h
index 1dfccb5..cc4be5d 100644
--- a/src/cobalt/script/mozjs-45/native_promise.h
+++ b/src/cobalt/script/mozjs-45/native_promise.h
@@ -169,6 +169,16 @@
   out_value.setObjectOrNull(native_promise->promise());
 }
 
+// Destroys |promise_holder| as soon as the conversion is done.
+// This is useful when a wrappable is not interested in retaining a reference
+// to a promise, typically when a promise is resolved or rejected synchronously.
+template <typename T>
+inline void ToJSValue(JSContext* context,
+                      scoped_ptr<ScriptValue<Promise<T> > > promise_holder,
+                      JS::MutableHandleValue out_value) {
+  ToJSValue(context, promise_holder.get(), out_value);
+}
+
 }  // namespace mozjs
 }  // namespace script
 }  // namespace cobalt
diff --git a/src/cobalt/script/mozjs/conversion_helpers.h b/src/cobalt/script/mozjs/conversion_helpers.h
index 88a13b8..0aa9192 100644
--- a/src/cobalt/script/mozjs/conversion_helpers.h
+++ b/src/cobalt/script/mozjs/conversion_helpers.h
@@ -152,19 +152,19 @@
 // https://heycam.github.io/webidl/#abstract-opdef-converttoint
 template <>
 inline const double UpperBound<int64_t>() {
-  const double kInt64UpperBound = static_cast<double>((1ull << 53) - 1);
+  const double kInt64UpperBound = static_cast<double>((1ll << 53) - 1);
   return kInt64UpperBound;
 }
 
 template <>
 inline const double LowerBound<int64_t>() {
-  const double kInt64LowerBound = static_cast<double>(-(1ull << 53) + 1);
+  const double kInt64LowerBound = static_cast<double>(-(1ll << 53) + 1);
   return kInt64LowerBound;
 }
 
 template <>
 inline const double UpperBound<uint64_t>() {
-  const double kUInt64UpperBound = static_cast<double>((1ull << 53) - 1);
+  const double kUInt64UpperBound = static_cast<double>((1ll << 53) - 1);
   return kUInt64UpperBound;
 }
 
diff --git a/src/cobalt/script/mozjs/native_promise.h b/src/cobalt/script/mozjs/native_promise.h
index e291197..f184076 100644
--- a/src/cobalt/script/mozjs/native_promise.h
+++ b/src/cobalt/script/mozjs/native_promise.h
@@ -169,6 +169,16 @@
   out_value.setObjectOrNull(native_promise->promise());
 }
 
+// Destroys |promise_holder| as soon as the conversion is done.
+// This is useful when a wrappable is not interested in retaining a reference
+// to a promise, typically when a promise is resolved or rejected synchronously.
+template <typename T>
+inline void ToJSValue(JSContext* context,
+                      scoped_ptr<ScriptValue<Promise<T> > > promise_holder,
+                      JS::MutableHandleValue out_value) {
+  ToJSValue(context, promise_holder.get(), out_value);
+}
+
 }  // namespace mozjs
 }  // namespace script
 }  // namespace cobalt
diff --git a/src/cobalt/script/script_value.h b/src/cobalt/script/script_value.h
index 0553bd1..7b9edac 100644
--- a/src/cobalt/script/script_value.h
+++ b/src/cobalt/script/script_value.h
@@ -54,6 +54,12 @@
   // constructor.
   class Reference {
    public:
+    Reference(Wrappable* wrappable, scoped_ptr<ScriptValue> script_value)
+        : owner_(wrappable), referenced_value_(script_value.Pass()) {
+      DCHECK(referenced_value_);
+      referenced_value_->RegisterOwner(owner_);
+    }
+
     Reference(Wrappable* wrappable, const ScriptValue& script_value)
         : owner_(wrappable), referenced_value_(script_value.MakeCopy()) {
       DCHECK(referenced_value_);
@@ -85,6 +91,12 @@
   // doesn't need to be retained past the scope of the function.
   class StrongReference {
    public:
+    explicit StrongReference(scoped_ptr<ScriptValue> script_value)
+        : referenced_value_(script_value.Pass()) {
+      DCHECK(referenced_value_);
+      referenced_value_->PreventGarbageCollection();
+    }
+
     explicit StrongReference(const ScriptValue& script_value)
         : referenced_value_(script_value.MakeCopy()) {
       DCHECK(referenced_value_);
diff --git a/src/cobalt/streams/byte_length_queuing_strategy.js b/src/cobalt/streams/byte_length_queuing_strategy.js
new file mode 100644
index 0000000..dd1a0a1
--- /dev/null
+++ b/src/cobalt/streams/byte_length_queuing_strategy.js
@@ -0,0 +1,34 @@
+// ==ClosureCompiler==
+// @output_file_name byte_length_queuing_strategy.js
+// @compilation_level SIMPLE_OPTIMIZATIONS
+// @language_out ES5_STRICT
+// ==/ClosureCompiler==
+
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function(global) {
+  'use strict';
+
+  const defineProperty = global.Object.defineProperty;
+
+  class ByteLengthQueuingStrategy {
+    constructor(options) {
+      defineProperty(this, 'highWaterMark', {
+        value: options.highWaterMark,
+        enumerable: true,
+        configurable: true,
+        writable: true
+      });
+    }
+    size(chunk) { return chunk.byteLength; }
+  }
+
+  defineProperty(global, 'ByteLengthQueuingStrategy', {
+    value: ByteLengthQueuingStrategy,
+    enumerable: false,
+    configurable: true,
+    writable: true
+  });
+})(this);
diff --git a/src/cobalt/streams/count_queuing_strategy.js b/src/cobalt/streams/count_queuing_strategy.js
new file mode 100644
index 0000000..5fc5715
--- /dev/null
+++ b/src/cobalt/streams/count_queuing_strategy.js
@@ -0,0 +1,35 @@
+// ==ClosureCompiler==
+// @output_file_name count_queuing_strategy.js
+// @compilation_level SIMPLE_OPTIMIZATIONS
+// @language_out ES5_STRICT
+// ==/ClosureCompiler==
+
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function(global) {
+  'use strict';
+
+  const defineProperty = global.Object.defineProperty;
+
+  class CountQueuingStrategy {
+    constructor(options) {
+      defineProperty(this, 'highWaterMark', {
+        value: options.highWaterMark,
+        enumerable: true,
+        configurable: true,
+        writable: true
+      });
+    }
+
+    size(chunk) { return 1; }
+  }
+
+  defineProperty(global, 'CountQueuingStrategy', {
+    value: CountQueuingStrategy,
+    enumerable: false,
+    configurable: true,
+    writable: true
+  });
+})(this);
diff --git a/src/cobalt/streams/embedded_scripts/byte_length_queuing_strategy.js b/src/cobalt/streams/embedded_scripts/byte_length_queuing_strategy.js
new file mode 100644
index 0000000..7a537ac
--- /dev/null
+++ b/src/cobalt/streams/embedded_scripts/byte_length_queuing_strategy.js
@@ -0,0 +1 @@
+'use strict';(function(b){var c=b.Object.defineProperty,d=function(a){c(this,"highWaterMark",{value:a.highWaterMark,enumerable:!0,configurable:!0,writable:!0})};d.prototype.size=function(a){return a.byteLength};c(b,"ByteLengthQueuingStrategy",{value:d,enumerable:!1,configurable:!0,writable:!0})})(this);
\ No newline at end of file
diff --git a/src/cobalt/streams/embedded_scripts/count_queuing_strategy.js b/src/cobalt/streams/embedded_scripts/count_queuing_strategy.js
new file mode 100644
index 0000000..288aed3
--- /dev/null
+++ b/src/cobalt/streams/embedded_scripts/count_queuing_strategy.js
@@ -0,0 +1 @@
+'use strict';(function(a){var b=a.Object.defineProperty,c=function(a){b(this,"highWaterMark",{value:a.highWaterMark,enumerable:!0,configurable:!0,writable:!0})};c.prototype.size=function(a){return 1};b(a,"CountQueuingStrategy",{value:c,enumerable:!1,configurable:!0,writable:!0})})(this);
\ No newline at end of file
diff --git a/src/cobalt/streams/embedded_scripts/readable_stream.js b/src/cobalt/streams/embedded_scripts/readable_stream.js
new file mode 100644
index 0000000..3017cdd
--- /dev/null
+++ b/src/cobalt/streams/embedded_scripts/readable_stream.js
@@ -0,0 +1,47 @@
+'use strict';(function(global){const v8_InternalPackedArray=global.Array;function v8_createPrivateSymbol(x){return Symbol(x)}function v8_simpleBind(fn,obj){return fn.bind(obj)}const arraySlice=global.Array.prototype.slice;function v8_uncurryThis(fn){return function(obj){return fn.apply(obj,arraySlice.call(arguments,1))}}const v8_PromiseBase=global.Promise;const _promiseResolve=v8_createPrivateSymbol("[[Resolve]]");const _promiseReject=v8_createPrivateSymbol("[[Reject]]");function v8_Promise(){var that=
+this;v8_PromiseBase.call(this,function(resolve,reject){that[_promiseResolve]=resolve;that[_promiseReject]=reject})}v8_Promise.prototype=v8_PromiseBase.prototype;function v8_createPromise(){return new v8_Promise}function v8_isPromise(obj){return obj instanceof v8_Promise}function v8_resolvePromise(promise,value){promise[_promiseResolve](value)}function v8_rejectPromise(promise,reason){promise[_promiseReject](reason)}function v8_markPromiseAsHandled(promise){try{thenPromise(promise,undefined,()=>{})}catch(error){}}
+const QUEUE_MAX_ARRAY_SIZE=16384;class SimpleQueue{constructor(){this.front={elements:new v8_InternalPackedArray,next:undefined};this.back=this.front;this.cursor=0;this.size=0}get length(){return this.size}push(element){++this.size;if(this.back.elements.length===QUEUE_MAX_ARRAY_SIZE){const oldBack=this.back;this.back={elements:new v8_InternalPackedArray,next:undefined};oldBack.next=this.back}this.back.elements.push(element)}shift(){--this.size;if(this.front.elements.length===this.cursor){this.front=
+this.front.next;this.cursor=0}const element=this.front.elements[this.cursor];this.front.elements[this.cursor]=undefined;++this.cursor;return element}forEach(callback){let i=this.cursor;let node=this.front;let elements=node.elements;while(i!==elements.length||node.next!==undefined){if(i===elements.length){node=node.next;elements=node.elements;i=0}callback(elements[i]);++i}}peek(){if(this.front.elements.length===this.cursor)return this.front.next.elements[0];return this.front.elements[this.cursor]}}
+const streamErrors_illegalInvocation="Illegal invocation";const streamErrors_illegalConstructor="Illegal constructor";const streamErrors_invalidType="Invalid type is specified";const streamErrors_invalidSize="The return value of a queuing strategy's size function must be a finite, non-NaN, non-negative number";const streamErrors_sizeNotAFunction="A queuing strategy's size property must be a function";const streamErrors_invalidHWM="A queueing strategy's highWaterMark property must be a nonnegative, non-NaN number";
+const _reader=v8_createPrivateSymbol("[[reader]]");const _storedError=v8_createPrivateSymbol("[[storedError]]");const _controller=v8_createPrivateSymbol("[[controller]]");const _closedPromise=v8_createPrivateSymbol("[[closedPromise]]");const _ownerReadableStream=v8_createPrivateSymbol("[[ownerReadableStream]]");const _readRequests=v8_createPrivateSymbol("[[readRequests]]");const createWithExternalControllerSentinel=v8_createPrivateSymbol("flag for UA-created ReadableStream to pass");const _readableStreamBits=
+v8_createPrivateSymbol("bit field for [[state]] and [[disturbed]]");const DISTURBED=1;const STATE_MASK=6;const STATE_BITS_OFFSET=1;const STATE_READABLE=0;const STATE_CLOSED=1;const STATE_ERRORED=2;const _underlyingSource=v8_createPrivateSymbol("[[underlyingSource]]");const _controlledReadableStream=v8_createPrivateSymbol("[[controlledReadableStream]]");const _queue=v8_createPrivateSymbol("[[queue]]");const _totalQueuedSize=v8_createPrivateSymbol("[[totalQueuedSize]]");const _strategySize=v8_createPrivateSymbol("[[strategySize]]");
+const _strategyHWM=v8_createPrivateSymbol("[[strategyHWM]]");const _readableStreamDefaultControllerBits=v8_createPrivateSymbol("bit field for [[started]], [[closeRequested]], [[pulling]], [[pullAgain]]");const STARTED=1;const CLOSE_REQUESTED=2;const PULLING=4;const PULL_AGAIN=8;const EXTERNALLY_CONTROLLED=16;const undefined=global.undefined;const Infinity=global.Infinity;const defineProperty=global.Object.defineProperty;const hasOwnProperty=v8_uncurryThis(global.Object.hasOwnProperty);const callFunction=
+v8_uncurryThis(global.Function.prototype.call);const applyFunction=v8_uncurryThis(global.Function.prototype.apply);const TypeError=global.TypeError;const RangeError=global.RangeError;const Number=global.Number;const Number_isNaN=Number.isNaN;const Number_isFinite=Number.isFinite;const Promise=global.Promise;const thenPromise=v8_uncurryThis(Promise.prototype.then);const Promise_resolve=v8_simpleBind(Promise.resolve,Promise);const Promise_reject=v8_simpleBind(Promise.reject,Promise);const errCancelLockedStream=
+"Cannot cancel a readable stream that is locked to a reader";const errEnqueueCloseRequestedStream="Cannot enqueue a chunk into a readable stream that is closed or has been requested to be closed";const errCancelReleasedReader="This readable stream reader has been released and cannot be used to cancel its previous owner stream";const errReadReleasedReader="This readable stream reader has been released and cannot be used to read from its previous owner stream";const errCloseCloseRequestedStream="Cannot close a readable stream that has already been requested to be closed";
+const errEnqueueClosedStream="Cannot enqueue a chunk into a closed readable stream";const errEnqueueErroredStream="Cannot enqueue a chunk into an errored readable stream";const errCloseClosedStream="Cannot close a closed readable stream";const errCloseErroredStream="Cannot close an errored readable stream";const errErrorClosedStream="Cannot error a close readable stream";const errErrorErroredStream="Cannot error a readable stream that is already errored";const errGetReaderNotByteStream="This readable stream does not support BYOB readers";
+const errGetReaderBadMode='Invalid reader mode given: expected undefined or "byob"';const errReaderConstructorBadArgument="ReadableStreamReader constructor argument is not a readable stream";const errReaderConstructorStreamAlreadyLocked="ReadableStreamReader constructor can only accept readable streams that are not yet locked to a reader";const errReleaseReaderWithPendingRead="Cannot release a readable stream reader when it still has outstanding read() calls that have not yet settled";const errReleasedReaderClosedPromise=
+"This readable stream reader has been released and cannot be used to monitor the stream's state";const errTmplMustBeFunctionOrUndefined=(name)=>`${name} must be a function or undefined`;class ReadableStream{constructor(){const underlyingSource=arguments[0]===undefined?{}:arguments[0];const strategy=arguments[1]===undefined?{}:arguments[1];const size=strategy.size;let highWaterMark=strategy.highWaterMark;if(highWaterMark===undefined)highWaterMark=1;this[_readableStreamBits]=0;ReadableStreamSetState(this,
+STATE_READABLE);this[_reader]=undefined;this[_storedError]=undefined;this[_controller]=undefined;const type=underlyingSource.type;const typeString=String(type);if(typeString==="bytes")throw new RangeError("bytes type is not yet implemented");else if(type!==undefined)throw new RangeError(streamErrors_invalidType);this[_controller]=new ReadableStreamDefaultController(this,underlyingSource,size,highWaterMark,arguments[2])}get locked(){if(IsReadableStream(this)===false)throw new TypeError(streamErrors_illegalInvocation);
+return IsReadableStreamLocked(this)}cancel(reason){if(IsReadableStream(this)===false)return Promise_reject(new TypeError(streamErrors_illegalInvocation));if(IsReadableStreamLocked(this)===true)return Promise_reject(new TypeError(errCancelLockedStream));return ReadableStreamCancel(this,reason)}getReader({mode}={}){if(IsReadableStream(this)===false)throw new TypeError(streamErrors_illegalInvocation);if(mode==="byob")throw new TypeError(errGetReaderNotByteStream);if(mode===undefined)return AcquireReadableStreamDefaultReader(this);
+throw new RangeError(errGetReaderBadMode);}pipeThrough({writable,readable},options){throw new TypeError("pipeThrough not implemented");}pipeTo(dest,{preventClose,preventAbort,preventCancel}={}){throw new TypeError("pipeTo not implemented");}tee(){if(IsReadableStream(this)===false)throw new TypeError(streamErrors_illegalInvocation);return ReadableStreamTee(this)}}class ReadableStreamDefaultController{constructor(stream,underlyingSource,size,highWaterMark){if(IsReadableStream(stream)===false)throw new TypeError(streamErrors_illegalConstructor);
+if(stream[_controller]!==undefined)throw new TypeError(streamErrors_illegalConstructor);this[_controlledReadableStream]=stream;this[_underlyingSource]=underlyingSource;this[_queue]=new SimpleQueue;this[_totalQueuedSize]=0;this[_readableStreamDefaultControllerBits]=0;if(arguments[4]===createWithExternalControllerSentinel)this[_readableStreamDefaultControllerBits]|=EXTERNALLY_CONTROLLED;const normalizedStrategy=ValidateAndNormalizeQueuingStrategy(size,highWaterMark);this[_strategySize]=normalizedStrategy.size;
+this[_strategyHWM]=normalizedStrategy.highWaterMark;const controller=this;const startResult=CallOrNoop(underlyingSource,"start",this,"underlyingSource.start");thenPromise(Promise_resolve(startResult),()=>{controller[_readableStreamDefaultControllerBits]|=STARTED;ReadableStreamDefaultControllerCallPullIfNeeded(controller)},(r)=>{if(ReadableStreamGetState(stream)===STATE_READABLE)ReadableStreamDefaultControllerError(controller,r)})}get desiredSize(){if(IsReadableStreamDefaultController(this)===false)throw new TypeError(streamErrors_illegalInvocation);
+return ReadableStreamDefaultControllerGetDesiredSize(this)}close(){if(IsReadableStreamDefaultController(this)===false)throw new TypeError(streamErrors_illegalInvocation);const stream=this[_controlledReadableStream];if(this[_readableStreamDefaultControllerBits]&CLOSE_REQUESTED)throw new TypeError(errCloseCloseRequestedStream);const state=ReadableStreamGetState(stream);if(state===STATE_ERRORED)throw new TypeError(errCloseErroredStream);if(state===STATE_CLOSED)throw new TypeError(errCloseClosedStream);
+return ReadableStreamDefaultControllerClose(this)}enqueue(chunk){if(IsReadableStreamDefaultController(this)===false)throw new TypeError(streamErrors_illegalInvocation);const stream=this[_controlledReadableStream];if(this[_readableStreamDefaultControllerBits]&CLOSE_REQUESTED)throw new TypeError(errEnqueueCloseRequestedStream);const state=ReadableStreamGetState(stream);if(state===STATE_ERRORED)throw new TypeError(errEnqueueErroredStream);if(state===STATE_CLOSED)throw new TypeError(errEnqueueClosedStream);
+return ReadableStreamDefaultControllerEnqueue(this,chunk)}error(e){if(IsReadableStreamDefaultController(this)===false)throw new TypeError(streamErrors_illegalInvocation);const stream=this[_controlledReadableStream];const state=ReadableStreamGetState(stream);if(state===STATE_ERRORED)throw new TypeError(errErrorErroredStream);if(state===STATE_CLOSED)throw new TypeError(errErrorClosedStream);return ReadableStreamDefaultControllerError(this,e)}}function ReadableStreamDefaultControllerCancel(controller,
+reason){controller[_queue]=new SimpleQueue;const underlyingSource=controller[_underlyingSource];return PromiseCallOrNoop(underlyingSource,"cancel",reason,"underlyingSource.cancel")}function ReadableStreamDefaultControllerPull(controller){const stream=controller[_controlledReadableStream];if(controller[_queue].length>0){const chunk=DequeueValue(controller);if(controller[_readableStreamDefaultControllerBits]&CLOSE_REQUESTED&&controller[_queue].length===0)ReadableStreamClose(stream);else ReadableStreamDefaultControllerCallPullIfNeeded(controller);
+return Promise_resolve(CreateIterResultObject(chunk,false))}const pendingPromise=ReadableStreamAddReadRequest(stream);ReadableStreamDefaultControllerCallPullIfNeeded(controller);return pendingPromise}function ReadableStreamAddReadRequest(stream){const promise=v8_createPromise();stream[_reader][_readRequests].push(promise);return promise}class ReadableStreamDefaultReader{constructor(stream){if(IsReadableStream(stream)===false)throw new TypeError(errReaderConstructorBadArgument);if(IsReadableStreamLocked(stream)===
+true)throw new TypeError(errReaderConstructorStreamAlreadyLocked);ReadableStreamReaderGenericInitialize(this,stream);this[_readRequests]=new SimpleQueue}get closed(){if(IsReadableStreamDefaultReader(this)===false)return Promise_reject(new TypeError(streamErrors_illegalInvocation));return this[_closedPromise]}cancel(reason){if(IsReadableStreamDefaultReader(this)===false)return Promise_reject(new TypeError(streamErrors_illegalInvocation));const stream=this[_ownerReadableStream];if(stream===undefined)return Promise_reject(new TypeError(errCancelReleasedReader));
+return ReadableStreamReaderGenericCancel(this,reason)}read(){if(IsReadableStreamDefaultReader(this)===false)return Promise_reject(new TypeError(streamErrors_illegalInvocation));if(this[_ownerReadableStream]===undefined)return Promise_reject(new TypeError(errReadReleasedReader));return ReadableStreamDefaultReaderRead(this)}releaseLock(){if(IsReadableStreamDefaultReader(this)===false)throw new TypeError(streamErrors_illegalInvocation);const stream=this[_ownerReadableStream];if(stream===undefined)return undefined;
+if(this[_readRequests].length>0)throw new TypeError(errReleaseReaderWithPendingRead);ReadableStreamReaderGenericRelease(this)}}function ReadableStreamReaderGenericCancel(reader,reason){return ReadableStreamCancel(reader[_ownerReadableStream],reason)}function AcquireReadableStreamDefaultReader(stream){return new ReadableStreamDefaultReader(stream)}function ReadableStreamCancel(stream,reason){stream[_readableStreamBits]|=DISTURBED;const state=ReadableStreamGetState(stream);if(state===STATE_CLOSED)return Promise_resolve(undefined);
+if(state===STATE_ERRORED)return Promise_reject(stream[_storedError]);ReadableStreamClose(stream);const sourceCancelPromise=ReadableStreamDefaultControllerCancel(stream[_controller],reason);return thenPromise(sourceCancelPromise,()=>undefined)}function ReadableStreamDefaultControllerClose(controller){const stream=controller[_controlledReadableStream];controller[_readableStreamDefaultControllerBits]|=CLOSE_REQUESTED;if(controller[_queue].length===0)ReadableStreamClose(stream)}function ReadableStreamFulfillReadRequest(stream,
+chunk,done){const reader=stream[_reader];const readRequest=stream[_reader][_readRequests].shift();v8_resolvePromise(readRequest,CreateIterResultObject(chunk,done))}function ReadableStreamDefaultControllerEnqueue(controller,chunk){const stream=controller[_controlledReadableStream];if(IsReadableStreamLocked(stream)===true&&ReadableStreamGetNumReadRequests(stream)>0)ReadableStreamFulfillReadRequest(stream,chunk,false);else{let chunkSize=1;const strategySize=controller[_strategySize];if(strategySize!==
+undefined)try{chunkSize=strategySize(chunk)}catch(chunkSizeE){if(ReadableStreamGetState(stream)===STATE_READABLE)ReadableStreamDefaultControllerError(controller,chunkSizeE);throw chunkSizeE;}try{EnqueueValueWithSize(controller,chunk,chunkSize)}catch(enqueueE){if(ReadableStreamGetState(stream)===STATE_READABLE)ReadableStreamDefaultControllerError(controller,enqueueE);throw enqueueE;}}ReadableStreamDefaultControllerCallPullIfNeeded(controller)}function ReadableStreamGetState(stream){return(stream[_readableStreamBits]&
+STATE_MASK)>>STATE_BITS_OFFSET}function ReadableStreamSetState(stream,state){stream[_readableStreamBits]=stream[_readableStreamBits]&~STATE_MASK|state<<STATE_BITS_OFFSET}function ReadableStreamDefaultControllerError(controller,e){controller[_queue]=new SimpleQueue;const stream=controller[_controlledReadableStream];ReadableStreamError(stream,e)}function ReadableStreamError(stream,e){stream[_storedError]=e;ReadableStreamSetState(stream,STATE_ERRORED);const reader=stream[_reader];if(reader===undefined)return undefined;
+if(IsReadableStreamDefaultReader(reader)===true){reader[_readRequests].forEach((request)=>v8_rejectPromise(request,e));reader[_readRequests]=new SimpleQueue}v8_rejectPromise(reader[_closedPromise],e);v8_markPromiseAsHandled(reader[_closedPromise])}function ReadableStreamClose(stream){ReadableStreamSetState(stream,STATE_CLOSED);const reader=stream[_reader];if(reader===undefined)return undefined;if(IsReadableStreamDefaultReader(reader)===true){reader[_readRequests].forEach((request)=>v8_resolvePromise(request,
+CreateIterResultObject(undefined,true)));reader[_readRequests]=new SimpleQueue}v8_resolvePromise(reader[_closedPromise],undefined)}function ReadableStreamDefaultControllerGetDesiredSize(controller){const stream=controller[_controlledReadableStream];const state=ReadableStreamGetState(stream);if(state===STATE_CLOSED)return 0;else if(state===STATE_ERRORED)return null;const queueSize=GetTotalQueueSize(controller);return controller[_strategyHWM]-queueSize}function IsReadableStream(x){return hasOwnProperty(x,
+_controller)}function IsReadableStreamDisturbed(stream){return stream[_readableStreamBits]&DISTURBED}function IsReadableStreamLocked(stream){return stream[_reader]!==undefined}function IsReadableStreamDefaultController(x){return hasOwnProperty(x,_controlledReadableStream)}function IsReadableStreamDefaultReader(x){return hasOwnProperty(x,_readRequests)}function IsReadableStreamReadable(stream){return ReadableStreamGetState(stream)===STATE_READABLE}function IsReadableStreamClosed(stream){return ReadableStreamGetState(stream)===
+STATE_CLOSED}function IsReadableStreamErrored(stream){return ReadableStreamGetState(stream)===STATE_ERRORED}function ReadableStreamReaderGenericInitialize(reader,stream){const controller=stream[_controller];if(controller[_readableStreamDefaultControllerBits]&EXTERNALLY_CONTROLLED){const underlyingSource=controller[_underlyingSource];callFunction(underlyingSource.notifyLockAcquired,underlyingSource)}reader[_ownerReadableStream]=stream;stream[_reader]=reader;switch(ReadableStreamGetState(stream)){case STATE_READABLE:reader[_closedPromise]=
+v8_createPromise();break;case STATE_CLOSED:reader[_closedPromise]=Promise_resolve(undefined);break;case STATE_ERRORED:reader[_closedPromise]=Promise_reject(stream[_storedError]);v8_markPromiseAsHandled(reader[_closedPromise]);break}}function ReadableStreamReaderGenericRelease(reader){const controller=reader[_ownerReadableStream][_controller];if(controller[_readableStreamDefaultControllerBits]&EXTERNALLY_CONTROLLED){const underlyingSource=controller[_underlyingSource];callFunction(underlyingSource.notifyLockReleased,
+underlyingSource)}if(ReadableStreamGetState(reader[_ownerReadableStream])===STATE_READABLE)v8_rejectPromise(reader[_closedPromise],new TypeError(errReleasedReaderClosedPromise));else reader[_closedPromise]=Promise_reject(new TypeError(errReleasedReaderClosedPromise));v8_markPromiseAsHandled(reader[_closedPromise]);reader[_ownerReadableStream][_reader]=undefined;reader[_ownerReadableStream]=undefined}function ReadableStreamDefaultReaderRead(reader){const stream=reader[_ownerReadableStream];stream[_readableStreamBits]|=
+DISTURBED;if(ReadableStreamGetState(stream)===STATE_CLOSED)return Promise_resolve(CreateIterResultObject(undefined,true));if(ReadableStreamGetState(stream)===STATE_ERRORED)return Promise_reject(stream[_storedError]);return ReadableStreamDefaultControllerPull(stream[_controller])}function ReadableStreamDefaultControllerCallPullIfNeeded(controller){const shouldPull=ReadableStreamDefaultControllerShouldCallPull(controller);if(shouldPull===false)return undefined;if(controller[_readableStreamDefaultControllerBits]&
+PULLING){controller[_readableStreamDefaultControllerBits]|=PULL_AGAIN;return undefined}controller[_readableStreamDefaultControllerBits]|=PULLING;const underlyingSource=controller[_underlyingSource];const pullPromise=PromiseCallOrNoop(underlyingSource,"pull",controller,"underlyingSource.pull");thenPromise(pullPromise,()=>{controller[_readableStreamDefaultControllerBits]&=~PULLING;if(controller[_readableStreamDefaultControllerBits]&PULL_AGAIN){controller[_readableStreamDefaultControllerBits]&=~PULL_AGAIN;
+ReadableStreamDefaultControllerCallPullIfNeeded(controller)}},(e)=>{if(ReadableStreamGetState(controller[_controlledReadableStream])===STATE_READABLE)ReadableStreamDefaultControllerError(controller,e)})}function ReadableStreamDefaultControllerShouldCallPull(controller){const stream=controller[_controlledReadableStream];const state=ReadableStreamGetState(stream);if(state===STATE_CLOSED||state===STATE_ERRORED)return false;if(controller[_readableStreamDefaultControllerBits]&CLOSE_REQUESTED)return false;
+if(!(controller[_readableStreamDefaultControllerBits]&STARTED))return false;if(IsReadableStreamLocked(stream)===true&&ReadableStreamGetNumReadRequests(stream)>0)return true;const desiredSize=ReadableStreamDefaultControllerGetDesiredSize(controller);if(desiredSize>0)return true;return false}function ReadableStreamGetNumReadRequests(stream){const reader=stream[_reader];const readRequests=reader[_readRequests];return readRequests.length}function ReadableStreamTee(stream){const reader=AcquireReadableStreamDefaultReader(stream);
+let closedOrErrored=false;let canceled1=false;let canceled2=false;let reason1;let reason2;let promise=v8_createPromise();const branch1Stream=new ReadableStream({pull,cancel:cancel1});const branch2Stream=new ReadableStream({pull,cancel:cancel2});const branch1=branch1Stream[_controller];const branch2=branch2Stream[_controller];thenPromise(reader[_closedPromise],undefined,function(r){if(closedOrErrored===true)return;ReadableStreamDefaultControllerError(branch1,r);ReadableStreamDefaultControllerError(branch2,
+r);closedOrErrored=true});return[branch1Stream,branch2Stream];function pull(){return thenPromise(ReadableStreamDefaultReaderRead(reader),function(result){const value=result.value;const done=result.done;if(done===true&&closedOrErrored===false){if(canceled1===false)ReadableStreamDefaultControllerClose(branch1);if(canceled2===false)ReadableStreamDefaultControllerClose(branch2);closedOrErrored=true}if(closedOrErrored===true)return;if(canceled1===false)ReadableStreamDefaultControllerEnqueue(branch1,value);
+if(canceled2===false)ReadableStreamDefaultControllerEnqueue(branch2,value)})}function cancel1(reason){canceled1=true;reason1=reason;if(canceled2===true){const compositeReason=[reason1,reason2];const cancelResult=ReadableStreamCancel(stream,compositeReason);v8_resolvePromise(promise,cancelResult)}return promise}function cancel2(reason){canceled2=true;reason2=reason;if(canceled1===true){const compositeReason=[reason1,reason2];const cancelResult=ReadableStreamCancel(stream,compositeReason);v8_resolvePromise(promise,
+cancelResult)}return promise}}function DequeueValue(controller){const result=controller[_queue].shift();controller[_totalQueuedSize]-=result.size;return result.value}function EnqueueValueWithSize(controller,value,size){size=Number(size);if(Number_isNaN(size)||size===+Infinity||size<0)throw new RangeError(streamErrors_invalidSize);controller[_totalQueuedSize]+=size;controller[_queue].push({value,size})}function GetTotalQueueSize(controller){return controller[_totalQueuedSize]}function ValidateAndNormalizeQueuingStrategy(size,
+highWaterMark){if(size!==undefined&&typeof size!=="function")throw new TypeError(streamErrors_sizeNotAFunction);highWaterMark=Number(highWaterMark);if(Number_isNaN(highWaterMark))throw new RangeError(streamErrors_invalidHWM);if(highWaterMark<0)throw new RangeError(streamErrors_invalidHWM);return{size,highWaterMark}}function CallOrNoop(O,P,arg,nameForError){const method=O[P];if(method===undefined)return undefined;if(typeof method!=="function")throw new TypeError(errTmplMustBeFunctionOrUndefined(nameForError));
+return callFunction(method,O,arg)}function PromiseCallOrNoop(O,P,arg,nameForError){let method;try{method=O[P]}catch(methodE){return Promise_reject(methodE)}if(method===undefined)return Promise_resolve(undefined);if(typeof method!=="function")return Promise_reject(new TypeError(errTmplMustBeFunctionOrUndefined(nameForError)));try{return Promise_resolve(callFunction(method,O,arg))}catch(e){return Promise_reject(e)}}function CreateIterResultObject(value,done){return{value,done}}defineProperty(global,
+"ReadableStream",{value:ReadableStream,enumerable:false,configurable:true,writable:true})})(this);
\ No newline at end of file
diff --git a/src/cobalt/streams/readable_stream.js b/src/cobalt/streams/readable_stream.js
new file mode 100644
index 0000000..5943f89
--- /dev/null
+++ b/src/cobalt/streams/readable_stream.js
@@ -0,0 +1,1083 @@
+// ==ClosureCompiler==
+// @output_file_name readable_stream.js
+// @compilation_level WHITESPACE_ONLY
+// @language_out ES6_STRICT
+// ==/ClosureCompiler==
+
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function(global) {
+  'use strict';
+
+  // Mimic functionality provided to v8 extras.
+  const v8_InternalPackedArray = global.Array;
+
+  function v8_createPrivateSymbol(x) {
+    return Symbol(x);
+  }
+
+  function v8_simpleBind(fn, obj) {
+    return fn.bind(obj);
+  }
+
+  const arraySlice = global.Array.prototype.slice;
+  function v8_uncurryThis(fn) {
+    return function(obj) {
+      return fn.apply(obj, arraySlice.call(arguments, 1));
+    }
+  }
+
+  const v8_PromiseBase = global.Promise;
+  const _promiseResolve = v8_createPrivateSymbol('[[Resolve]]');
+  const _promiseReject = v8_createPrivateSymbol('[[Reject]]');
+
+  function v8_Promise() {
+    var that = this;
+    v8_PromiseBase.call(this, function(resolve, reject) {
+      that[_promiseResolve] = resolve;
+      that[_promiseReject] = reject;
+    });
+  }
+
+  v8_Promise.prototype = v8_PromiseBase.prototype;
+
+  function v8_createPromise() {
+    return new v8_Promise();
+  }
+
+  function v8_isPromise(obj) {
+    return obj instanceof v8_Promise;
+  }
+
+  function v8_resolvePromise(promise, value) {
+    promise[_promiseResolve](value);
+  }
+
+  function v8_rejectPromise(promise, reason) {
+    promise[_promiseReject](reason);
+  }
+
+  function v8_markPromiseAsHandled(promise) {
+    try {
+      thenPromise(promise, undefined, () => {});
+    } catch(error) {
+    }
+  }
+
+  /* SimpleQueue.js: begin */
+  // Simple queue structure. Avoids scalability issues with using
+  // InternalPackedArray directly by using multiple arrays in a linked list and
+  // keeping the array size bounded.
+  const QUEUE_MAX_ARRAY_SIZE = 16384;
+  class SimpleQueue {
+    constructor() {
+      this.front = {
+        elements: new v8_InternalPackedArray(),
+        next: undefined,
+      };
+      this.back = this.front;
+      // The cursor is used to avoid calling InternalPackedArray.shift().
+      this.cursor = 0;
+      this.size = 0;
+    }
+
+    get length() {
+      return this.size;
+    }
+
+    push(element) {
+      ++this.size;
+      if (this.back.elements.length === QUEUE_MAX_ARRAY_SIZE) {
+        const oldBack = this.back;
+        this.back = {
+          elements: new v8_InternalPackedArray(),
+          next: undefined,
+        };
+        oldBack.next = this.back;
+      }
+      this.back.elements.push(element);
+    }
+
+    shift() {
+      // assert(this.size > 0);
+      --this.size;
+      if (this.front.elements.length === this.cursor) {
+        // assert(this.cursor === QUEUE_MAX_ARRAY_SIZE);
+        // assert(this.front.next !== undefined);
+        this.front = this.front.next;
+        this.cursor = 0;
+      }
+      const element = this.front.elements[this.cursor];
+      // Permit shifted element to be garbage collected.
+      this.front.elements[this.cursor] = undefined;
+      ++this.cursor;
+
+      return element;
+    }
+
+    forEach(callback) {
+      let i = this.cursor;
+      let node = this.front;
+      let elements = node.elements;
+      while (i !== elements.length || node.next !== undefined) {
+        if (i === elements.length) {
+          // assert(node.next !== undefined);
+          // assert(i === QUEUE_MAX_ARRAY_SIZE);
+          node = node.next;
+          elements = node.elements;
+          i = 0;
+        }
+        callback(elements[i]);
+        ++i;
+      }
+    }
+
+    // Return the element that would be returned if shift() was called now,
+    // without modifying the queue.
+    peek() {
+      // assert(this.size > 0);
+      if (this.front.elements.length === this.cursor) {
+        // assert(this.cursor === QUEUE_MAX_ARRAY_SIZE)
+        // assert(this.front.next !== undefined);
+        return this.front.next.elements[0];
+      }
+      return this.front.elements[this.cursor];
+    }
+  }
+  /* SimpleQueue.js: end */
+
+  /* CommonStrings.js: begin */
+  const streamErrors_illegalInvocation = 'Illegal invocation';
+  const streamErrors_illegalConstructor = 'Illegal constructor';
+  const streamErrors_invalidType = 'Invalid type is specified';
+  const streamErrors_invalidSize = 'The return value of a queuing strategy\'s size function must be a finite, non-NaN, non-negative number';
+  const streamErrors_sizeNotAFunction = 'A queuing strategy\'s size property must be a function';
+  const streamErrors_invalidHWM = 'A queueing strategy\'s highWaterMark property must be a nonnegative, non-NaN number';
+  /* CommonStrings.js: end */
+
+  const _reader = v8_createPrivateSymbol('[[reader]]');
+  const _storedError = v8_createPrivateSymbol('[[storedError]]');
+  const _controller = v8_createPrivateSymbol('[[controller]]');
+
+  const _closedPromise = v8_createPrivateSymbol('[[closedPromise]]');
+  const _ownerReadableStream =
+      v8_createPrivateSymbol('[[ownerReadableStream]]');
+
+  const _readRequests = v8_createPrivateSymbol('[[readRequests]]');
+
+  const createWithExternalControllerSentinel =
+      v8_createPrivateSymbol('flag for UA-created ReadableStream to pass');
+
+  const _readableStreamBits = v8_createPrivateSymbol('bit field for [[state]] and [[disturbed]]');
+  const DISTURBED = 0b1;
+  // The 2nd and 3rd bit are for [[state]].
+  const STATE_MASK = 0b110;
+  const STATE_BITS_OFFSET = 1;
+  const STATE_READABLE = 0;
+  const STATE_CLOSED = 1;
+  const STATE_ERRORED = 2;
+
+  const _underlyingSource = v8_createPrivateSymbol('[[underlyingSource]]');
+  const _controlledReadableStream =
+      v8_createPrivateSymbol('[[controlledReadableStream]]');
+  const _queue = v8_createPrivateSymbol('[[queue]]');
+  const _totalQueuedSize = v8_createPrivateSymbol('[[totalQueuedSize]]');
+  const _strategySize = v8_createPrivateSymbol('[[strategySize]]');
+  const _strategyHWM = v8_createPrivateSymbol('[[strategyHWM]]');
+
+  const _readableStreamDefaultControllerBits = v8_createPrivateSymbol(
+      'bit field for [[started]], [[closeRequested]], [[pulling]], [[pullAgain]]');
+  const STARTED = 0b1;
+  const CLOSE_REQUESTED = 0b10;
+  const PULLING = 0b100;
+  const PULL_AGAIN = 0b1000;
+  const EXTERNALLY_CONTROLLED = 0b10000;
+
+  const undefined = global.undefined;
+  const Infinity = global.Infinity;
+
+  const defineProperty = global.Object.defineProperty;
+  const hasOwnProperty = v8_uncurryThis(global.Object.hasOwnProperty);
+  const callFunction = v8_uncurryThis(global.Function.prototype.call);
+  const applyFunction = v8_uncurryThis(global.Function.prototype.apply);
+
+  const TypeError = global.TypeError;
+  const RangeError = global.RangeError;
+
+  const Number = global.Number;
+  const Number_isNaN = Number.isNaN;
+  const Number_isFinite = Number.isFinite;
+
+  const Promise = global.Promise;
+  const thenPromise = v8_uncurryThis(Promise.prototype.then);
+  const Promise_resolve = v8_simpleBind(Promise.resolve, Promise);
+  const Promise_reject = v8_simpleBind(Promise.reject, Promise);
+
+  const errCancelLockedStream =
+      'Cannot cancel a readable stream that is locked to a reader';
+  const errEnqueueCloseRequestedStream =
+      'Cannot enqueue a chunk into a readable stream that is closed or has been requested to be closed';
+  const errCancelReleasedReader =
+      'This readable stream reader has been released and cannot be used to cancel its previous owner stream';
+  const errReadReleasedReader =
+      'This readable stream reader has been released and cannot be used to read from its previous owner stream';
+  const errCloseCloseRequestedStream =
+      'Cannot close a readable stream that has already been requested to be closed';
+  const errEnqueueClosedStream = 'Cannot enqueue a chunk into a closed readable stream';
+  const errEnqueueErroredStream = 'Cannot enqueue a chunk into an errored readable stream';
+  const errCloseClosedStream = 'Cannot close a closed readable stream';
+  const errCloseErroredStream = 'Cannot close an errored readable stream';
+  const errErrorClosedStream = 'Cannot error a close readable stream';
+  const errErrorErroredStream =
+      'Cannot error a readable stream that is already errored';
+  const errGetReaderNotByteStream = 'This readable stream does not support BYOB readers';
+  const errGetReaderBadMode = 'Invalid reader mode given: expected undefined or "byob"';
+  const errReaderConstructorBadArgument =
+      'ReadableStreamReader constructor argument is not a readable stream';
+  const errReaderConstructorStreamAlreadyLocked =
+      'ReadableStreamReader constructor can only accept readable streams that are not yet locked to a reader';
+  const errReleaseReaderWithPendingRead =
+      'Cannot release a readable stream reader when it still has outstanding read() calls that have not yet settled';
+  const errReleasedReaderClosedPromise =
+      'This readable stream reader has been released and cannot be used to monitor the stream\'s state';
+
+  const errTmplMustBeFunctionOrUndefined = name =>
+      `${name} must be a function or undefined`;
+
+  class ReadableStream {
+    constructor() {
+      // TODO(domenic): when V8 gets default parameters and destructuring, all
+      // this can be cleaned up.
+      const underlyingSource = arguments[0] === undefined ? {} : arguments[0];
+      const strategy = arguments[1] === undefined ? {} : arguments[1];
+      const size = strategy.size;
+      let highWaterMark = strategy.highWaterMark;
+      if (highWaterMark === undefined) {
+        highWaterMark = 1;
+      }
+
+      this[_readableStreamBits] = 0b0;
+      ReadableStreamSetState(this, STATE_READABLE);
+      this[_reader] = undefined;
+      this[_storedError] = undefined;
+
+      // Avoid allocating the controller if the stream is going to be controlled
+      // externally (i.e. from C++) anyway. All calls to underlyingSource
+      // methods will disregard their controller argument in such situations
+      // (but see below).
+
+      this[_controller] = undefined;
+
+      const type = underlyingSource.type;
+      const typeString = String(type);
+      if (typeString === 'bytes') {
+        throw new RangeError('bytes type is not yet implemented');
+      } else if (type !== undefined) {
+        throw new RangeError(streamErrors_invalidType);
+      }
+
+      this[_controller] =
+          new ReadableStreamDefaultController(this, underlyingSource, size, highWaterMark, arguments[2]);
+    }
+
+    get locked() {
+      if (IsReadableStream(this) === false) {
+        throw new TypeError(streamErrors_illegalInvocation);
+      }
+
+      return IsReadableStreamLocked(this);
+    }
+
+    cancel(reason) {
+      if (IsReadableStream(this) === false) {
+        return Promise_reject(new TypeError(streamErrors_illegalInvocation));
+      }
+
+      if (IsReadableStreamLocked(this) === true) {
+        return Promise_reject(new TypeError(errCancelLockedStream));
+      }
+
+      return ReadableStreamCancel(this, reason);
+    }
+
+    getReader({ mode } = {}) {
+      if (IsReadableStream(this) === false) {
+        throw new TypeError(streamErrors_illegalInvocation);
+      }
+
+      if (mode === 'byob') {
+        // TODO(ricea): When BYOB readers are supported:
+        //
+        // a. If
+        // ! IsReadableByteStreamController(this.[[_controller]])
+        // is false, throw a TypeError exception.
+        // b. Return ? AcquireReadableStreamBYOBReader(this).
+        throw new TypeError(errGetReaderNotByteStream);
+      }
+
+      if (mode === undefined) {
+        return AcquireReadableStreamDefaultReader(this);
+      }
+
+      throw new RangeError(errGetReaderBadMode);
+    }
+
+    pipeThrough({writable, readable}, options) {
+      throw new TypeError('pipeThrough not implemented');
+    }
+
+    pipeTo(dest, {preventClose, preventAbort, preventCancel} = {}) {
+      throw new TypeError('pipeTo not implemented');
+    }
+
+    tee() {
+      if (IsReadableStream(this) === false) {
+        throw new TypeError(streamErrors_illegalInvocation);
+      }
+
+      return ReadableStreamTee(this);
+    }
+  }
+
+  class ReadableStreamDefaultController {
+    // Cobalt: Constructor has a hidden argument at the end to designate
+    // whether it is externally controlled. Exposing this would fail the
+    // web platform test checking the number of parameters the constructor
+    // accepts.
+    constructor(stream, underlyingSource, size, highWaterMark) {
+      if (IsReadableStream(stream) === false) {
+        throw new TypeError(streamErrors_illegalConstructor);
+      }
+
+      if (stream[_controller] !== undefined) {
+        throw new TypeError(streamErrors_illegalConstructor);
+      }
+
+      this[_controlledReadableStream] = stream;
+
+      this[_underlyingSource] = underlyingSource;
+
+      this[_queue] = new SimpleQueue();
+      this[_totalQueuedSize] = 0;
+
+      this[_readableStreamDefaultControllerBits] = 0b0;
+      // Cobalt: Hidden constructor parameter to designate whether the
+      // is externally controlled.
+      if (arguments[4] === createWithExternalControllerSentinel) {
+        this[_readableStreamDefaultControllerBits] |= EXTERNALLY_CONTROLLED;
+      }
+
+      const normalizedStrategy =
+          ValidateAndNormalizeQueuingStrategy(size, highWaterMark);
+      this[_strategySize] = normalizedStrategy.size;
+      this[_strategyHWM] = normalizedStrategy.highWaterMark;
+
+      const controller = this;
+
+      const startResult = CallOrNoop(
+          underlyingSource, 'start', this, 'underlyingSource.start');
+      thenPromise(Promise_resolve(startResult),
+          () => {
+            controller[_readableStreamDefaultControllerBits] |= STARTED;
+            ReadableStreamDefaultControllerCallPullIfNeeded(controller);
+          },
+          r => {
+            if (ReadableStreamGetState(stream) === STATE_READABLE) {
+              ReadableStreamDefaultControllerError(controller, r);
+            }
+          });
+    }
+
+    get desiredSize() {
+      if (IsReadableStreamDefaultController(this) === false) {
+        throw new TypeError(streamErrors_illegalInvocation);
+      }
+
+      return ReadableStreamDefaultControllerGetDesiredSize(this);
+    }
+
+    close() {
+      if (IsReadableStreamDefaultController(this) === false) {
+        throw new TypeError(streamErrors_illegalInvocation);
+      }
+
+      const stream = this[_controlledReadableStream];
+
+      if (this[_readableStreamDefaultControllerBits] & CLOSE_REQUESTED) {
+        throw new TypeError(errCloseCloseRequestedStream);
+      }
+
+      const state = ReadableStreamGetState(stream);
+      if (state === STATE_ERRORED) {
+        throw new TypeError(errCloseErroredStream);
+      }
+      if (state === STATE_CLOSED) {
+        throw new TypeError(errCloseClosedStream);
+      }
+
+      return ReadableStreamDefaultControllerClose(this);
+    }
+
+    enqueue(chunk) {
+      if (IsReadableStreamDefaultController(this) === false) {
+        throw new TypeError(streamErrors_illegalInvocation);
+      }
+
+      const stream = this[_controlledReadableStream];
+
+      if (this[_readableStreamDefaultControllerBits] & CLOSE_REQUESTED) {
+        throw new TypeError(errEnqueueCloseRequestedStream);
+      }
+
+      const state = ReadableStreamGetState(stream);
+      if (state === STATE_ERRORED) {
+        throw new TypeError(errEnqueueErroredStream);
+      }
+      if (state === STATE_CLOSED) {
+        throw new TypeError(errEnqueueClosedStream);
+      }
+
+      return ReadableStreamDefaultControllerEnqueue(this, chunk);
+    }
+
+    error(e) {
+      if (IsReadableStreamDefaultController(this) === false) {
+        throw new TypeError(streamErrors_illegalInvocation);
+      }
+
+      const stream = this[_controlledReadableStream];
+
+      const state = ReadableStreamGetState(stream);
+      if (state === STATE_ERRORED) {
+        throw new TypeError(errErrorErroredStream);
+      }
+      if (state === STATE_CLOSED) {
+        throw new TypeError(errErrorClosedStream);
+      }
+
+      return ReadableStreamDefaultControllerError(this, e);
+    }
+  }
+
+  function ReadableStreamDefaultControllerCancel(controller, reason) {
+    controller[_queue] = new SimpleQueue();
+
+    const underlyingSource = controller[_underlyingSource];
+    return PromiseCallOrNoop(underlyingSource, 'cancel', reason, 'underlyingSource.cancel');
+  }
+
+  function ReadableStreamDefaultControllerPull(controller) {
+    const stream = controller[_controlledReadableStream];
+
+    if (controller[_queue].length > 0) {
+      const chunk = DequeueValue(controller);
+
+      if ((controller[_readableStreamDefaultControllerBits] & CLOSE_REQUESTED) &&
+          controller[_queue].length === 0) {
+        ReadableStreamClose(stream);
+      } else {
+        ReadableStreamDefaultControllerCallPullIfNeeded(controller);
+      }
+
+      return Promise_resolve(CreateIterResultObject(chunk, false));
+    }
+
+    const pendingPromise = ReadableStreamAddReadRequest(stream);
+    ReadableStreamDefaultControllerCallPullIfNeeded(controller);
+    return pendingPromise;
+  }
+
+  function ReadableStreamAddReadRequest(stream) {
+    const promise = v8_createPromise();
+    stream[_reader][_readRequests].push(promise);
+    return promise;
+  }
+
+  class ReadableStreamDefaultReader {
+    constructor(stream) {
+      if (IsReadableStream(stream) === false) {
+        throw new TypeError(errReaderConstructorBadArgument);
+      }
+      if (IsReadableStreamLocked(stream) === true) {
+        throw new TypeError(errReaderConstructorStreamAlreadyLocked);
+      }
+
+      ReadableStreamReaderGenericInitialize(this, stream);
+
+      this[_readRequests] = new SimpleQueue();
+    }
+
+    get closed() {
+      if (IsReadableStreamDefaultReader(this) === false) {
+        return Promise_reject(new TypeError(streamErrors_illegalInvocation));
+      }
+
+      return this[_closedPromise];
+    }
+
+    cancel(reason) {
+      if (IsReadableStreamDefaultReader(this) === false) {
+        return Promise_reject(new TypeError(streamErrors_illegalInvocation));
+      }
+
+      const stream = this[_ownerReadableStream];
+      if (stream === undefined) {
+        return Promise_reject(new TypeError(errCancelReleasedReader));
+      }
+
+      return ReadableStreamReaderGenericCancel(this, reason);
+    }
+
+    read() {
+      if (IsReadableStreamDefaultReader(this) === false) {
+        return Promise_reject(new TypeError(streamErrors_illegalInvocation));
+      }
+
+      if (this[_ownerReadableStream] === undefined) {
+        return Promise_reject(new TypeError(errReadReleasedReader));
+      }
+
+      return ReadableStreamDefaultReaderRead(this);
+    }
+
+    releaseLock() {
+      if (IsReadableStreamDefaultReader(this) === false) {
+        throw new TypeError(streamErrors_illegalInvocation);
+      }
+
+      const stream = this[_ownerReadableStream];
+      if (stream === undefined) {
+        return undefined;
+      }
+
+      if (this[_readRequests].length > 0) {
+        throw new TypeError(errReleaseReaderWithPendingRead);
+      }
+
+      ReadableStreamReaderGenericRelease(this);
+    }
+  }
+
+  function ReadableStreamReaderGenericCancel(reader, reason) {
+    return ReadableStreamCancel(reader[_ownerReadableStream], reason);
+  }
+
+  //
+  // Readable stream abstract operations
+  //
+
+  function AcquireReadableStreamDefaultReader(stream) {
+    return new ReadableStreamDefaultReader(stream);
+  }
+
+  function ReadableStreamCancel(stream, reason) {
+    stream[_readableStreamBits] |= DISTURBED;
+
+    const state = ReadableStreamGetState(stream);
+    if (state === STATE_CLOSED) {
+      return Promise_resolve(undefined);
+    }
+    if (state === STATE_ERRORED) {
+      return Promise_reject(stream[_storedError]);
+    }
+
+    ReadableStreamClose(stream);
+
+    const sourceCancelPromise = ReadableStreamDefaultControllerCancel(stream[_controller], reason);
+    return thenPromise(sourceCancelPromise, () => undefined);
+  }
+
+  function ReadableStreamDefaultControllerClose(controller) {
+    const stream = controller[_controlledReadableStream];
+
+    controller[_readableStreamDefaultControllerBits] |= CLOSE_REQUESTED;
+
+    if (controller[_queue].length === 0) {
+      ReadableStreamClose(stream);
+    }
+  }
+
+  function ReadableStreamFulfillReadRequest(stream, chunk, done) {
+    const reader = stream[_reader];
+
+    const readRequest = stream[_reader][_readRequests].shift();
+    v8_resolvePromise(readRequest, CreateIterResultObject(chunk, done));
+  }
+
+  function ReadableStreamDefaultControllerEnqueue(controller, chunk) {
+    const stream = controller[_controlledReadableStream];
+
+    if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) {
+      ReadableStreamFulfillReadRequest(stream, chunk, false);
+    } else {
+      let chunkSize = 1;
+
+      const strategySize = controller[_strategySize];
+      if (strategySize !== undefined) {
+        try {
+          chunkSize = strategySize(chunk);
+        } catch (chunkSizeE) {
+          if (ReadableStreamGetState(stream) === STATE_READABLE) {
+            ReadableStreamDefaultControllerError(controller, chunkSizeE);
+          }
+          throw chunkSizeE;
+        }
+      }
+
+      try {
+        EnqueueValueWithSize(controller, chunk, chunkSize);
+      } catch (enqueueE) {
+        if (ReadableStreamGetState(stream) === STATE_READABLE) {
+          ReadableStreamDefaultControllerError(controller, enqueueE);
+        }
+        throw enqueueE;
+      }
+    }
+
+    ReadableStreamDefaultControllerCallPullIfNeeded(controller);
+  }
+
+  function ReadableStreamGetState(stream) {
+    return (stream[_readableStreamBits] & STATE_MASK) >> STATE_BITS_OFFSET;
+  }
+
+  function ReadableStreamSetState(stream, state) {
+    stream[_readableStreamBits] = (stream[_readableStreamBits] & ~STATE_MASK) |
+        (state << STATE_BITS_OFFSET);
+  }
+
+  function ReadableStreamDefaultControllerError(controller, e) {
+    controller[_queue] = new SimpleQueue();
+    const stream = controller[_controlledReadableStream];
+    ReadableStreamError(stream, e);
+  }
+
+  function ReadableStreamError(stream, e) {
+    stream[_storedError] = e;
+    ReadableStreamSetState(stream, STATE_ERRORED);
+
+    const reader = stream[_reader];
+    if (reader === undefined) {
+      return undefined;
+    }
+
+    if (IsReadableStreamDefaultReader(reader) === true) {
+      reader[_readRequests].forEach(request => v8_rejectPromise(request, e));
+      reader[_readRequests] = new SimpleQueue();
+    }
+
+    v8_rejectPromise(reader[_closedPromise], e);
+    v8_markPromiseAsHandled(reader[_closedPromise]);
+  }
+
+  function ReadableStreamClose(stream) {
+    ReadableStreamSetState(stream, STATE_CLOSED);
+
+    const reader = stream[_reader];
+    if (reader === undefined) {
+      return undefined;
+    }
+
+    if (IsReadableStreamDefaultReader(reader) === true) {
+      reader[_readRequests].forEach(request =>
+          v8_resolvePromise(request, CreateIterResultObject(undefined, true)));
+      reader[_readRequests] = new SimpleQueue();
+    }
+
+    v8_resolvePromise(reader[_closedPromise], undefined);
+  }
+
+  function ReadableStreamDefaultControllerGetDesiredSize(controller) {
+    // Cobalt: When the state is closed or errored, return particular values.
+    const stream = controller[_controlledReadableStream];
+    const state = ReadableStreamGetState(stream);
+    if (state === STATE_CLOSED) {
+      return 0;
+    } else if (state === STATE_ERRORED) {
+      return null;
+    }
+
+    const queueSize = GetTotalQueueSize(controller);
+    return controller[_strategyHWM] - queueSize;
+  }
+
+  function IsReadableStream(x) {
+    return hasOwnProperty(x, _controller);
+  }
+
+  function IsReadableStreamDisturbed(stream) {
+    return stream[_readableStreamBits] & DISTURBED;
+  }
+
+  function IsReadableStreamLocked(stream) {
+    return stream[_reader] !== undefined;
+  }
+
+  function IsReadableStreamDefaultController(x) {
+    return hasOwnProperty(x, _controlledReadableStream);
+  }
+
+  function IsReadableStreamDefaultReader(x) {
+    return hasOwnProperty(x, _readRequests);
+  }
+
+  function IsReadableStreamReadable(stream) {
+    return ReadableStreamGetState(stream) === STATE_READABLE;
+  }
+
+  function IsReadableStreamClosed(stream) {
+    return ReadableStreamGetState(stream) === STATE_CLOSED;
+  }
+
+  function IsReadableStreamErrored(stream) {
+    return ReadableStreamGetState(stream) === STATE_ERRORED;
+  }
+
+  function ReadableStreamReaderGenericInitialize(reader, stream) {
+    // TODO(yhirano): Remove this when we don't need hasPendingActivity in
+    // blink::UnderlyingSourceBase.
+    const controller = stream[_controller];
+    if (controller[_readableStreamDefaultControllerBits] & EXTERNALLY_CONTROLLED) {
+      // The stream is created with an external controller (i.e. made in
+      // Blink).
+      const underlyingSource = controller[_underlyingSource];
+      callFunction(underlyingSource.notifyLockAcquired, underlyingSource);
+    }
+
+    reader[_ownerReadableStream] = stream;
+    stream[_reader] = reader;
+
+    switch (ReadableStreamGetState(stream)) {
+      case STATE_READABLE:
+        reader[_closedPromise] = v8_createPromise();
+        break;
+      case STATE_CLOSED:
+        reader[_closedPromise] = Promise_resolve(undefined);
+        break;
+      case STATE_ERRORED:
+        reader[_closedPromise] = Promise_reject(stream[_storedError]);
+        v8_markPromiseAsHandled(reader[_closedPromise]);
+        break;
+    }
+  }
+
+  function ReadableStreamReaderGenericRelease(reader) {
+    // TODO(yhirano): Remove this when we don't need hasPendingActivity in
+    // blink::UnderlyingSourceBase.
+    const controller = reader[_ownerReadableStream][_controller];
+    if (controller[_readableStreamDefaultControllerBits] & EXTERNALLY_CONTROLLED) {
+      // The stream is created with an external controller (i.e. made in
+      // Blink).
+      const underlyingSource = controller[_underlyingSource];
+      callFunction(underlyingSource.notifyLockReleased, underlyingSource);
+    }
+
+    if (ReadableStreamGetState(reader[_ownerReadableStream]) === STATE_READABLE) {
+      v8_rejectPromise(reader[_closedPromise], new TypeError(errReleasedReaderClosedPromise));
+    } else {
+      reader[_closedPromise] = Promise_reject(new TypeError(errReleasedReaderClosedPromise));
+    }
+    v8_markPromiseAsHandled(reader[_closedPromise]);
+
+    reader[_ownerReadableStream][_reader] = undefined;
+    reader[_ownerReadableStream] = undefined;
+  }
+
+  function ReadableStreamDefaultReaderRead(reader) {
+    const stream = reader[_ownerReadableStream];
+    stream[_readableStreamBits] |= DISTURBED;
+
+    if (ReadableStreamGetState(stream) === STATE_CLOSED) {
+      return Promise_resolve(CreateIterResultObject(undefined, true));
+    }
+
+    if (ReadableStreamGetState(stream) === STATE_ERRORED) {
+      return Promise_reject(stream[_storedError]);
+    }
+
+    return ReadableStreamDefaultControllerPull(stream[_controller]);
+  }
+
+  function ReadableStreamDefaultControllerCallPullIfNeeded(controller) {
+    const shouldPull = ReadableStreamDefaultControllerShouldCallPull(controller);
+    if (shouldPull === false) {
+      return undefined;
+    }
+
+    if (controller[_readableStreamDefaultControllerBits] & PULLING) {
+      controller[_readableStreamDefaultControllerBits] |= PULL_AGAIN;
+      return undefined;
+    }
+
+    controller[_readableStreamDefaultControllerBits] |= PULLING;
+
+    const underlyingSource = controller[_underlyingSource];
+    const pullPromise = PromiseCallOrNoop(
+        underlyingSource, 'pull', controller, 'underlyingSource.pull');
+
+    thenPromise(pullPromise,
+        () => {
+          controller[_readableStreamDefaultControllerBits] &= ~PULLING;
+
+          if (controller[_readableStreamDefaultControllerBits] & PULL_AGAIN) {
+            controller[_readableStreamDefaultControllerBits] &= ~PULL_AGAIN;
+            ReadableStreamDefaultControllerCallPullIfNeeded(controller);
+          }
+        },
+        e => {
+          if (ReadableStreamGetState(controller[_controlledReadableStream]) === STATE_READABLE) {
+            ReadableStreamDefaultControllerError(controller, e);
+          }
+        });
+  }
+
+  function ReadableStreamDefaultControllerShouldCallPull(controller) {
+    const stream = controller[_controlledReadableStream];
+
+    const state = ReadableStreamGetState(stream);
+    if (state === STATE_CLOSED || state === STATE_ERRORED) {
+      return false;
+    }
+
+    if (controller[_readableStreamDefaultControllerBits] & CLOSE_REQUESTED) {
+      return false;
+    }
+
+    if (!(controller[_readableStreamDefaultControllerBits] & STARTED)) {
+      return false;
+    }
+
+    if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) {
+      return true;
+    }
+
+    const desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller);
+    if (desiredSize > 0) {
+      return true;
+    }
+
+    return false;
+  }
+
+  function ReadableStreamGetNumReadRequests(stream) {
+    const reader = stream[_reader];
+    const readRequests = reader[_readRequests];
+    return readRequests.length;
+  }
+
+  // Potential future optimization: use class instances for the underlying
+  // sources, so that we don't re-create
+  // closures every time.
+
+  // TODO(domenic): shouldClone argument from spec not supported yet
+  function ReadableStreamTee(stream) {
+    const reader = AcquireReadableStreamDefaultReader(stream);
+
+    let closedOrErrored = false;
+    let canceled1 = false;
+    let canceled2 = false;
+    let reason1;
+    let reason2;
+    let promise = v8_createPromise();
+
+    const branch1Stream = new ReadableStream({pull, cancel: cancel1});
+
+    const branch2Stream = new ReadableStream({pull, cancel: cancel2});
+
+    const branch1 = branch1Stream[_controller];
+    const branch2 = branch2Stream[_controller];
+
+    thenPromise(
+        reader[_closedPromise], undefined, function(r) {
+          if (closedOrErrored === true) {
+            return;
+          }
+
+          ReadableStreamDefaultControllerError(branch1, r);
+          ReadableStreamDefaultControllerError(branch2, r);
+          closedOrErrored = true;
+        });
+
+    return [branch1Stream, branch2Stream];
+
+    function pull() {
+      return thenPromise(
+          ReadableStreamDefaultReaderRead(reader), function(result) {
+            const value = result.value;
+            const done = result.done;
+
+            if (done === true && closedOrErrored === false) {
+              if (canceled1 === false) {
+                ReadableStreamDefaultControllerClose(branch1);
+              }
+              if (canceled2 === false) {
+                ReadableStreamDefaultControllerClose(branch2);
+              }
+              closedOrErrored = true;
+            }
+
+            if (closedOrErrored === true) {
+              return;
+            }
+
+            if (canceled1 === false) {
+              ReadableStreamDefaultControllerEnqueue(branch1, value);
+            }
+
+            if (canceled2 === false) {
+              ReadableStreamDefaultControllerEnqueue(branch2, value);
+            }
+          });
+    }
+
+    function cancel1(reason) {
+      canceled1 = true;
+      reason1 = reason;
+
+      if (canceled2 === true) {
+        const compositeReason = [reason1, reason2];
+        const cancelResult = ReadableStreamCancel(stream, compositeReason);
+        v8_resolvePromise(promise, cancelResult);
+      }
+
+      return promise;
+    }
+
+    function cancel2(reason) {
+      canceled2 = true;
+      reason2 = reason;
+
+      if (canceled1 === true) {
+        const compositeReason = [reason1, reason2];
+        const cancelResult = ReadableStreamCancel(stream, compositeReason);
+        v8_resolvePromise(promise, cancelResult);
+      }
+
+      return promise;
+    }
+  }
+
+  //
+  // Queue-with-sizes
+  //
+
+  function DequeueValue(controller) {
+    const result = controller[_queue].shift();
+    controller[_totalQueuedSize] -= result.size;
+    return result.value;
+  }
+
+  function EnqueueValueWithSize(controller, value, size) {
+    size = Number(size);
+    if (Number_isNaN(size) || size === +Infinity || size < 0) {
+      throw new RangeError(streamErrors_invalidSize);
+    }
+
+    controller[_totalQueuedSize] += size;
+    controller[_queue].push({value, size});
+  }
+
+  function GetTotalQueueSize(controller) { return controller[_totalQueuedSize]; }
+
+  //
+  // Other helpers
+  //
+
+  function ValidateAndNormalizeQueuingStrategy(size, highWaterMark) {
+    if (size !== undefined && typeof size !== 'function') {
+      throw new TypeError(streamErrors_sizeNotAFunction);
+    }
+
+    highWaterMark = Number(highWaterMark);
+    if (Number_isNaN(highWaterMark)) {
+      throw new RangeError(streamErrors_invalidHWM);
+    }
+    if (highWaterMark < 0) {
+      throw new RangeError(streamErrors_invalidHWM);
+    }
+
+    return {size, highWaterMark};
+  }
+
+  // Modified from InvokeOrNoop in spec
+  function CallOrNoop(O, P, arg, nameForError) {
+    const method = O[P];
+    if (method === undefined) {
+      return undefined;
+    }
+    if (typeof method !== 'function') {
+      throw new TypeError(errTmplMustBeFunctionOrUndefined(nameForError));
+    }
+
+    return callFunction(method, O, arg);
+  }
+
+
+  // Modified from PromiseInvokeOrNoop in spec
+  function PromiseCallOrNoop(O, P, arg, nameForError) {
+    let method;
+    try {
+      method = O[P];
+    } catch (methodE) {
+      return Promise_reject(methodE);
+    }
+
+    if (method === undefined) {
+      return Promise_resolve(undefined);
+    }
+
+    if (typeof method !== 'function') {
+      return Promise_reject(new TypeError(errTmplMustBeFunctionOrUndefined(nameForError)));
+    }
+
+    try {
+      return Promise_resolve(callFunction(method, O, arg));
+    } catch (e) {
+      return Promise_reject(e);
+    }
+  }
+
+  function CreateIterResultObject(value, done) { return {value, done}; }
+
+
+  //
+  // Additions to the global
+  //
+
+  defineProperty(global, 'ReadableStream', {
+    value: ReadableStream,
+    enumerable: false,
+    configurable: true,
+    writable: true
+  });
+
+  //
+  // Exports to Blink
+  //
+
+/*
+  binding.AcquireReadableStreamDefaultReader = AcquireReadableStreamDefaultReader;
+  binding.IsReadableStream = IsReadableStream;
+  binding.IsReadableStreamDisturbed = IsReadableStreamDisturbed;
+  binding.IsReadableStreamLocked = IsReadableStreamLocked;
+  binding.IsReadableStreamReadable = IsReadableStreamReadable;
+  binding.IsReadableStreamClosed = IsReadableStreamClosed;
+  binding.IsReadableStreamErrored = IsReadableStreamErrored;
+  binding.IsReadableStreamDefaultReader = IsReadableStreamDefaultReader;
+  binding.ReadableStreamDefaultReaderRead = ReadableStreamDefaultReaderRead;
+  binding.ReadableStreamTee = ReadableStreamTee;
+
+  binding.ReadableStreamDefaultControllerClose = ReadableStreamDefaultControllerClose;
+  binding.ReadableStreamDefaultControllerGetDesiredSize = ReadableStreamDefaultControllerGetDesiredSize;
+  binding.ReadableStreamDefaultControllerEnqueue = ReadableStreamDefaultControllerEnqueue;
+  binding.ReadableStreamDefaultControllerError = ReadableStreamDefaultControllerError;
+
+  binding.createReadableStreamWithExternalController =
+      (underlyingSource, strategy) => {
+        return new ReadableStream(
+            underlyingSource, strategy, createWithExternalControllerSentinel);
+      };
+*/
+})(this);
diff --git a/src/cobalt/trace_event/benchmark_internal.h b/src/cobalt/trace_event/benchmark_internal.h
index c6a13cd..f060a2d 100644
--- a/src/cobalt/trace_event/benchmark_internal.h
+++ b/src/cobalt/trace_event/benchmark_internal.h
@@ -62,18 +62,20 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
@@ -155,36 +157,40 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
     switch (measurement_type_2) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " flow duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " flow duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " in-scope duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " in-scope duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_2) +\
+                   " time between event starts in seconds", \
                    event_2_samples_));\
       } break;\
     }\
@@ -293,54 +299,60 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
     switch (measurement_type_2) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " flow duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " flow duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " in-scope duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " in-scope duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_2) +\
+                   " time between event starts in seconds", \
                    event_2_samples_));\
       } break;\
     }\
     switch (measurement_type_3) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " flow duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " flow duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " in-scope duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " in-scope duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_3) +\
+                   " time between event starts in seconds", \
                    event_3_samples_));\
       } break;\
     }\
@@ -477,72 +489,80 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
     switch (measurement_type_2) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " flow duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " flow duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " in-scope duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " in-scope duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_2) +\
+                   " time between event starts in seconds", \
                    event_2_samples_));\
       } break;\
     }\
     switch (measurement_type_3) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " flow duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " flow duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " in-scope duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " in-scope duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_3) +\
+                   " time between event starts in seconds", \
                    event_3_samples_));\
       } break;\
     }\
     switch (measurement_type_4) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " flow duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " flow duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " in-scope duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " in-scope duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_4) +\
+                   " time between event starts in seconds", \
                    event_4_samples_));\
       } break;\
     }\
@@ -706,90 +726,100 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
     switch (measurement_type_2) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " flow duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " flow duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " in-scope duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " in-scope duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_2) +\
+                   " time between event starts in seconds", \
                    event_2_samples_));\
       } break;\
     }\
     switch (measurement_type_3) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " flow duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " flow duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " in-scope duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " in-scope duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_3) +\
+                   " time between event starts in seconds", \
                    event_3_samples_));\
       } break;\
     }\
     switch (measurement_type_4) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " flow duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " flow duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " in-scope duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " in-scope duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_4) +\
+                   " time between event starts in seconds", \
                    event_4_samples_));\
       } break;\
     }\
     switch (measurement_type_5) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " flow duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " flow duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " in-scope duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " in-scope duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_5) +\
+                   " time between event starts in seconds", \
                    event_5_samples_));\
       } break;\
     }\
@@ -981,108 +1011,120 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
     switch (measurement_type_2) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " flow duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " flow duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " in-scope duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " in-scope duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_2) +\
+                   " time between event starts in seconds", \
                    event_2_samples_));\
       } break;\
     }\
     switch (measurement_type_3) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " flow duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " flow duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " in-scope duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " in-scope duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_3) +\
+                   " time between event starts in seconds", \
                    event_3_samples_));\
       } break;\
     }\
     switch (measurement_type_4) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " flow duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " flow duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " in-scope duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " in-scope duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_4) +\
+                   " time between event starts in seconds", \
                    event_4_samples_));\
       } break;\
     }\
     switch (measurement_type_5) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " flow duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " flow duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " in-scope duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " in-scope duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_5) +\
+                   " time between event starts in seconds", \
                    event_5_samples_));\
       } break;\
     }\
     switch (measurement_type_6) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " flow duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " flow duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " in-scope duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " in-scope duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_6) +\
+                   " time between event starts in seconds", \
                    event_6_samples_));\
       } break;\
     }\
@@ -1301,126 +1343,140 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
     switch (measurement_type_2) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " flow duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " flow duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " in-scope duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " in-scope duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_2) +\
+                   " time between event starts in seconds", \
                    event_2_samples_));\
       } break;\
     }\
     switch (measurement_type_3) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " flow duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " flow duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " in-scope duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " in-scope duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_3) +\
+                   " time between event starts in seconds", \
                    event_3_samples_));\
       } break;\
     }\
     switch (measurement_type_4) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " flow duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " flow duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " in-scope duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " in-scope duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_4) +\
+                   " time between event starts in seconds", \
                    event_4_samples_));\
       } break;\
     }\
     switch (measurement_type_5) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " flow duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " flow duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " in-scope duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " in-scope duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_5) +\
+                   " time between event starts in seconds", \
                    event_5_samples_));\
       } break;\
     }\
     switch (measurement_type_6) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " flow duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " flow duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " in-scope duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " in-scope duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_6) +\
+                   " time between event starts in seconds", \
                    event_6_samples_));\
       } break;\
     }\
     switch (measurement_type_7) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " flow duration in seconds",\
+            Result(std::string(event_name_7) +\
+                   " flow duration in seconds", \
                    event_7_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " in-scope duration in seconds",\
+            Result(std::string(event_name_7) +\
+                   " in-scope duration in seconds", \
                    event_7_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_7) +\
+                   " time between event starts in seconds", \
                    event_7_samples_));\
       } break;\
     }\
@@ -1667,144 +1723,160 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
     switch (measurement_type_2) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " flow duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " flow duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " in-scope duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " in-scope duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_2) +\
+                   " time between event starts in seconds", \
                    event_2_samples_));\
       } break;\
     }\
     switch (measurement_type_3) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " flow duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " flow duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " in-scope duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " in-scope duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_3) +\
+                   " time between event starts in seconds", \
                    event_3_samples_));\
       } break;\
     }\
     switch (measurement_type_4) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " flow duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " flow duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " in-scope duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " in-scope duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_4) +\
+                   " time between event starts in seconds", \
                    event_4_samples_));\
       } break;\
     }\
     switch (measurement_type_5) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " flow duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " flow duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " in-scope duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " in-scope duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_5) +\
+                   " time between event starts in seconds", \
                    event_5_samples_));\
       } break;\
     }\
     switch (measurement_type_6) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " flow duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " flow duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " in-scope duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " in-scope duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_6) +\
+                   " time between event starts in seconds", \
                    event_6_samples_));\
       } break;\
     }\
     switch (measurement_type_7) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " flow duration in seconds",\
+            Result(std::string(event_name_7) +\
+                   " flow duration in seconds", \
                    event_7_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " in-scope duration in seconds",\
+            Result(std::string(event_name_7) +\
+                   " in-scope duration in seconds", \
                    event_7_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_7) +\
+                   " time between event starts in seconds", \
                    event_7_samples_));\
       } break;\
     }\
     switch (measurement_type_8) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_8) + " flow duration in seconds",\
+            Result(std::string(event_name_8) +\
+                   " flow duration in seconds", \
                    event_8_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_8) + " in-scope duration in seconds",\
+            Result(std::string(event_name_8) +\
+                   " in-scope duration in seconds", \
                    event_8_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_8) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_8) +\
+                   " time between event starts in seconds", \
                    event_8_samples_));\
       } break;\
     }\
@@ -2078,162 +2150,180 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
     switch (measurement_type_2) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " flow duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " flow duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " in-scope duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " in-scope duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_2) +\
+                   " time between event starts in seconds", \
                    event_2_samples_));\
       } break;\
     }\
     switch (measurement_type_3) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " flow duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " flow duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " in-scope duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " in-scope duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_3) +\
+                   " time between event starts in seconds", \
                    event_3_samples_));\
       } break;\
     }\
     switch (measurement_type_4) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " flow duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " flow duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " in-scope duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " in-scope duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_4) +\
+                   " time between event starts in seconds", \
                    event_4_samples_));\
       } break;\
     }\
     switch (measurement_type_5) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " flow duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " flow duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " in-scope duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " in-scope duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_5) +\
+                   " time between event starts in seconds", \
                    event_5_samples_));\
       } break;\
     }\
     switch (measurement_type_6) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " flow duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " flow duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " in-scope duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " in-scope duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_6) +\
+                   " time between event starts in seconds", \
                    event_6_samples_));\
       } break;\
     }\
     switch (measurement_type_7) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " flow duration in seconds",\
+            Result(std::string(event_name_7) +\
+                   " flow duration in seconds", \
                    event_7_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " in-scope duration in seconds",\
+            Result(std::string(event_name_7) +\
+                   " in-scope duration in seconds", \
                    event_7_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_7) +\
+                   " time between event starts in seconds", \
                    event_7_samples_));\
       } break;\
     }\
     switch (measurement_type_8) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_8) + " flow duration in seconds",\
+            Result(std::string(event_name_8) +\
+                   " flow duration in seconds", \
                    event_8_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_8) + " in-scope duration in seconds",\
+            Result(std::string(event_name_8) +\
+                   " in-scope duration in seconds", \
                    event_8_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_8) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_8) +\
+                   " time between event starts in seconds", \
                    event_8_samples_));\
       } break;\
     }\
     switch (measurement_type_9) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_9) + " flow duration in seconds",\
+            Result(std::string(event_name_9) +\
+                   " flow duration in seconds", \
                    event_9_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_9) + " in-scope duration in seconds",\
+            Result(std::string(event_name_9) +\
+                   " in-scope duration in seconds", \
                    event_9_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_9) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_9) +\
+                   " time between event starts in seconds", \
                    event_9_samples_));\
       } break;\
     }\
@@ -2535,181 +2625,200 @@
     switch (measurement_type_1) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " flow duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " flow duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " in-scope duration in seconds",\
+            Result(std::string(event_name_1) +\
+                   " in-scope duration in seconds", \
                    event_1_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_1) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_1) +\
+                   " time between event starts in seconds", \
                    event_1_samples_));\
       } break;\
     }\
     switch (measurement_type_2) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " flow duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " flow duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " in-scope duration in seconds",\
+            Result(std::string(event_name_2) +\
+                   " in-scope duration in seconds", \
                    event_2_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_2) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_2) +\
+                   " time between event starts in seconds", \
                    event_2_samples_));\
       } break;\
     }\
     switch (measurement_type_3) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " flow duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " flow duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " in-scope duration in seconds",\
+            Result(std::string(event_name_3) +\
+                   " in-scope duration in seconds", \
                    event_3_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_3) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_3) +\
+                   " time between event starts in seconds", \
                    event_3_samples_));\
       } break;\
     }\
     switch (measurement_type_4) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " flow duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " flow duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " in-scope duration in seconds",\
+            Result(std::string(event_name_4) +\
+                   " in-scope duration in seconds", \
                    event_4_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_4) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_4) +\
+                   " time between event starts in seconds", \
                    event_4_samples_));\
       } break;\
     }\
     switch (measurement_type_5) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " flow duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " flow duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " in-scope duration in seconds",\
+            Result(std::string(event_name_5) +\
+                   " in-scope duration in seconds", \
                    event_5_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_5) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_5) +\
+                   " time between event starts in seconds", \
                    event_5_samples_));\
       } break;\
     }\
     switch (measurement_type_6) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " flow duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " flow duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " in-scope duration in seconds",\
+            Result(std::string(event_name_6) +\
+                   " in-scope duration in seconds", \
                    event_6_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_6) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_6) +\
+                   " time between event starts in seconds", \
                    event_6_samples_));\
       } break;\
     }\
     switch (measurement_type_7) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " flow duration in seconds",\
+            Result(std::string(event_name_7) +\
+                   " flow duration in seconds", \
                    event_7_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " in-scope duration in seconds",\
+            Result(std::string(event_name_7) +\
+                   " in-scope duration in seconds", \
                    event_7_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_7) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_7) +\
+                   " time between event starts in seconds", \
                    event_7_samples_));\
       } break;\
     }\
     switch (measurement_type_8) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_8) + " flow duration in seconds",\
+            Result(std::string(event_name_8) +\
+                   " flow duration in seconds", \
                    event_8_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_8) + " in-scope duration in seconds",\
+            Result(std::string(event_name_8) +\
+                   " in-scope duration in seconds", \
                    event_8_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_8) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_8) +\
+                   " time between event starts in seconds", \
                    event_8_samples_));\
       } break;\
     }\
     switch (measurement_type_9) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_9) + " flow duration in seconds",\
+            Result(std::string(event_name_9) +\
+                   " flow duration in seconds", \
                    event_9_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_9) + " in-scope duration in seconds",\
+            Result(std::string(event_name_9) +\
+                   " in-scope duration in seconds", \
                    event_9_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_9) + " time between event starts in \
-                seconds",\
+            Result(std::string(event_name_9) +\
+                   " time between event starts in seconds", \
                    event_9_samples_));\
       } break;\
     }\
     switch (measurement_type_10) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_10) + " flow duration in seconds",\
+            Result(std::string(event_name_10) +\
+                   " flow duration in seconds", \
                    event_10_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_10) + " in-scope duration in \
-                seconds",\
+            Result(std::string(event_name_10) +\
+                   " in-scope duration in seconds", \
                    event_10_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_10) + " time between event starts \
-                in seconds",\
+            Result(std::string(event_name_10) +\
+                   " time between event starts in seconds", \
                    event_10_samples_));\
       } break;\
     }\
diff --git a/src/cobalt/trace_event/benchmark_internal.h.pump b/src/cobalt/trace_event/benchmark_internal.h.pump
index 80121f3..9a9d9fa 100644
--- a/src/cobalt/trace_event/benchmark_internal.h.pump
+++ b/src/cobalt/trace_event/benchmark_internal.h.pump
@@ -81,17 +81,20 @@
     switch (measurement_type_$(ARG)) {\
       case cobalt::trace_event::FLOW_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_$(ARG)) + " flow duration in seconds",\
+            Result(std::string(event_name_$(ARG)) +\
+                   " flow duration in seconds", \
                    event_$(ARG)_samples_));\
       } break;\
       case cobalt::trace_event::IN_SCOPE_DURATION: {\
         results.push_back(\
-            Result(std::string(event_name_$(ARG)) + " in-scope duration in seconds",\
+            Result(std::string(event_name_$(ARG)) +\
+                   " in-scope duration in seconds", \
                    event_$(ARG)_samples_));\
       } break;\
       case cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS: {\
         results.push_back(\
-            Result(std::string(event_name_$(ARG)) + " time between event starts in seconds",\
+            Result(std::string(event_name_$(ARG)) +\
+                   " time between event starts in seconds", \
                    event_$(ARG)_samples_));\
       } break;\
     }\
diff --git a/src/nb/README.md b/src/nb/README.md
new file mode 100644
index 0000000..ee6c322
--- /dev/null
+++ b/src/nb/README.md
@@ -0,0 +1,14 @@
+# Nanobase
+
+Nanobase is essentially a minified/lightweight version of Chromium's base
+library, though it does include utility classes that Chromium's base does not.
+
+Its usefulness is found in the fact that its only dependency is starboard,
+making it very portable and easy to include in projects that don't want
+to depend on Chromium's base (which currently would require the Chromium
+repository to be available and that may not be desirable).
+
+An example project that depends on nb is glimp, which was the project that
+initiated the creation of nb.  We wanted glimp to be portable alongside
+Starboard, and so in order to enable that, we wanted to avoid a dependency
+on Chromium's base.
diff --git a/src/nb/analytics/memory_tracker_helpers.cc b/src/nb/analytics/memory_tracker_helpers.cc
index 4ec1de7..4d1f7ad 100644
--- a/src/nb/analytics/memory_tracker_helpers.cc
+++ b/src/nb/analytics/memory_tracker_helpers.cc
@@ -200,7 +200,8 @@
        it != pointer_map_.end(); ++it) {
     const AllocationRecord& rec = it->second;
     AllocationGroup* group = rec.allocation_group;
-    group->AddAllocation(-rec.size);
+    const int64_t size = static_cast<int64_t>(rec.size);
+    group->AddAllocation(-size);
   }
   return pointer_map_.clear();
 }
@@ -260,9 +261,8 @@
   return true;
 }
 
-size_t ConcurrentAllocationMap::hash_ptr(const void* ptr) {
+uint32_t ConcurrentAllocationMap::hash_ptr(const void* ptr) {
   uintptr_t val = reinterpret_cast<uintptr_t>(ptr);
-
   return RuntimeHash32(reinterpret_cast<const char*>(&val), sizeof(val));
 }
 
diff --git a/src/nb/analytics/memory_tracker_helpers.h b/src/nb/analytics/memory_tracker_helpers.h
index 653a47f..70cf32b 100644
--- a/src/nb/analytics/memory_tracker_helpers.h
+++ b/src/nb/analytics/memory_tracker_helpers.h
@@ -205,7 +205,7 @@
  private:
   SB_DISALLOW_COPY_AND_ASSIGN(ConcurrentAllocationMap);
   // Takes a pointer and generates a hash.
-  static size_t hash_ptr(const void* ptr);
+  static uint32_t hash_ptr(const void* ptr);
 
   int ToIndex(const void* ptr) const;
   AtomicAllocationMap pointer_map_array_[kNumElements];
diff --git a/src/nb/memory_scope_test.cc b/src/nb/memory_scope_test.cc
index e734c2f..d9180f9 100644
--- a/src/nb/memory_scope_test.cc
+++ b/src/nb/memory_scope_test.cc
@@ -227,16 +227,7 @@
                             true};          // true allows caching.

 

   NbPushMemoryScope(&info);

-

-  ASSERT_FALSE(test_memory_reporter()->stack_thread_local()->empty());

-  NbMemoryScopeInfo* info_ptr =

-      test_memory_reporter()->stack_thread_local()->front();

-

-  EXPECT_EQ(&info, info_ptr);

-  EXPECT_STREQ(info.file_name_, file_name);

-  EXPECT_STREQ(info.function_name_, function_name);

-  EXPECT_EQ(info.line_number_, line_number);

-

+  ASSERT_TRUE(test_memory_reporter()->stack_thread_local()->empty());

   NbPopMemoryScope();

   EXPECT_TRUE(test_memory_reporter()->stack_thread_local()->empty());

 }

diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index a549295..742cded 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -60,6 +60,7 @@
 
 // Adds kSbSystemPropertyUserAgentAuxField to the SbSystemPropertyId
 // enum to allow platform-specific  User-Agent suffix.
+// NOLINTNEXTLINE(whitespace/line_length)
 #define SB_USER_AGENT_AUX_SYSTEM_PROPERTY_API_VERSION SB_EXPERIMENTAL_API_VERSION
 
 // Introduce 'starboard/speech_recognizer.h'
@@ -67,6 +68,10 @@
 // speech recognizer feature.
 #define SB_SPEECH_RECOGNIZER_API_VERSION SB_EXPERIMENTAL_API_VERSION
 
+// Introduce pointer (mouse) input support. This extends the SbInput interface
+// with some enum values and data members to allow mouse, wheel, and more
+// generic pointer input.
+#define SB_POINTER_INPUT_API_VERSION SB_EXPERIMENTAL_API_VERSION
 // --- Common Detected Features ----------------------------------------------
 
 #if defined(__GNUC__)
diff --git a/src/starboard/input.h b/src/starboard/input.h
index 10c919a..c6e0fd7 100644
--- a/src/starboard/input.h
+++ b/src/starboard/input.h
@@ -33,9 +33,9 @@
 // device type produces correspond to |SbInputEventType| values.
 typedef enum SbInputDeviceType {
   // Input from a gesture-detection mechanism. Examples include Kinect,
-  // Wiimotes, LG Magic Remotes, etc...
+  // Wiimotes, etc...
   //
-  // Produces |Move|, |Grab|, |Ungrab|, |Press| and |Unpress| events.
+  // Produces |Move|, |Press| and |Unpress| events.
   kSbInputDeviceTypeGesture,
 
   // Input from a gamepad, following the layout provided in the W3C Web Gamepad
@@ -49,12 +49,14 @@
   // Produces |Press| and |Unpress| events.
   kSbInputDeviceTypeKeyboard,
 
+#if SB_API_VERSION <= 4
   // Input from a microphone that would provide audio data to the caller, who
   // may then find some way to detect speech or other sounds within it. It may
   // have processed or filtered the audio in some way before it arrives.
   //
   // Produces |Audio| events.
   kSbInputDeviceTypeMicrophone,
+#endif
 
   // Input from a traditional mouse.
   //
@@ -66,12 +68,14 @@
   // Produces |Press| and |Unpress| events.
   kSbInputDeviceTypeRemote,
 
+#if SB_API_VERSION <= 4
   // Input from a speech command analyzer, which is some hardware or software
   // that, given a set of known phrases, activates when one of the registered
   // phrases is heard.
   //
   // Produces |Command| events.
   kSbInputDeviceTypeSpeechCommand,
+#endif
 
   // Input from a single- or multi-touchscreen.
   //
@@ -86,15 +90,15 @@
 
 // The action that an input event represents.
 typedef enum SbInputEventType {
+#if SB_API_VERSION <= 4
   // Receipt of Audio. Some audio data was received by the input microphone.
   kSbInputEventTypeAudio,
-
   // Receipt of a command. A command was received from some semantic source,
   // like a speech recognizer.
   kSbInputEventTypeCommand,
-
   // Grab activation. This event type is deprecated.
   kSbInputEventTypeGrab,
+#endif
 
   // Device Movement. In the case of |Mouse|, and perhaps |Gesture|, the
   // movement tracks an absolute cursor position. In the case of |TouchPad|,
@@ -108,12 +112,19 @@
   // Injecting repeat presses is up to the client.
   kSbInputEventTypePress,
 
+#if SB_API_VERSION <= 4
   // Grab deactivation. This event type is deprecated.
   kSbInputEventTypeUngrab,
+#endif
 
   // Key or button deactivation. The counterpart to the |Press| event, this
   // event is sent when the key or button being pressed is released.
   kSbInputEventTypeUnpress,
+
+#if SB_API_VERSION >= SB_POINTER_INPUT_API_VERSION
+  // Wheel movement. Provides relative movements of the |Mouse| wheel.
+  kSbInputEventTypeWheel,
+#endif
 } SbInputEventType;
 
 // A 2-dimensional vector used to represent points and motion vectors.
@@ -168,6 +179,29 @@
   // The relative motion vector of this input. The value is |0| if this data
   // is not applicable.
   SbInputVector delta;
+
+#if SB_API_VERSION >= SB_POINTER_INPUT_API_VERSION
+  // The normalized pressure of the pointer input in the range of
+  // [0,1], where 0 and 1 represent the minimum and maximum pressure
+  // the hardware is capable of detecting, respectively. Use NaN for
+  // devices that do not report pressure. This value is only used for input
+  // events with device type mouse or touch screen.
+  float pressure;
+
+  // The (width, height) of the contact geometry of the pointer.
+  // This defines the limits of the values reported for the pointer
+  // coordinates in the 'position' field. If (NaN, NaN) is specified,
+  // the width and height of the window will be used. This value is only used
+  // for input events with device type mouse or touch screen.
+  SbInputVector size;
+
+  // The (x, y) angle in degrees, in the range of [-90, 90] of the
+  // pointer, relative to the z axis. Positive values are for tilt
+  // to the right (x), and towards the user (y). Use (NaN, NaN) for
+  // devices that do not report tilt. This value is only used for input events
+  // with device type mouse or touch screen.
+  SbInputVector tilt;
+#endif
 } SbInputData;
 
 #ifdef __cplusplus
diff --git a/src/starboard/key.h b/src/starboard/key.h
index b50608f..8191acd 100644
--- a/src/starboard/key.h
+++ b/src/starboard/key.h
@@ -19,6 +19,8 @@
 #ifndef STARBOARD_KEY_H_
 #define STARBOARD_KEY_H_
 
+#include "starboard/configuration.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -279,6 +281,13 @@
   kSbKeyModifiersCtrl = 1 << 1,
   kSbKeyModifiersMeta = 1 << 2,
   kSbKeyModifiersShift = 1 << 3,
+#if SB_API_VERSION >= SB_POINTER_INPUT_API_VERSION
+  kSbKeyModifiersPointerButtonLeft = 1 << 4,
+  kSbKeyModifiersPointerButtonRight = 1 << 5,
+  kSbKeyModifiersPointerButtonMiddle = 1 << 6,
+  kSbKeyModifiersPointerButtonBack = 1 << 7,
+  kSbKeyModifiersPointerButtonForward = 1 << 8,
+#endif
 } SbKeyModifiers;
 
 #ifdef __cplusplus
diff --git a/src/starboard/linux/x64x11/clang/3.6/compiler_flags.gypi b/src/starboard/linux/x64x11/clang/3.6/compiler_flags.gypi
index eca2f8e..5cde2f7 100644
--- a/src/starboard/linux/x64x11/clang/3.6/compiler_flags.gypi
+++ b/src/starboard/linux/x64x11/clang/3.6/compiler_flags.gypi
@@ -123,11 +123,7 @@
       '-std=c99',
     ],
     'cflags_cc': [
-      # Limit to gnu++98. This allows Linux to be a canary build for any
-      # C++11 features that are not supported on some platforms' compilers.
-      # We do allow ourselves GNU extensions, which are assumed to exist
-      # by Chromium code.
-      '-std=gnu++98',
+      '-std=gnu++11',
     ],
     'target_conditions': [
       ['cobalt_code==1', {
@@ -149,6 +145,8 @@
           '-Wno-unused-parameter',
           # Do not warn for implicit type conversions that may change a value.
           '-Wno-conversion',
+          # Do not warn about an implicit exception spec mismatch.
+          '-Wno-implicit-exception-spec-mismatch',
         ],
       }],
       ['use_asan==1', {
diff --git a/src/starboard/nplb/condition_variable_wait_timed_test.cc b/src/starboard/nplb/condition_variable_wait_timed_test.cc
index 7507a91..8698e37 100644
--- a/src/starboard/nplb/condition_variable_wait_timed_test.cc
+++ b/src/starboard/nplb/condition_variable_wait_timed_test.cc
@@ -28,6 +28,8 @@
                      TakeThenSignalEntryPoint, context);
 
   const SbTime kDelay = kSbTimeMillisecond * 10;
+  // Allow millisecond-level precision.
+  const SbTime kPrecision = kSbTimeMillisecond;
 
   // We know the thread hasn't signaled the condition variable yet, and won't
   // unless we tell it, so it should wait at least the whole delay time.
@@ -38,8 +40,8 @@
         &context->condition, &context->mutex, kDelay);
     EXPECT_EQ(kSbConditionVariableTimedOut, result);
     SbTimeMonotonic elapsed = SbTimeGetMonotonicNow() - start;
-    EXPECT_LE(kDelay, elapsed);
-    EXPECT_GT(kDelay * 2, elapsed);
+    EXPECT_LE(kDelay, elapsed + kPrecision);
+    EXPECT_GT(kDelay * 2, elapsed - kPrecision);
     EXPECT_TRUE(SbMutexRelease(&context->mutex));
   }
 
diff --git a/src/starboard/nplb/cryptography_transform_gcm_test.cc b/src/starboard/nplb/cryptography_transform_gcm_test.cc
index 819b63d..d2674a4 100644
--- a/src/starboard/nplb/cryptography_transform_gcm_test.cc
+++ b/src/starboard/nplb/cryptography_transform_gcm_test.cc
@@ -310,7 +310,7 @@
   }
 
   *out = buf.Pass();
-  *out_len = len / 2;
+  *out_len = static_cast<int>(len / 2);
 }
 
 std::string hexdump(const void *in, int len) {
diff --git a/src/starboard/nplb/cryptography_transform_test.cc b/src/starboard/nplb/cryptography_transform_test.cc
index ae916a7..fc44126 100644
--- a/src/starboard/nplb/cryptography_transform_test.cc
+++ b/src/starboard/nplb/cryptography_transform_test.cc
@@ -45,8 +45,8 @@
     return;
   }
 
-  const int kInputSize = SbStringGetLength(kClearText);
-  const int kBufferSize = sizeof(kClearText);
+  const int kInputSize = static_cast<int>(SbStringGetLength(kClearText));
+  const int kBufferSize = static_cast<int>(sizeof(kClearText));
   char* cipher_text = new char[kBufferSize];
   SbMemorySet(cipher_text, 0, kBufferSize);
   int count = SbCryptographyTransform(transformer, kClearText, kInputSize,
diff --git a/src/starboard/nplb/directory_create_test.cc b/src/starboard/nplb/directory_create_test.cc
index 2b8fb21..738bae9 100644
--- a/src/starboard/nplb/directory_create_test.cc
+++ b/src/starboard/nplb/directory_create_test.cc
@@ -55,15 +55,30 @@
   EXPECT_TRUE(SbDirectoryCanOpen(path.c_str()));
 }
 
-TEST(SbDirectoryCreateTest, SunnyDayRoot) {
-  const char* kRootPath = SB_FILE_SEP_STRING;
-  EXPECT_TRUE(SbDirectoryCanOpen(kRootPath));
-  EXPECT_TRUE(SbDirectoryCreate(kRootPath));
-  EXPECT_TRUE(SbDirectoryCanOpen(kRootPath));
+TEST(SbDirectoryCreateTest, SunnyDayTempDirectory) {
+  const int kMaxFilePath = SB_FILE_MAX_PATH;
+  char temp_path[kMaxFilePath];
+  bool system_path_success =
+      SbSystemGetPath(kSbSystemPathTempDirectory, temp_path, kMaxFilePath);
+  ASSERT_TRUE(system_path_success);
+  EXPECT_TRUE(SbDirectoryCanOpen(temp_path));
+  EXPECT_TRUE(SbDirectoryCreate(temp_path));
+  EXPECT_TRUE(SbDirectoryCanOpen(temp_path));
+}
 
-  EXPECT_TRUE(SbDirectoryCanOpen(kManyFileSeparators));
-  EXPECT_TRUE(SbDirectoryCreate(kManyFileSeparators));
-  EXPECT_TRUE(SbDirectoryCanOpen(kManyFileSeparators));
+TEST(SbDirectoryCreateTest, SunnyDayTempDirectoryManySeparators) {
+  const int kMaxFilePath = SB_FILE_MAX_PATH;
+  char temp_path[kMaxFilePath];
+  bool system_path_success =
+      SbSystemGetPath(kSbSystemPathTempDirectory, temp_path, kMaxFilePath);
+  ASSERT_TRUE(system_path_success);
+  const int new_size =
+      SbStringConcat(temp_path, kManyFileSeparators, kMaxFilePath);
+  ASSERT_LT(new_size, kMaxFilePath);
+
+  EXPECT_TRUE(SbDirectoryCanOpen(temp_path));
+  EXPECT_TRUE(SbDirectoryCreate(temp_path));
+  EXPECT_TRUE(SbDirectoryCanOpen(temp_path));
 }
 
 TEST(SbDirectoryCreateTest, FailureNullPath) {
diff --git a/src/starboard/nplb/directory_open_test.cc b/src/starboard/nplb/directory_open_test.cc
index 8eff98f..f37dd9c 100644
--- a/src/starboard/nplb/directory_open_test.cc
+++ b/src/starboard/nplb/directory_open_test.cc
@@ -72,7 +72,7 @@
   EXPECT_TRUE(SbFileExists(path.c_str()));
 
   // Funny way to make sure the directory seems valid but doesn't exist.
-  int len = path.length();
+  int len = static_cast<int>(path.length());
   if (path[len - 1] != 'z') {
     path[len - 1] = 'z';
   } else {
diff --git a/src/starboard/nplb/file_read_test.cc b/src/starboard/nplb/file_read_test.cc
index a4c828d..23c12f5 100644
--- a/src/starboard/nplb/file_read_test.cc
+++ b/src/starboard/nplb/file_read_test.cc
@@ -140,7 +140,7 @@
   }
 
   // Read off the end of the file.
-  int position = SbFileSeek(file, kSbFileFromEnd, 0);
+  int position = static_cast<int>(SbFileSeek(file, kSbFileFromEnd, 0));
   EXPECT_EQ(kFileSize, position);
   int bytes_read = TypeParam::Read(file, buffer, kBufferLength);
   EXPECT_EQ(0, bytes_read);
@@ -210,7 +210,8 @@
   }
 
   // Read from the middle of the file.
-  int position = SbFileSeek(file, kSbFileFromBegin, kFileSize / 4);
+  int position =
+      static_cast<int>(SbFileSeek(file, kSbFileFromBegin, kFileSize / 4));
   EXPECT_EQ(kFileSize / 4, position);
   int bytes_read = TypeParam::Read(file, buffer, kBufferLength);
   EXPECT_GE(kBufferLength, bytes_read);
diff --git a/src/starboard/nplb/file_seek_test.cc b/src/starboard/nplb/file_seek_test.cc
index 0debe02..f8f41aa 100644
--- a/src/starboard/nplb/file_seek_test.cc
+++ b/src/starboard/nplb/file_seek_test.cc
@@ -23,16 +23,18 @@
 namespace {
 
 TEST(SbFileSeekTest, InvalidFileErrors) {
-  int result = SbFileSeek(kSbFileInvalid, kSbFileFromBegin, 50);
+  int result =
+      static_cast<int>(SbFileSeek(kSbFileInvalid, kSbFileFromBegin, 50));
   EXPECT_EQ(-1, result);
 
-  result = SbFileSeek(kSbFileInvalid, kSbFileFromEnd, -50);
+  result = static_cast<int>(SbFileSeek(kSbFileInvalid, kSbFileFromEnd, -50));
   EXPECT_EQ(-1, result);
 
-  result = SbFileSeek(kSbFileInvalid, kSbFileFromCurrent, -50);
+  result =
+      static_cast<int>(SbFileSeek(kSbFileInvalid, kSbFileFromCurrent, -50));
   EXPECT_EQ(-1, result);
 
-  result = SbFileSeek(kSbFileInvalid, kSbFileFromCurrent, 50);
+  result = static_cast<int>(SbFileSeek(kSbFileInvalid, kSbFileFromCurrent, 50));
   EXPECT_EQ(-1, result);
 }
 
diff --git a/src/starboard/nplb/file_truncate_test.cc b/src/starboard/nplb/file_truncate_test.cc
index c4d7a06..c21cad5 100644
--- a/src/starboard/nplb/file_truncate_test.cc
+++ b/src/starboard/nplb/file_truncate_test.cc
@@ -82,13 +82,13 @@
     EXPECT_EQ(kStartSize, info.size);
   }
 
-  int position = SbFileSeek(file, kSbFileFromCurrent, 0);
+  int position = static_cast<int>(SbFileSeek(file, kSbFileFromCurrent, 0));
   EXPECT_EQ(0, position);
 
   bool result = SbFileTruncate(file, kEndSize);
   EXPECT_TRUE(result);
 
-  position = SbFileSeek(file, kSbFileFromCurrent, 0);
+  position = static_cast<int>(SbFileSeek(file, kSbFileFromCurrent, 0));
   EXPECT_EQ(0, position);
 
   {
diff --git a/src/starboard/nplb/file_write_test.cc b/src/starboard/nplb/file_write_test.cc
index e503a86..1b3eefc 100644
--- a/src/starboard/nplb/file_write_test.cc
+++ b/src/starboard/nplb/file_write_test.cc
@@ -100,7 +100,7 @@
   // Tests reading and writing from same opened file.
   bool result = SbFileFlush(file);
   ASSERT_TRUE(result);
-  int position = SbFileSeek(file, kSbFileFromBegin, 0);
+  int position = static_cast<int>(SbFileSeek(file, kSbFileFromBegin, 0));
   ASSERT_EQ(0, position);
 
   // Read and check the whole file.
diff --git a/src/starboard/nplb/rwlock_test.cc b/src/starboard/nplb/rwlock_test.cc
index b31df05..6ef24fd 100644
--- a/src/starboard/nplb/rwlock_test.cc
+++ b/src/starboard/nplb/rwlock_test.cc
@@ -199,7 +199,7 @@
   ThreadRWLockStressTest::SharedData shared_data;
   std::vector<AbstractTestThread*> threads;
 
-  for (size_t i = 0; i < NUM_STRESS_THREADS; ++i) {
+  for (int i = 0; i < NUM_STRESS_THREADS; ++i) {
     int32_t start_value = i * kNumValuesEachThread;
     int32_t end_value = (i + 1) * kNumValuesEachThread;
     ThreadRWLockStressTest* thread =
diff --git a/src/starboard/nplb/semaphore_test.cc b/src/starboard/nplb/semaphore_test.cc
index 05de364..e81b762 100644
--- a/src/starboard/nplb/semaphore_test.cc
+++ b/src/starboard/nplb/semaphore_test.cc
@@ -90,9 +90,8 @@
   thread.Join();
 
   EXPECT_TRUE(thread.result_signaled_);
-  EXPECT_NEAR(thread.result_wait_time_,
-              wait_time / 2,
-              kSbTimeMillisecond * 10);  // Error threshold
+  EXPECT_NEAR(thread.result_wait_time_ * 1.0, wait_time * 0.5,
+              kSbTimeMillisecond * 10.0);  // Error threshold
 }
 
 double IsDoubleNear(double first, double second, double diff_threshold) {
@@ -120,7 +119,8 @@
     thread.Join();
     EXPECT_FALSE(thread.result_signaled_);
 
-    if (IsDoubleNear(wait_time, thread.result_wait_time_, kTimeThreshold)) {
+    if (IsDoubleNear(1.0 * wait_time, 1.0 * thread.result_wait_time_,
+                     kTimeThreshold * 1.0)) {
       return;  // Test passed.
     }
   }
diff --git a/src/starboard/nplb/string_concat_test.cc b/src/starboard/nplb/string_concat_test.cc
index 158390c..0e3af9a 100644
--- a/src/starboard/nplb/string_concat_test.cc
+++ b/src/starboard/nplb/string_concat_test.cc
@@ -24,8 +24,8 @@
 
 void TestConcat(const char* initial, const char* source, bool is_short) {
   const int kDestinationOffset = 16;
-  int initial_length = SbStringGetLength(initial);
-  int source_length = SbStringGetLength(source);
+  int initial_length = static_cast<int>(SbStringGetLength(initial));
+  int source_length = static_cast<int>(SbStringGetLength(source));
   int destination_size =
       initial_length + source_length + kDestinationOffset * 2;
   int destination_limit = initial_length + source_length + 1;
diff --git a/src/starboard/nplb/string_concat_wide_test.cc b/src/starboard/nplb/string_concat_wide_test.cc
index f4367d7..9713411 100644
--- a/src/starboard/nplb/string_concat_wide_test.cc
+++ b/src/starboard/nplb/string_concat_wide_test.cc
@@ -22,8 +22,8 @@
 
 void TestConcat(const wchar_t* initial, const wchar_t* source, bool is_short) {
   const int kDestinationOffset = 16;
-  int initial_length = SbStringGetLengthWide(initial);
-  int source_length = SbStringGetLengthWide(source);
+  int initial_length = static_cast<int>(SbStringGetLengthWide(initial));
+  int source_length = static_cast<int>(SbStringGetLengthWide(source));
   int destination_size =
       initial_length + source_length + kDestinationOffset * 2;
   int destination_limit = initial_length + source_length + 1;
diff --git a/src/starboard/nplb/string_copy_test.cc b/src/starboard/nplb/string_copy_test.cc
index 00e8e83..0fe6d9f 100644
--- a/src/starboard/nplb/string_copy_test.cc
+++ b/src/starboard/nplb/string_copy_test.cc
@@ -23,7 +23,7 @@
 
 void TestCopy(const char* source, bool is_short) {
   const int kDestinationOffset = 16;
-  int source_length = SbStringGetLength(source);
+  int source_length = static_cast<int>(SbStringGetLength(source));
   int destination_size = source_length + kDestinationOffset * 2;
   int destination_limit = source_length + 1;
   if (is_short) {
diff --git a/src/starboard/nplb/string_copy_wide_test.cc b/src/starboard/nplb/string_copy_wide_test.cc
index 0a98d75..9a682b5 100644
--- a/src/starboard/nplb/string_copy_wide_test.cc
+++ b/src/starboard/nplb/string_copy_wide_test.cc
@@ -21,7 +21,7 @@
 
 void TestCopy(const wchar_t* source, bool is_short) {
   const int kDestinationOffset = 16;
-  int source_length = SbStringGetLengthWide(source);
+  int source_length = static_cast<int>(SbStringGetLengthWide(source));
   int destination_size = source_length + kDestinationOffset * 2;
   int destination_limit = source_length + 1;
   if (is_short) {
diff --git a/src/starboard/nplb/system_get_path_test.cc b/src/starboard/nplb/system_get_path_test.cc
index 2e9ddf0..ea36035 100644
--- a/src/starboard/nplb/system_get_path_test.cc
+++ b/src/starboard/nplb/system_get_path_test.cc
@@ -37,7 +37,7 @@
   }
   if (result) {
     EXPECT_NE('\xCD', path[0]) << LOCAL_CONTEXT;
-    int len = strlen(path);
+    int len = static_cast<int>(strlen(path));
     EXPECT_GT(len, 0) << LOCAL_CONTEXT;
   } else {
     EXPECT_EQ('\xCD', path[0]) << LOCAL_CONTEXT;
diff --git a/src/starboard/nplb/system_get_property_test.cc b/src/starboard/nplb/system_get_property_test.cc
index ef4078f..e27b2ce 100644
--- a/src/starboard/nplb/system_get_property_test.cc
+++ b/src/starboard/nplb/system_get_property_test.cc
@@ -54,7 +54,7 @@
   }
   if (result) {
     EXPECT_NE('\xCD', value[0]) << LOCAL_CONTEXT;
-    int len = SbStringGetLength(value);
+    int len = static_cast<int>(SbStringGetLength(value));
     EXPECT_GT(len, 0) << LOCAL_CONTEXT;
   } else {
     EXPECT_EQ('\xCD', value[0]) << LOCAL_CONTEXT;
diff --git a/src/starboard/nplb/thread_get_id_test.cc b/src/starboard/nplb/thread_get_id_test.cc
index 4ecf448..a2ef7d8 100644
--- a/src/starboard/nplb/thread_get_id_test.cc
+++ b/src/starboard/nplb/thread_get_id_test.cc
@@ -46,7 +46,7 @@
   for (int i = 0; i < kThreads; ++i) {
     void* result = NULL;
     EXPECT_TRUE(SbThreadJoin(threads[i], &result));
-    SbThreadId id = nplb::FromVoid(result);
+    SbThreadId id = static_cast<SbThreadId>(nplb::FromVoid(result));
     EXPECT_NE(id, SbThreadGetId());
     thread_ids[i] = id;
   }
diff --git a/src/starboard/nplb/thread_sleep_test.cc b/src/starboard/nplb/thread_sleep_test.cc
index 626f185..0bebdb9 100644
--- a/src/starboard/nplb/thread_sleep_test.cc
+++ b/src/starboard/nplb/thread_sleep_test.cc
@@ -20,6 +20,9 @@
 namespace nplb {
 namespace {
 
+// Allow millisecond-level precision.
+const SbTime kPrecision = kSbTimeMillisecond;
+
 TEST(SbThreadSleepTest, SunnyDay) {
   SbThreadSleep(0);
   // Well, my work here is done.
@@ -30,13 +33,15 @@
 // the thread can wake up, something I completely sympathize with.
 TEST(SbThreadSleepTest, SunnyDayAtLeastDelay) {
   const int kTrials = 12;
+  const int64_t one = 1;
   for (int trial = 0; trial < kTrials; ++trial) {
     // This tests several delays, between about 15 to about 4 milliseconds.
-    const SbTime kDelay = kSbTimeSecond / (1 << ((trial % 3) + 6));
+    const SbTime kDelay = kSbTimeSecond / (one << ((trial % 3) + 6));
     SbTimeMonotonic start = SbTimeGetMonotonicNow();
     SbThreadSleep(kDelay);
-    EXPECT_LE(start + kDelay, SbTimeGetMonotonicNow()) << "Trial " << trial
-                                                       << ", kDelay=" << kDelay;
+    SbTimeMonotonic end = SbTimeGetMonotonicNow();
+    EXPECT_LE(start + kDelay, end + kPrecision) << "Trial " << trial
+                                                << ", kDelay=" << kDelay;
   }
 }
 
diff --git a/src/starboard/shared/starboard/file_mode_string_to_flags.cc b/src/starboard/shared/starboard/file_mode_string_to_flags.cc
index b3575e1..04e7512 100644
--- a/src/starboard/shared/starboard/file_mode_string_to_flags.cc
+++ b/src/starboard/shared/starboard/file_mode_string_to_flags.cc
@@ -33,7 +33,7 @@
     return 0;
   }
 
-  int length = SbStringGetLength(mode);
+  int length = static_cast<int>(SbStringGetLength(mode));
   if (length < 1) {
     return 0;
   }
diff --git a/src/starboard/shared/starboard/media/mime_type.cc b/src/starboard/shared/starboard/media/mime_type.cc
index 4986d87..524c85c 100644
--- a/src/starboard/shared/starboard/media/mime_type.cc
+++ b/src/starboard/shared/starboard/media/mime_type.cc
@@ -67,8 +67,11 @@
 
   for (;;) {
     size_t next = str.find(ch, pos);
-    result.push_back(str.substr(pos, next - pos));
-    Trim(&result.back());
+    std::string sub_str = str.substr(pos, next - pos);
+    Trim(&sub_str);
+    if (!sub_str.empty()) {
+      result.push_back(sub_str);
+    }
     if (next == str.npos) {
       break;
     }
@@ -85,7 +88,9 @@
 MimeType::MimeType(const std::string& content_type) : is_valid_(false) {
   Strings components = SplitAndTrim(content_type, ';');
 
-  SB_DCHECK(!components.empty());
+  if (components.empty()) {
+    return;
+  }
 
   // 1. Verify if there is a valid type/subtype in the very beginning.
   if (ContainsSpace(components.front())) {
@@ -171,7 +176,10 @@
 int MimeType::GetParamIntValue(int index) const {
   SB_DCHECK(is_valid());
   SB_DCHECK(index < GetParamCount());
-  SB_DCHECK(GetParamType(index) == kParamTypeInteger);
+
+  if (GetParamType(index) != kParamTypeInteger) {
+    return 0;
+  }
 
   int i;
   SbStringScanF(params_[index].value.c_str(), "%d", &i);
@@ -181,8 +189,11 @@
 float MimeType::GetParamFloatValue(int index) const {
   SB_DCHECK(is_valid());
   SB_DCHECK(index < GetParamCount());
-  SB_DCHECK(GetParamType(index) == kParamTypeInteger ||
-            GetParamType(index) == kParamTypeFloat);
+
+  if (GetParamType(index) != kParamTypeInteger &&
+      GetParamType(index) != kParamTypeFloat) {
+    return 0.0f;
+  }
 
   float f;
   SbStringScanF(params_[index].value.c_str(), "%g", &f);
diff --git a/src/starboard/shared/starboard/player/filter/audio_buffer_queue.cc b/src/starboard/shared/starboard/player/filter/audio_buffer_queue.cc
new file mode 100644
index 0000000..c051ee8
--- /dev/null
+++ b/src/starboard/shared/starboard/player/filter/audio_buffer_queue.cc
@@ -0,0 +1,140 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cobalt/media/base/audio_buffer_queue.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "cobalt/media/base/audio_bus.h"
+
+namespace cobalt {
+namespace media {
+
+AudioBufferQueue::AudioBufferQueue() {
+  Clear();
+}
+AudioBufferQueue::~AudioBufferQueue() {}
+
+void AudioBufferQueue::Clear() {
+  buffers_.clear();
+  current_buffer_ = buffers_.begin();
+  current_buffer_offset_ = 0;
+  frames_ = 0;
+}
+
+void AudioBufferQueue::Append(const scoped_refptr<AudioBuffer>& buffer_in) {
+  // Add the buffer to the queue. Inserting into deque invalidates all
+  // iterators, so point to the first buffer.
+  buffers_.push_back(buffer_in);
+  current_buffer_ = buffers_.begin();
+
+  // Update the |frames_| counter since we have added frames.
+  frames_ += buffer_in->frame_count();
+  CHECK_GT(frames_, 0);  // make sure it doesn't overflow.
+}
+
+int AudioBufferQueue::ReadFrames(int frames,
+                                 int dest_frame_offset,
+                                 AudioBus* dest) {
+  DCHECK_GE(dest->frames(), frames + dest_frame_offset);
+  return InternalRead(frames, true, 0, dest_frame_offset, dest);
+}
+
+int AudioBufferQueue::PeekFrames(int frames,
+                                 int source_frame_offset,
+                                 int dest_frame_offset,
+                                 AudioBus* dest) {
+  DCHECK_GE(dest->frames(), frames);
+  return InternalRead(frames, false, source_frame_offset, dest_frame_offset,
+                      dest);
+}
+
+void AudioBufferQueue::SeekFrames(int frames) {
+  // Perform seek only if we have enough bytes in the queue.
+  CHECK_LE(frames, frames_);
+  int taken = InternalRead(frames, true, 0, 0, NULL);
+  DCHECK_EQ(taken, frames);
+}
+
+int AudioBufferQueue::InternalRead(int frames,
+                                   bool advance_position,
+                                   int source_frame_offset,
+                                   int dest_frame_offset,
+                                   AudioBus* dest) {
+  // Counts how many frames are actually read from the buffer queue.
+  int taken = 0;
+  BufferQueue::iterator current_buffer = current_buffer_;
+  int current_buffer_offset = current_buffer_offset_;
+
+  int frames_to_skip = source_frame_offset;
+  while (taken < frames) {
+    // |current_buffer| is valid since the first time this buffer is appended
+    // with data. Make sure there is data to be processed.
+    if (current_buffer == buffers_.end())
+      break;
+
+    scoped_refptr<AudioBuffer> buffer = *current_buffer;
+
+    int remaining_frames_in_buffer =
+        buffer->frame_count() - current_buffer_offset;
+
+    if (frames_to_skip > 0) {
+      // If there are frames to skip, do it first. May need to skip into
+      // subsequent buffers.
+      int skipped = std::min(remaining_frames_in_buffer, frames_to_skip);
+      current_buffer_offset += skipped;
+      frames_to_skip -= skipped;
+    } else {
+      // Find the right amount to copy from the current buffer. We shall copy no
+      // more than |frames| frames in total and each single step copies no more
+      // than the current buffer size.
+      int copied = std::min(frames - taken, remaining_frames_in_buffer);
+
+      // if |dest| is NULL, there's no need to copy.
+      if (dest) {
+        buffer->ReadFrames(copied, current_buffer_offset,
+                           dest_frame_offset + taken, dest);
+      }
+
+      // Increase total number of frames copied, which regulates when to end
+      // this loop.
+      taken += copied;
+
+      // We have read |copied| frames from the current buffer. Advance the
+      // offset.
+      current_buffer_offset += copied;
+    }
+
+    // Has the buffer has been consumed?
+    if (current_buffer_offset == buffer->frame_count()) {
+      // If we are at the last buffer, no more data to be copied, so stop.
+      BufferQueue::iterator next = current_buffer + 1;
+      if (next == buffers_.end())
+        break;
+
+      // Advances the iterator.
+      current_buffer = next;
+      current_buffer_offset = 0;
+    }
+  }
+
+  if (advance_position) {
+    // Update the appropriate values since |taken| frames have been copied out.
+    frames_ -= taken;
+    DCHECK_GE(frames_, 0);
+    DCHECK(current_buffer_ != buffers_.end() || frames_ == 0);
+
+    // Remove any buffers before the current buffer as there is no going
+    // backwards.
+    buffers_.erase(buffers_.begin(), current_buffer);
+    current_buffer_ = buffers_.begin();
+    current_buffer_offset_ = current_buffer_offset;
+  }
+
+  return taken;
+}
+
+}  // namespace media
+}  // namespace cobalt
diff --git a/src/starboard/shared/starboard/player/filter/audio_buffer_queue.h b/src/starboard/shared/starboard/player/filter/audio_buffer_queue.h
new file mode 100644
index 0000000..64162a4
--- /dev/null
+++ b/src/starboard/shared/starboard/player/filter/audio_buffer_queue.h
@@ -0,0 +1,90 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COBALT_MEDIA_BASE_AUDIO_BUFFER_QUEUE_H_
+#define COBALT_MEDIA_BASE_AUDIO_BUFFER_QUEUE_H_
+
+#include <deque>
+
+#include "base/basictypes.h"
+#include "cobalt/media/base/audio_buffer.h"
+#include "cobalt/media/base/media_export.h"
+
+namespace cobalt {
+namespace media {
+
+class AudioBus;
+
+// A queue of AudioBuffers to support reading of arbitrary chunks of a media
+// data source. Audio data can be copied into an AudioBus for output. The
+// current position can be forwarded to anywhere in the buffered data.
+//
+// This class is not inherently thread-safe. Concurrent access must be
+// externally serialized.
+class MEDIA_EXPORT AudioBufferQueue {
+ public:
+  AudioBufferQueue();
+  ~AudioBufferQueue();
+
+  // Clears the buffer queue.
+  void Clear();
+
+  // Appends |buffer_in| to this queue.
+  void Append(const scoped_refptr<AudioBuffer>& buffer_in);
+
+  // Reads a maximum of |frames| frames into |dest| from the current position.
+  // Returns the number of frames read. The current position will advance by the
+  // amount of frames read. |dest_frame_offset| specifies a starting offset into
+  // |dest|. On each call, the frames are converted from their source format
+  // into the destination AudioBus.
+  int ReadFrames(int frames, int dest_frame_offset, AudioBus* dest);
+
+  // Copies up to |frames| frames from current position to |dest|. Returns
+  // number of frames copied. Doesn't advance current position. Starts at
+  // |source_frame_offset| from current position. |dest_frame_offset| specifies
+  // a starting offset into |dest|. On each call, the frames are converted from
+  // their source format into the destination AudioBus.
+  int PeekFrames(int frames,
+                 int source_frame_offset,
+                 int dest_frame_offset,
+                 AudioBus* dest);
+
+  // Moves the current position forward by |frames| frames. If |frames| exceeds
+  // frames available, the seek operation will fail.
+  void SeekFrames(int frames);
+
+  // Returns the number of frames buffered beyond the current position.
+  int frames() const { return frames_; }
+
+ private:
+  // Definition of the buffer queue.
+  typedef std::deque<scoped_refptr<AudioBuffer> > BufferQueue;
+
+  // An internal method shared by ReadFrames() and SeekFrames() that actually
+  // does reading. It reads a maximum of |frames| frames into |dest|. Returns
+  // the number of frames read. The current position will be moved forward by
+  // the number of frames read if |advance_position| is set. If |dest| is NULL,
+  // only the current position will advance but no data will be copied.
+  // |source_frame_offset| can be used to skip frames before reading.
+  // |dest_frame_offset| specifies a starting offset into |dest|.
+  int InternalRead(int frames,
+                   bool advance_position,
+                   int source_frame_offset,
+                   int dest_frame_offset,
+                   AudioBus* dest);
+
+  BufferQueue::iterator current_buffer_;
+  BufferQueue buffers_;
+  int current_buffer_offset_;
+
+  // Number of frames available to be read in the buffer.
+  int frames_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioBufferQueue);
+};
+
+}  // namespace media
+}  // namespace cobalt
+
+#endif  // COBALT_MEDIA_BASE_AUDIO_BUFFER_QUEUE_H_
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_algorithm.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_algorithm.cc
new file mode 100644
index 0000000..5143d7b
--- /dev/null
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_algorithm.cc
@@ -0,0 +1,396 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cobalt/media/filters/audio_renderer_algorithm.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+#include "cobalt/media/base/audio_bus.h"
+#include "cobalt/media/base/limits.h"
+#include "cobalt/media/filters/wsola_internals.h"
+#include "starboard/memory.h"
+
+namespace cobalt {
+namespace media {
+
+// Waveform Similarity Overlap-and-add (WSOLA).
+//
+// One WSOLA iteration
+//
+// 1) Extract |target_block_| as input frames at indices
+//    [|target_block_index_|, |target_block_index_| + |ola_window_size_|).
+//    Note that |target_block_| is the "natural" continuation of the output.
+//
+// 2) Extract |search_block_| as input frames at indices
+//    [|search_block_index_|,
+//     |search_block_index_| + |num_candidate_blocks_| + |ola_window_size_|).
+//
+// 3) Find a block within the |search_block_| that is most similar
+//    to |target_block_|. Let |optimal_index| be the index of such block and
+//    write it to |optimal_block_|.
+//
+// 4) Update:
+//    |optimal_block_| = |transition_window_| * |target_block_| +
+//    (1 - |transition_window_|) * |optimal_block_|.
+//
+// 5) Overlap-and-add |optimal_block_| to the |wsola_output_|.
+//
+// 6) Update:
+//    |target_block_| = |optimal_index| + |ola_window_size_| / 2.
+//    |output_index_| = |output_index_| + |ola_window_size_| / 2,
+//    |search_block_center_offset_| = |output_index_| * |playback_rate|, and
+//    |search_block_index_| = |search_block_center_offset_| -
+//        |search_block_center_offset_|.
+
+// Max/min supported playback rates for fast/slow audio. Audio outside of these
+// ranges are muted.
+// Audio at these speeds would sound better under a frequency domain algorithm.
+static const double kMinPlaybackRate = 0.5;
+static const double kMaxPlaybackRate = 4.0;
+
+// Overlap-and-add window size in milliseconds.
+static const int kOlaWindowSizeMs = 20;
+
+// Size of search interval in milliseconds. The search interval is
+// [-delta delta] around |output_index_| * |playback_rate|. So the search
+// interval is 2 * delta.
+static const int kWsolaSearchIntervalMs = 30;
+
+// The maximum size in seconds for the |audio_buffer_|. Arbitrarily determined.
+static const int kMaxCapacityInSeconds = 3;
+
+// The minimum size in ms for the |audio_buffer_|. Arbitrarily determined.
+static const int kStartingCapacityInMs = 200;
+
+AudioRendererAlgorithm::AudioRendererAlgorithm()
+    : channels_(0),
+      samples_per_second_(0),
+      muted_partial_frame_(0),
+      capacity_(0),
+      output_time_(0.0),
+      search_block_center_offset_(0),
+      search_block_index_(0),
+      num_candidate_blocks_(0),
+      target_block_index_(0),
+      ola_window_size_(0),
+      ola_hop_size_(0),
+      num_complete_frames_(0),
+      initial_capacity_(0),
+      max_capacity_(0) {}
+
+AudioRendererAlgorithm::~AudioRendererAlgorithm() {}
+
+void AudioRendererAlgorithm::Initialize(const AudioParameters& params) {
+  CHECK(params.IsValid());
+
+  channels_ = params.channels();
+  samples_per_second_ = params.sample_rate();
+  initial_capacity_ = capacity_ =
+      std::max(params.frames_per_buffer() * 2,
+               ConvertMillisecondsToFrames(kStartingCapacityInMs));
+  max_capacity_ =
+      std::max(initial_capacity_, kMaxCapacityInSeconds * samples_per_second_);
+  num_candidate_blocks_ = ConvertMillisecondsToFrames(kWsolaSearchIntervalMs);
+  ola_window_size_ = ConvertMillisecondsToFrames(kOlaWindowSizeMs);
+
+  // Make sure window size in an even number.
+  ola_window_size_ += ola_window_size_ & 1;
+  ola_hop_size_ = ola_window_size_ / 2;
+
+  // |num_candidate_blocks_| / 2 is the offset of the center of the search
+  // block to the center of the first (left most) candidate block. The offset
+  // of the center of a candidate block to its left most point is
+  // |ola_window_size_| / 2 - 1. Note that |ola_window_size_| is even and in
+  // our convention the center belongs to the left half, so we need to subtract
+  // one frame to get the correct offset.
+  //
+  //                             Search Block
+  //              <------------------------------------------->
+  //
+  //   |ola_window_size_| / 2 - 1
+  //              <----
+  //
+  //             |num_candidate_blocks_| / 2
+  //                   <----------------
+  //                                 center
+  //              X----X----------------X---------------X-----X
+  //              <---------->                     <---------->
+  //                Candidate      ...               Candidate
+  //                   1,          ...         |num_candidate_blocks_|
+  search_block_center_offset_ =
+      num_candidate_blocks_ / 2 + (ola_window_size_ / 2 - 1);
+
+  ola_window_.reset(new float[ola_window_size_]);
+  internal::GetSymmetricHanningWindow(ola_window_size_, ola_window_.get());
+
+  transition_window_.reset(new float[ola_window_size_ * 2]);
+  internal::GetSymmetricHanningWindow(2 * ola_window_size_,
+                                      transition_window_.get());
+
+  wsola_output_ = AudioBus::Create(channels_, ola_window_size_ + ola_hop_size_);
+  wsola_output_->Zero();  // Initialize for overlap-and-add of the first block.
+
+  // Auxiliary containers.
+  optimal_block_ = AudioBus::Create(channels_, ola_window_size_);
+  search_block_ = AudioBus::Create(
+      channels_, num_candidate_blocks_ + (ola_window_size_ - 1));
+  target_block_ = AudioBus::Create(channels_, ola_window_size_);
+}
+
+int AudioRendererAlgorithm::FillBuffer(AudioBus* dest, int dest_offset,
+                                       int requested_frames,
+                                       double playback_rate) {
+  if (playback_rate == 0) return 0;
+
+  DCHECK_GT(playback_rate, 0);
+  DCHECK_EQ(channels_, dest->channels());
+
+  // Optimize the muted case to issue a single clear instead of performing
+  // the full crossfade and clearing each crossfaded frame.
+  if (playback_rate < kMinPlaybackRate || playback_rate > kMaxPlaybackRate) {
+    int frames_to_render =
+        std::min(static_cast<int>(audio_buffer_.frames() / playback_rate),
+                 requested_frames);
+
+    // Compute accurate number of frames to actually skip in the source data.
+    // Includes the leftover partial frame from last request. However, we can
+    // only skip over complete frames, so a partial frame may remain for next
+    // time.
+    muted_partial_frame_ += frames_to_render * playback_rate;
+    // Handle the case where muted_partial_frame_ rounds up to
+    // audio_buffer_.frames()+1.
+    int seek_frames = std::min(static_cast<int>(muted_partial_frame_),
+                               audio_buffer_.frames());
+    dest->ZeroFramesPartial(dest_offset, frames_to_render);
+    audio_buffer_.SeekFrames(seek_frames);
+
+    // Determine the partial frame that remains to be skipped for next call. If
+    // the user switches back to playing, it may be off time by this partial
+    // frame, which would be undetectable. If they subsequently switch to
+    // another playback rate that mutes, the code will attempt to line up the
+    // frames again.
+    muted_partial_frame_ -= seek_frames;
+    return frames_to_render;
+  }
+
+  int slower_step = ceil(ola_window_size_ * playback_rate);
+  int faster_step = ceil(ola_window_size_ / playback_rate);
+
+  // Optimize the most common |playback_rate| ~= 1 case to use a single copy
+  // instead of copying frame by frame.
+  if (ola_window_size_ <= faster_step && slower_step >= ola_window_size_) {
+    const int frames_to_copy =
+        std::min(audio_buffer_.frames(), requested_frames);
+    const int frames_read =
+        audio_buffer_.ReadFrames(frames_to_copy, dest_offset, dest);
+    DCHECK_EQ(frames_read, frames_to_copy);
+    return frames_read;
+  }
+
+  int rendered_frames = 0;
+  do {
+    rendered_frames +=
+        WriteCompletedFramesTo(requested_frames - rendered_frames,
+                               dest_offset + rendered_frames, dest);
+  } while (rendered_frames < requested_frames &&
+           RunOneWsolaIteration(playback_rate));
+  return rendered_frames;
+}
+
+void AudioRendererAlgorithm::FlushBuffers() {
+  // Clear the queue of decoded packets (releasing the buffers).
+  audio_buffer_.Clear();
+  output_time_ = 0.0;
+  search_block_index_ = 0;
+  target_block_index_ = 0;
+  wsola_output_->Zero();
+  num_complete_frames_ = 0;
+
+  // Reset |capacity_| so growth triggered by underflows doesn't penalize seek
+  // time.
+  capacity_ = initial_capacity_;
+}
+
+void AudioRendererAlgorithm::EnqueueBuffer(
+    const scoped_refptr<AudioBuffer>& buffer_in) {
+  DCHECK(!buffer_in->end_of_stream());
+  audio_buffer_.Append(buffer_in);
+}
+
+bool AudioRendererAlgorithm::IsQueueFull() {
+  return audio_buffer_.frames() >= capacity_;
+}
+
+void AudioRendererAlgorithm::IncreaseQueueCapacity() {
+  DCHECK_LE(capacity_, max_capacity_);
+  capacity_ = std::min(2 * capacity_, max_capacity_);
+}
+
+int64_t AudioRendererAlgorithm::GetMemoryUsage() const {
+  return audio_buffer_.frames() * channels_ * sizeof(float);
+}
+
+bool AudioRendererAlgorithm::CanPerformWsola() const {
+  const int search_block_size = num_candidate_blocks_ + (ola_window_size_ - 1);
+  const int frames = audio_buffer_.frames();
+  return target_block_index_ + ola_window_size_ <= frames &&
+         search_block_index_ + search_block_size <= frames;
+}
+
+int AudioRendererAlgorithm::ConvertMillisecondsToFrames(int ms) const {
+  return ms * (samples_per_second_ /
+               static_cast<double>(base::Time::kMillisecondsPerSecond));
+}
+
+bool AudioRendererAlgorithm::RunOneWsolaIteration(double playback_rate) {
+  if (!CanPerformWsola()) return false;
+
+  GetOptimalBlock();
+
+  // Overlap-and-add.
+  for (int k = 0; k < channels_; ++k) {
+    const float* const ch_opt_frame = optimal_block_->channel(k);
+    float* ch_output = wsola_output_->channel(k) + num_complete_frames_;
+    for (int n = 0; n < ola_hop_size_; ++n) {
+      ch_output[n] = ch_output[n] * ola_window_[ola_hop_size_ + n] +
+                     ch_opt_frame[n] * ola_window_[n];
+    }
+
+    // Copy the second half to the output.
+    SbMemoryCopy(&ch_output[ola_hop_size_], &ch_opt_frame[ola_hop_size_],
+                 sizeof(*ch_opt_frame) * ola_hop_size_);
+  }
+
+  num_complete_frames_ += ola_hop_size_;
+  UpdateOutputTime(playback_rate, ola_hop_size_);
+  RemoveOldInputFrames(playback_rate);
+  return true;
+}
+
+void AudioRendererAlgorithm::UpdateOutputTime(double playback_rate,
+                                              double time_change) {
+  output_time_ += time_change;
+  // Center of the search region, in frames.
+  const int search_block_center_index =
+      static_cast<int>(output_time_ * playback_rate + 0.5);
+  search_block_index_ = search_block_center_index - search_block_center_offset_;
+}
+
+void AudioRendererAlgorithm::RemoveOldInputFrames(double playback_rate) {
+  const int earliest_used_index =
+      std::min(target_block_index_, search_block_index_);
+  if (earliest_used_index <= 0) return;  // Nothing to remove.
+
+  // Remove frames from input and adjust indices accordingly.
+  audio_buffer_.SeekFrames(earliest_used_index);
+  target_block_index_ -= earliest_used_index;
+
+  // Adjust output index.
+  double output_time_change =
+      static_cast<double>(earliest_used_index) / playback_rate;
+  CHECK_GE(output_time_, output_time_change);
+  UpdateOutputTime(playback_rate, -output_time_change);
+}
+
+int AudioRendererAlgorithm::WriteCompletedFramesTo(int requested_frames,
+                                                   int dest_offset,
+                                                   AudioBus* dest) {
+  int rendered_frames = std::min(num_complete_frames_, requested_frames);
+
+  if (rendered_frames == 0)
+    return 0;  // There is nothing to read from |wsola_output_|, return.
+
+  wsola_output_->CopyPartialFramesTo(0, rendered_frames, dest_offset, dest);
+
+  // Remove the frames which are read.
+  int frames_to_move = wsola_output_->frames() - rendered_frames;
+  for (int k = 0; k < channels_; ++k) {
+    float* ch = wsola_output_->channel(k);
+    SbMemoryMove(ch, &ch[rendered_frames], sizeof(*ch) * frames_to_move);
+  }
+  num_complete_frames_ -= rendered_frames;
+  return rendered_frames;
+}
+
+bool AudioRendererAlgorithm::TargetIsWithinSearchRegion() const {
+  const int search_block_size = num_candidate_blocks_ + (ola_window_size_ - 1);
+
+  return target_block_index_ >= search_block_index_ &&
+         target_block_index_ + ola_window_size_ <=
+             search_block_index_ + search_block_size;
+}
+
+void AudioRendererAlgorithm::GetOptimalBlock() {
+  int optimal_index = 0;
+
+  // An interval around last optimal block which is excluded from the search.
+  // This is to reduce the buzzy sound. The number 160 is rather arbitrary and
+  // derived heuristically.
+  const int kExcludeIntervalLengthFrames = 160;
+  if (TargetIsWithinSearchRegion()) {
+    optimal_index = target_block_index_;
+    PeekAudioWithZeroPrepend(optimal_index, optimal_block_.get());
+  } else {
+    PeekAudioWithZeroPrepend(target_block_index_, target_block_.get());
+    PeekAudioWithZeroPrepend(search_block_index_, search_block_.get());
+    int last_optimal =
+        target_block_index_ - ola_hop_size_ - search_block_index_;
+    internal::Interval exclude_iterval =
+        std::make_pair(last_optimal - kExcludeIntervalLengthFrames / 2,
+                       last_optimal + kExcludeIntervalLengthFrames / 2);
+
+    // |optimal_index| is in frames and it is relative to the beginning of the
+    // |search_block_|.
+    optimal_index = internal::OptimalIndex(
+        search_block_.get(), target_block_.get(), exclude_iterval);
+
+    // Translate |index| w.r.t. the beginning of |audio_buffer_| and extract the
+    // optimal block.
+    optimal_index += search_block_index_;
+    PeekAudioWithZeroPrepend(optimal_index, optimal_block_.get());
+
+    // Make a transition from target block to the optimal block if different.
+    // Target block has the best continuation to the current output.
+    // Optimal block is the most similar block to the target, however, it might
+    // introduce some discontinuity when over-lap-added. Therefore, we combine
+    // them for a smoother transition. The length of transition window is twice
+    // as that of the optimal-block which makes it like a weighting function
+    // where target-block has higher weight close to zero (weight of 1 at index
+    // 0) and lower weight close the end.
+    for (int k = 0; k < channels_; ++k) {
+      float* ch_opt = optimal_block_->channel(k);
+      const float* const ch_target = target_block_->channel(k);
+      for (int n = 0; n < ola_window_size_; ++n) {
+        ch_opt[n] = ch_opt[n] * transition_window_[n] +
+                    ch_target[n] * transition_window_[ola_window_size_ + n];
+      }
+    }
+  }
+
+  // Next target is one hop ahead of the current optimal.
+  target_block_index_ = optimal_index + ola_hop_size_;
+}
+
+void AudioRendererAlgorithm::PeekAudioWithZeroPrepend(int read_offset_frames,
+                                                      AudioBus* dest) {
+  CHECK_LE(read_offset_frames + dest->frames(), audio_buffer_.frames());
+
+  int write_offset = 0;
+  int num_frames_to_read = dest->frames();
+  if (read_offset_frames < 0) {
+    int num_zero_frames_appended =
+        std::min(-read_offset_frames, num_frames_to_read);
+    read_offset_frames = 0;
+    num_frames_to_read -= num_zero_frames_appended;
+    write_offset = num_zero_frames_appended;
+    dest->ZeroFrames(num_zero_frames_appended);
+  }
+  audio_buffer_.PeekFrames(num_frames_to_read, read_offset_frames, write_offset,
+                           dest);
+}
+
+}  // namespace media
+}  // namespace cobalt
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_algorithm.h b/src/starboard/shared/starboard/player/filter/audio_renderer_algorithm.h
new file mode 100644
index 0000000..e2becc9
--- /dev/null
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_algorithm.h
@@ -0,0 +1,218 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// AudioRendererAlgorithm buffers and transforms audio data. The owner of
+// this object provides audio data to the object through EnqueueBuffer() and
+// requests data from the buffer via FillBuffer().
+//
+// This class is *not* thread-safe. Calls to enqueue and retrieve data must be
+// locked if called from multiple threads.
+//
+// AudioRendererAlgorithm uses the Waveform Similarity Overlap and Add (WSOLA)
+// algorithm to stretch or compress audio data to meet playback speeds less than
+// or greater than the natural playback of the audio stream. The algorithm
+// preserves local properties of the audio, therefore, pitch and harmonics are
+// are preserved. See audio_renderer_algorith.cc for a more elaborate
+// description of the algorithm.
+//
+// Audio at very low or very high playback rates are muted to preserve quality.
+
+#ifndef COBALT_MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_H_
+#define COBALT_MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_H_
+
+#include <memory>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "cobalt/media/base/audio_buffer.h"
+#include "cobalt/media/base/audio_buffer_queue.h"
+#include "cobalt/media/base/audio_parameters.h"
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace media {
+
+class AudioBus;
+
+class MEDIA_EXPORT AudioRendererAlgorithm {
+ public:
+  AudioRendererAlgorithm();
+  ~AudioRendererAlgorithm();
+
+  // Initializes this object with information about the audio stream.
+  void Initialize(const AudioParameters& params);
+
+  // Tries to fill |requested_frames| frames into |dest| with possibly scaled
+  // data from our |audio_buffer_|. Data is scaled based on |playback_rate|,
+  // using a variation of the Overlap-Add method to combine sample windows.
+  //
+  // Data from |audio_buffer_| is consumed in proportion to the playback rate.
+  //
+  // |dest_offset| is the offset in frames for writing into |dest|.
+  //
+  // Returns the number of frames copied into |dest|.
+  int FillBuffer(AudioBus* dest, int dest_offset, int requested_frames,
+                 double playback_rate);
+
+  // Clears |audio_buffer_|.
+  void FlushBuffers();
+
+  // Enqueues a buffer. It is called from the owner of the algorithm after a
+  // read completes.
+  void EnqueueBuffer(const scoped_refptr<AudioBuffer>& buffer_in);
+
+  // Returns true if |audio_buffer_| is at or exceeds capacity.
+  bool IsQueueFull();
+
+  // Returns the capacity of |audio_buffer_| in frames.
+  int QueueCapacity() const { return capacity_; }
+
+  // Increase the capacity of |audio_buffer_| if possible.
+  void IncreaseQueueCapacity();
+
+  // Returns an estimate of the amount of memory (in bytes) used for frames.
+  int64_t GetMemoryUsage() const;
+
+  // Returns the number of frames left in |audio_buffer_|, which may be larger
+  // than QueueCapacity() in the event that EnqueueBuffer() delivered more data
+  // than |audio_buffer_| was intending to hold.
+  int frames_buffered() { return audio_buffer_.frames(); }
+
+  // Returns the samples per second for this audio stream.
+  int samples_per_second() { return samples_per_second_; }
+
+ private:
+  // Within |search_block_|, find the block of data that is most similar to
+  // |target_block_|, and write it in |optimal_block_|. This method assumes that
+  // there is enough data to perform a search, i.e. |search_block_| and
+  // |target_block_| can be extracted from the available frames.
+  void GetOptimalBlock();
+
+  // Read a maximum of |requested_frames| frames from |wsola_output_|. Returns
+  // number of frames actually read.
+  int WriteCompletedFramesTo(int requested_frames, int output_offset,
+                             AudioBus* dest);
+
+  // Fill |dest| with frames from |audio_buffer_| starting from frame
+  // |read_offset_frames|. |dest| is expected to have the same number of
+  // channels as |audio_buffer_|. A negative offset, i.e.
+  // |read_offset_frames| < 0, is accepted assuming that |audio_buffer| is zero
+  // for negative indices. This might happen for few first frames. This method
+  // assumes there is enough frames to fill |dest|, i.e. |read_offset_frames| +
+  // |dest->frames()| does not extend to future.
+  void PeekAudioWithZeroPrepend(int read_offset_frames, AudioBus* dest);
+
+  // Run one iteration of WSOLA, if there are sufficient frames. This will
+  // overlap-and-add one block to |wsola_output_|, hence, |num_complete_frames_|
+  // is incremented by |ola_hop_size_|.
+  bool RunOneWsolaIteration(double playback_rate);
+
+  // Seek |audio_buffer_| forward to remove frames from input that are not used
+  // any more. State of the WSOLA will be updated accordingly.
+  void RemoveOldInputFrames(double playback_rate);
+
+  // Update |output_time_| by |time_change|. In turn |search_block_index_| is
+  // updated.
+  void UpdateOutputTime(double playback_rate, double time_change);
+
+  // Is |target_block_| fully within |search_block_|? If so, we don't need to
+  // perform the search.
+  bool TargetIsWithinSearchRegion() const;
+
+  // Do we have enough data to perform one round of WSOLA?
+  bool CanPerformWsola() const;
+
+  // Converts a time in milliseconds to frames using |samples_per_second_|.
+  int ConvertMillisecondsToFrames(int ms) const;
+
+  // Number of channels in audio stream.
+  int channels_;
+
+  // Sample rate of audio stream.
+  int samples_per_second_;
+
+  // Buffered audio data.
+  AudioBufferQueue audio_buffer_;
+
+  // If muted, keep track of partial frames that should have been skipped over.
+  double muted_partial_frame_;
+
+  // How many frames to have in the queue before we report the queue is full.
+  int capacity_;
+
+  // Book keeping of the current time of generated audio, in frames. This
+  // should be appropriately updated when out samples are generated, regardless
+  // of whether we push samples out when FillBuffer() is called or we store
+  // audio in |wsola_output_| for the subsequent calls to FillBuffer().
+  // Furthermore, if samples from |audio_buffer_| are evicted then this
+  // member variable should be updated based on |playback_rate_|.
+  // Note that this member should be updated ONLY by calling UpdateOutputTime(),
+  // so that |search_block_index_| is update accordingly.
+  double output_time_;
+
+  // The offset of the center frame of |search_block_| w.r.t. its first frame.
+  int search_block_center_offset_;
+
+  // Index of the beginning of the |search_block_|, in frames.
+  int search_block_index_;
+
+  // Number of Blocks to search to find the most similar one to the target
+  // frame.
+  int num_candidate_blocks_;
+
+  // Index of the beginning of the target block, counted in frames.
+  int target_block_index_;
+
+  // Overlap-and-add window size in frames.
+  int ola_window_size_;
+
+  // The hop size of overlap-and-add in frames. This implementation assumes 50%
+  // overlap-and-add.
+  int ola_hop_size_;
+
+  // Number of frames in |wsola_output_| that overlap-and-add is completed for
+  // them and can be copied to output if FillBuffer() is called. It also
+  // specifies the index where the next WSOLA window has to overlap-and-add.
+  int num_complete_frames_;
+
+  // This stores a part of the output that is created but couldn't be rendered.
+  // Output is generated frame-by-frame which at some point might exceed the
+  // number of requested samples. Furthermore, due to overlap-and-add,
+  // the last half-window of the output is incomplete, which is stored in this
+  // buffer.
+  std::unique_ptr<AudioBus> wsola_output_;
+
+  // Overlap-and-add window.
+  std::unique_ptr<float[]> ola_window_;
+
+  // Transition window, used to update |optimal_block_| by a weighted sum of
+  // |optimal_block_| and |target_block_|.
+  std::unique_ptr<float[]> transition_window_;
+
+  // Auxiliary variables to avoid allocation in every iteration.
+
+  // Stores the optimal block in every iteration. This is the most
+  // similar block to |target_block_| within |search_block_| and it is
+  // overlap-and-added to |wsola_output_|.
+  std::unique_ptr<AudioBus> optimal_block_;
+
+  // A block of data that search is performed over to find the |optimal_block_|.
+  std::unique_ptr<AudioBus> search_block_;
+
+  // Stores the target block, denoted as |target| above. |search_block_| is
+  // searched for a block (|optimal_block_|) that is most similar to
+  // |target_block_|.
+  std::unique_ptr<AudioBus> target_block_;
+
+  // The initial and maximum capacity calculated by Initialize().
+  int initial_capacity_;
+  int max_capacity_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioRendererAlgorithm);
+};
+
+}  // namespace media
+}  // namespace cobalt
+
+#endif  // COBALT_MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_H_
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
index 13b9db4..96e38a7 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
@@ -220,6 +220,12 @@
   *is_playing = true;
   *frames_in_buffer = frames_in_buffer_;
   *offset_in_frames = offset_in_frames_;
+
+  if (!end_of_stream_decoded_ && !read_from_decoder_closure_.is_valid()) {
+    read_from_decoder_closure_ =
+        Bind(&AudioRendererImpl::ReadFromDecoder, this);
+    job_queue_->Schedule(read_from_decoder_closure_);
+  }
 }
 
 void AudioRendererImpl::ConsumeFrames(int frames_consumed) {
@@ -231,15 +237,6 @@
   frames_in_buffer_ -= frames_consumed;
   frames_consumed_ += frames_consumed;
   frames_consumed_set_at_ = SbTimeGetMonotonicNow();
-
-  bool decoded_audio_available =
-      pending_decoded_audio_ ||
-      (end_of_stream_written_ && !end_of_stream_decoded_);
-  if (decoded_audio_available && !read_from_decoder_closure_.is_valid()) {
-    read_from_decoder_closure_ =
-        Bind(&AudioRendererImpl::ReadFromDecoder, this);
-    job_queue_->Schedule(read_from_decoder_closure_);
-  }
 }
 
 void AudioRendererImpl::LogFramesConsumed() {
diff --git a/src/starboard/shared/starboard/player/filter/wsola_internals.cc b/src/starboard/shared/starboard/player/filter/wsola_internals.cc
new file mode 100644
index 0000000..507893e
--- /dev/null
+++ b/src/starboard/shared/starboard/player/filter/wsola_internals.cc
@@ -0,0 +1,260 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// MSVC++ requires this to be set before any other includes to get M_PI.
+#define _USE_MATH_DEFINES
+
+#include "cobalt/media/filters/wsola_internals.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <memory>
+
+#include "base/logging.h"
+#include "cobalt/media/base/audio_bus.h"
+#include "starboard/memory.h"
+
+namespace cobalt {
+namespace media {
+
+namespace internal {
+
+bool InInterval(int n, Interval q) { return n >= q.first && n <= q.second; }
+
+float MultiChannelSimilarityMeasure(const float* dot_prod_a_b,
+                                    const float* energy_a,
+                                    const float* energy_b, int channels) {
+  const float kEpsilon = 1e-12f;
+  float similarity_measure = 0.0f;
+  for (int n = 0; n < channels; ++n) {
+    similarity_measure +=
+        dot_prod_a_b[n] / sqrt(energy_a[n] * energy_b[n] + kEpsilon);
+  }
+  return similarity_measure;
+}
+
+void MultiChannelDotProduct(const AudioBus* a, int frame_offset_a,
+                            const AudioBus* b, int frame_offset_b,
+                            int num_frames, float* dot_product) {
+  DCHECK_EQ(a->channels(), b->channels());
+  DCHECK_GE(frame_offset_a, 0);
+  DCHECK_GE(frame_offset_b, 0);
+  DCHECK_LE(frame_offset_a + num_frames, a->frames());
+  DCHECK_LE(frame_offset_b + num_frames, b->frames());
+
+  SbMemorySet(dot_product, 0, sizeof(*dot_product) * a->channels());
+  for (int k = 0; k < a->channels(); ++k) {
+    const float* ch_a = a->channel(k) + frame_offset_a;
+    const float* ch_b = b->channel(k) + frame_offset_b;
+    for (int n = 0; n < num_frames; ++n) {
+      dot_product[k] += *ch_a++ * *ch_b++;
+    }
+  }
+}
+
+void MultiChannelMovingBlockEnergies(const AudioBus* input,
+                                     int frames_per_block, float* energy) {
+  int num_blocks = input->frames() - (frames_per_block - 1);
+  int channels = input->channels();
+
+  for (int k = 0; k < input->channels(); ++k) {
+    const float* input_channel = input->channel(k);
+
+    energy[k] = 0;
+
+    // First block of channel |k|.
+    for (int m = 0; m < frames_per_block; ++m) {
+      energy[k] += input_channel[m] * input_channel[m];
+    }
+
+    const float* slide_out = input_channel;
+    const float* slide_in = input_channel + frames_per_block;
+    for (int n = 1; n < num_blocks; ++n, ++slide_in, ++slide_out) {
+      energy[k + n * channels] = energy[k + (n - 1) * channels] -
+                                 *slide_out * *slide_out +
+                                 *slide_in * *slide_in;
+    }
+  }
+}
+
+// Fit the curve f(x) = a * x^2 + b * x + c such that
+//   f(-1) = y[0]
+//   f(0) = y[1]
+//   f(1) = y[2]
+// and return the maximum, assuming that y[0] <= y[1] >= y[2].
+void QuadraticInterpolation(const float* y_values, float* extremum,
+                            float* extremum_value) {
+  float a = 0.5f * (y_values[2] + y_values[0]) - y_values[1];
+  float b = 0.5f * (y_values[2] - y_values[0]);
+  float c = y_values[1];
+
+  if (a == 0.f) {
+    // The coordinates are colinear (within floating-point error).
+    *extremum = 0;
+    *extremum_value = y_values[1];
+  } else {
+    *extremum = -b / (2.f * a);
+    *extremum_value = a * (*extremum) * (*extremum) + b * (*extremum) + c;
+  }
+}
+
+int DecimatedSearch(int decimation, Interval exclude_interval,
+                    const AudioBus* target_block,
+                    const AudioBus* search_segment,
+                    const float* energy_target_block,
+                    const float* energy_candidate_blocks) {
+  int channels = search_segment->channels();
+  int block_size = target_block->frames();
+  int num_candidate_blocks = search_segment->frames() - (block_size - 1);
+  std::unique_ptr<float[]> dot_prod(new float[channels]);
+  float similarity[3];  // Three elements for cubic interpolation.
+
+  int n = 0;
+  MultiChannelDotProduct(target_block, 0, search_segment, n, block_size,
+                         dot_prod.get());
+  similarity[0] = MultiChannelSimilarityMeasure(
+      dot_prod.get(), energy_target_block,
+      &energy_candidate_blocks[n * channels], channels);
+
+  // Set the starting point as optimal point.
+  float best_similarity = similarity[0];
+  int optimal_index = 0;
+
+  n += decimation;
+  if (n >= num_candidate_blocks) {
+    return 0;
+  }
+
+  MultiChannelDotProduct(target_block, 0, search_segment, n, block_size,
+                         dot_prod.get());
+  similarity[1] = MultiChannelSimilarityMeasure(
+      dot_prod.get(), energy_target_block,
+      &energy_candidate_blocks[n * channels], channels);
+
+  n += decimation;
+  if (n >= num_candidate_blocks) {
+    // We cannot do any more sampling. Compare these two values and return the
+    // optimal index.
+    return similarity[1] > similarity[0] ? decimation : 0;
+  }
+
+  for (; n < num_candidate_blocks; n += decimation) {
+    MultiChannelDotProduct(target_block, 0, search_segment, n, block_size,
+                           dot_prod.get());
+
+    similarity[2] = MultiChannelSimilarityMeasure(
+        dot_prod.get(), energy_target_block,
+        &energy_candidate_blocks[n * channels], channels);
+
+    if ((similarity[1] > similarity[0] && similarity[1] >= similarity[2]) ||
+        (similarity[1] >= similarity[0] && similarity[1] > similarity[2])) {
+      // A local maximum is found. Do a cubic interpolation for a better
+      // estimate of candidate maximum.
+      float normalized_candidate_index;
+      float candidate_similarity;
+      QuadraticInterpolation(similarity, &normalized_candidate_index,
+                             &candidate_similarity);
+
+      int candidate_index =
+          n - decimation +
+          static_cast<int>(normalized_candidate_index * decimation + 0.5f);
+      if (candidate_similarity > best_similarity &&
+          !InInterval(candidate_index, exclude_interval)) {
+        optimal_index = candidate_index;
+        best_similarity = candidate_similarity;
+      }
+    } else if (n + decimation >= num_candidate_blocks &&
+               similarity[2] > best_similarity &&
+               !InInterval(n, exclude_interval)) {
+      // If this is the end-point and has a better similarity-measure than
+      // optimal, then we accept it as optimal point.
+      optimal_index = n;
+      best_similarity = similarity[2];
+    }
+    SbMemoryMove(similarity, &similarity[1], 2 * sizeof(*similarity));
+  }
+  return optimal_index;
+}
+
+int FullSearch(int low_limit, int high_limit, Interval exclude_interval,
+               const AudioBus* target_block, const AudioBus* search_block,
+               const float* energy_target_block,
+               const float* energy_candidate_blocks) {
+  int channels = search_block->channels();
+  int block_size = target_block->frames();
+  std::unique_ptr<float[]> dot_prod(new float[channels]);
+
+  float best_similarity = std::numeric_limits<float>::min();
+  int optimal_index = 0;
+
+  for (int n = low_limit; n <= high_limit; ++n) {
+    if (InInterval(n, exclude_interval)) {
+      continue;
+    }
+    MultiChannelDotProduct(target_block, 0, search_block, n, block_size,
+                           dot_prod.get());
+
+    float similarity = MultiChannelSimilarityMeasure(
+        dot_prod.get(), energy_target_block,
+        &energy_candidate_blocks[n * channels], channels);
+
+    if (similarity > best_similarity) {
+      best_similarity = similarity;
+      optimal_index = n;
+    }
+  }
+
+  return optimal_index;
+}
+
+int OptimalIndex(const AudioBus* search_block, const AudioBus* target_block,
+                 Interval exclude_interval) {
+  int channels = search_block->channels();
+  DCHECK_EQ(channels, target_block->channels());
+  int target_size = target_block->frames();
+  int num_candidate_blocks = search_block->frames() - (target_size - 1);
+
+  // This is a compromise between complexity reduction and search accuracy. I
+  // don't have a proof that down sample of order 5 is optimal. One can compute
+  // a decimation factor that minimizes complexity given the size of
+  // |search_block| and |target_block|. However, my experiments show the rate of
+  // missing the optimal index is significant. This value is chosen
+  // heuristically based on experiments.
+  const int kSearchDecimation = 5;
+
+  std::unique_ptr<float[]> energy_target_block(new float[channels]);
+  std::unique_ptr<float[]> energy_candidate_blocks(
+      new float[channels * num_candidate_blocks]);
+
+  // Energy of all candid frames.
+  MultiChannelMovingBlockEnergies(search_block, target_size,
+                                  energy_candidate_blocks.get());
+
+  // Energy of target frame.
+  MultiChannelDotProduct(target_block, 0, target_block, 0, target_size,
+                         energy_target_block.get());
+
+  int optimal_index = DecimatedSearch(
+      kSearchDecimation, exclude_interval, target_block, search_block,
+      energy_target_block.get(), energy_candidate_blocks.get());
+
+  int lim_low = std::max(0, optimal_index - kSearchDecimation);
+  int lim_high =
+      std::min(num_candidate_blocks - 1, optimal_index + kSearchDecimation);
+  return FullSearch(lim_low, lim_high, exclude_interval, target_block,
+                    search_block, energy_target_block.get(),
+                    energy_candidate_blocks.get());
+}
+
+void GetSymmetricHanningWindow(int window_length, float* window) {
+  const float scale = 2.0f * M_PI / window_length;
+  for (int n = 0; n < window_length; ++n)
+    window[n] = 0.5f * (1.0f - cosf(n * scale));
+}
+
+}  // namespace internal
+
+}  // namespace media
+}  // namespace cobalt
diff --git a/src/starboard/shared/starboard/player/filter/wsola_internals.h b/src/starboard/shared/starboard/player/filter/wsola_internals.h
new file mode 100644
index 0000000..4d96b39
--- /dev/null
+++ b/src/starboard/shared/starboard/player/filter/wsola_internals.h
@@ -0,0 +1,83 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A set of utility functions to perform WSOLA.
+
+#ifndef COBALT_MEDIA_FILTERS_WSOLA_INTERNALS_H_
+#define COBALT_MEDIA_FILTERS_WSOLA_INTERNALS_H_
+
+#include <utility>
+
+#include "cobalt/media/base/media_export.h"
+
+namespace cobalt {
+namespace media {
+
+class AudioBus;
+
+namespace internal {
+
+typedef std::pair<int, int> Interval;
+
+// Dot-product of channels of two AudioBus. For each AudioBus an offset is
+// given. |dot_product[k]| is the dot-product of channel |k|. The caller should
+// allocate sufficient space for |dot_product|.
+MEDIA_EXPORT void MultiChannelDotProduct(const AudioBus* a, int frame_offset_a,
+                                         const AudioBus* b, int frame_offset_b,
+                                         int num_frames, float* dot_product);
+
+// Energies of sliding windows of channels are interleaved.
+// The number windows is |input->frames()| - (|frames_per_window| - 1), hence,
+// the method assumes |energy| must be, at least, of size
+// (|input->frames()| - (|frames_per_window| - 1)) * |input->channels()|.
+MEDIA_EXPORT void MultiChannelMovingBlockEnergies(const AudioBus* input,
+                                                  int frames_per_window,
+                                                  float* energy);
+
+// Fit the curve f(x) = a * x^2 + b * x + c such that
+//   f(-1) = y[0]
+//   f(0) = y[1]
+//   f(1) = y[2]
+// and return the maximum, assuming that y[0] <= y[1] >= y[2].
+MEDIA_EXPORT void QuadraticInterpolation(const float* y_values, float* extremum,
+                                         float* extremum_value);
+
+// Search a subset of all candid blocks. The search is performed every
+// |decimation| frames. This reduces complexity by a factor of about
+// 1 / |decimation|. A cubic interpolation is used to have a better estimate of
+// the best match.
+MEDIA_EXPORT int DecimatedSearch(int decimation, Interval exclude_interval,
+                                 const AudioBus* target_block,
+                                 const AudioBus* search_segment,
+                                 const float* energy_target_block,
+                                 const float* energy_candid_blocks);
+
+// Search [|low_limit|, |high_limit|] of |search_segment| to find a block that
+// is most similar to |target_block|. |energy_target_block| is the energy of the
+// |target_block|. |energy_candidate_blocks| is the energy of all blocks within
+// |search_block|.
+MEDIA_EXPORT int FullSearch(int low_limit, int hight_limimit,
+                            Interval exclude_interval,
+                            const AudioBus* target_block,
+                            const AudioBus* search_block,
+                            const float* energy_target_block,
+                            const float* energy_candidate_blocks);
+
+// Find the index of the block, within |search_block|, that is most similar
+// to |target_block|. Obviously, the returned index is w.r.t. |search_block|.
+// |exclude_interval| is an interval that is excluded from the search.
+MEDIA_EXPORT int OptimalIndex(const AudioBus* search_block,
+                              const AudioBus* target_block,
+                              Interval exclude_interval);
+
+// Return a "periodic" Hann window. This is the first L samples of an L+1
+// Hann window. It is perfect reconstruction for overlap-and-add.
+MEDIA_EXPORT void GetSymmetricHanningWindow(int window_length, float* window);
+
+}  // namespace internal
+
+}  // namespace media
+}  // namespace cobalt
+
+#endif  // COBALT_MEDIA_FILTERS_WSOLA_INTERNALS_H_
diff --git a/src/starboard/shared/starboard/string_duplicate.cc b/src/starboard/shared/starboard/string_duplicate.cc
index b5e51d9..b504b16 100644
--- a/src/starboard/shared/starboard/string_duplicate.cc
+++ b/src/starboard/shared/starboard/string_duplicate.cc
@@ -14,12 +14,15 @@
 
 #include "starboard/string.h"
 
+#include "starboard/log.h"
 #include "starboard/memory.h"
 
 char* SbStringDuplicate(const char* source) {
   size_t length = SbStringGetLength(source);
   char* result = static_cast<char*>(SbMemoryAllocate(length + 1));
-  SbStringCopy(result, source, length + 1);
+  SB_DCHECK(length < kSbInt32Max);
+  int int_length = static_cast<int>(length + 1);
+  SbStringCopy(result, source, int_length);
 
   return result;
 }
diff --git a/src/starboard/shared/win32/application_stub.cc b/src/starboard/shared/win32/application_stub.cc
new file mode 100644
index 0000000..1f56080
--- /dev/null
+++ b/src/starboard/shared/win32/application_stub.cc
@@ -0,0 +1,62 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/win32/application_stub.h"
+
+#include "starboard/event.h"
+#include "starboard/log.h"
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+ApplicationStub::ApplicationStub() {
+  SB_NOTIMPLEMENTED();
+}
+
+ApplicationStub::~ApplicationStub() {
+  SB_NOTIMPLEMENTED();
+}
+
+void ApplicationStub::Initialize() {
+  SB_NOTIMPLEMENTED();
+}
+
+void ApplicationStub::Teardown() {
+  SB_NOTIMPLEMENTED();
+}
+
+bool ApplicationStub::MayHaveSystemEvents() {
+  SB_NOTIMPLEMENTED();
+  return false;
+}
+
+shared::starboard::Application::Event* ApplicationStub::PollNextSystemEvent() {
+  SB_NOTIMPLEMENTED();
+  return NULL;
+}
+
+shared::starboard::Application::Event*
+ApplicationStub::WaitForSystemEventWithTimeout(SbTime time) {
+  SB_NOTIMPLEMENTED();
+  return NULL;
+}
+
+void ApplicationStub::WakeSystemEventWait() {
+  SB_NOTIMPLEMENTED();
+}
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/win32/application_stub.h b/src/starboard/shared/win32/application_stub.h
new file mode 100644
index 0000000..c112677
--- /dev/null
+++ b/src/starboard/shared/win32/application_stub.h
@@ -0,0 +1,54 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_WIN32_APPLICATION_STUB_H_
+#define STARBOARD_SHARED_WIN32_APPLICATION_STUB_H_
+
+#include "starboard/configuration.h"
+#include "starboard/shared/internal_only.h"
+#include "starboard/shared/starboard/application.h"
+#include "starboard/shared/starboard/queue_application.h"
+#include "starboard/types.h"
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+// Stub application engine using the generic queue and a stub implementation.
+class ApplicationStub : public shared::starboard::QueueApplication {
+ public:
+  ApplicationStub();
+  ~ApplicationStub() SB_OVERRIDE;
+
+  static ApplicationStub* Get() {
+    return static_cast<ApplicationStub*>(shared::starboard::Application::Get());
+  }
+
+ protected:
+  // --- Application overrides ---
+  void Initialize() SB_OVERRIDE;
+  void Teardown() SB_OVERRIDE;
+
+  // --- QueueApplication overrides ---
+  bool MayHaveSystemEvents() SB_OVERRIDE;
+  Event* PollNextSystemEvent() SB_OVERRIDE;
+  Event* WaitForSystemEventWithTimeout(SbTime time) SB_OVERRIDE;
+  void WakeSystemEventWait() SB_OVERRIDE;
+};
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_WIN32_APPLICATION_STUB_H_
diff --git a/src/starboard/shared/win32/byte_swap.cc b/src/starboard/shared/win32/byte_swap.cc
new file mode 100644
index 0000000..45f4fd9
--- /dev/null
+++ b/src/starboard/shared/win32/byte_swap.cc
@@ -0,0 +1,44 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Not breaking these functions up because however one is implemented, the
+// others should be implemented similarly.
+
+#include "starboard/byte_swap.h"
+
+#include <stdlib.h>
+
+int16_t SbByteSwapS16(int16_t value) {
+  return _byteswap_ushort(value);
+}
+
+uint16_t SbByteSwapU16(uint16_t value) {
+  return _byteswap_ushort(value);
+}
+
+int32_t SbByteSwapS32(int32_t value) {
+  return _byteswap_ulong(value);
+}
+
+uint32_t SbByteSwapU32(uint32_t value) {
+  return _byteswap_ulong(value);
+}
+
+int64_t SbByteSwapS64(int64_t value) {
+  return _byteswap_uint64(value);
+}
+
+uint64_t SbByteSwapU64(uint64_t value) {
+  return _byteswap_uint64(value);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/condition_variable_broadcast.cc
similarity index 68%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/condition_variable_broadcast.cc
index 51e1f2e..f2b9ea5 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/condition_variable_broadcast.cc
@@ -12,9 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/condition_variable.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+bool SbConditionVariableBroadcast(SbConditionVariable* condition) {
+  if (!condition) {
+    return false;
+  }
+  WakeAllConditionVariable(reinterpret_cast<PCONDITION_VARIABLE>(condition));
+  return true;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/condition_variable_create.cc
similarity index 63%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/condition_variable_create.cc
index 51e1f2e..9d74a6f 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/condition_variable_create.cc
@@ -12,9 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/condition_variable.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+bool SbConditionVariableCreate(SbConditionVariable* out_condition,
+                               SbMutex* /*opt_mutex*/) {
+  if (!out_condition) {
+    return false;
+  }
+  InitializeConditionVariable(
+      reinterpret_cast<PCONDITION_VARIABLE>(out_condition));
+  return true;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/condition_variable_destroy.cc
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/condition_variable_destroy.cc
index 51e1f2e..4a24e47 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/condition_variable_destroy.cc
@@ -12,9 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/condition_variable.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+bool SbConditionVariableDestroy(SbConditionVariable* condition) {
+  if (!condition) {
+    return false;
+  }
+  return true;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/condition_variable_signal.cc
similarity index 69%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/condition_variable_signal.cc
index 51e1f2e..5e8e67b 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/condition_variable_signal.cc
@@ -12,9 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/condition_variable.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+bool SbConditionVariableSignal(SbConditionVariable* condition) {
+  if (!condition) {
+    return false;
+  }
+  WakeConditionVariable(reinterpret_cast<PCONDITION_VARIABLE>(condition));
+  return true;
+}
diff --git a/src/starboard/shared/win32/condition_variable_wait.cc b/src/starboard/shared/win32/condition_variable_wait.cc
new file mode 100644
index 0000000..a224afc
--- /dev/null
+++ b/src/starboard/shared/win32/condition_variable_wait.cc
@@ -0,0 +1,30 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/condition_variable.h"
+
+#include <windows.h>
+
+SbConditionVariableResult SbConditionVariableWait(
+    SbConditionVariable* condition,
+    SbMutex* mutex) {
+  if (!condition || !mutex) {
+    return kSbConditionVariableFailed;
+  }
+  bool result = SleepConditionVariableSRW(
+      reinterpret_cast<PCONDITION_VARIABLE>(condition),
+      reinterpret_cast<PSRWLOCK>(mutex), INFINITE, 0);
+
+  return result ? kSbConditionVariableSignaled : kSbConditionVariableFailed;
+}
diff --git a/src/starboard/shared/win32/condition_variable_wait_timed.cc b/src/starboard/shared/win32/condition_variable_wait_timed.cc
new file mode 100644
index 0000000..e967695
--- /dev/null
+++ b/src/starboard/shared/win32/condition_variable_wait_timed.cc
@@ -0,0 +1,54 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/condition_variable.h"
+
+#include <windows.h>
+
+#include "starboard/shared/win32/time_utils.h"
+
+using starboard::shared::win32::ConvertSbTimeToMillisRoundUp;
+
+SbConditionVariableResult SbConditionVariableWaitTimed(
+    SbConditionVariable* condition,
+    SbMutex* mutex,
+    SbTime timeout) {
+  if (!condition || !mutex) {
+    return kSbConditionVariableFailed;
+  }
+
+  if (timeout < 0) {
+    timeout = 0;
+  }
+  bool result = SleepConditionVariableSRW(
+      reinterpret_cast<PCONDITION_VARIABLE>(condition),
+      reinterpret_cast<PSRWLOCK>(mutex),
+      ConvertSbTimeToMillisRoundUp(timeout), 0);
+
+  if (timeout == 0) {
+    // Per documentation, "If the |timeout_duration| value is less than
+    // or equal to zero, the function returns as quickly as possible with a
+    // kSbConditionVariableTimedOut result."
+    return kSbConditionVariableTimedOut;
+  }
+
+  if (result) {
+    return kSbConditionVariableSignaled;
+  }
+
+  if (GetLastError() == ERROR_TIMEOUT) {
+    return kSbConditionVariableTimedOut;
+  }
+  return kSbConditionVariableFailed;
+}
diff --git a/src/starboard/shared/win32/directory_can_open.cc b/src/starboard/shared/win32/directory_can_open.cc
new file mode 100644
index 0000000..b64a410
--- /dev/null
+++ b/src/starboard/shared/win32/directory_can_open.cc
@@ -0,0 +1,48 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/directory.h"
+
+#include <windows.h>
+
+#include <algorithm>
+
+#include "starboard/shared/win32/directory_internal.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+bool SbDirectoryCanOpen(const char* path) {
+  if ((path == nullptr) || (path[0] == '\0')) {
+    return false;
+  }
+
+  std::wstring path_wstring = starboard::shared::win32::CStringToWString(path);
+  starboard::shared::win32::TrimExtraFileSeparators(&path_wstring);
+
+  if (!starboard::shared::win32::IsAbsolutePath(path_wstring)) {
+    return false;
+  }
+
+  WIN32_FIND_DATA find_data = {0};
+
+  HANDLE search_handle = FindFirstFileExW(
+      path_wstring.c_str(), FindExInfoStandard, &find_data,
+      FindExSearchNameMatch, NULL, FIND_FIRST_EX_CASE_SENSITIVE);
+  if (!starboard::shared::win32::IsValidHandle(search_handle)) {
+    return false;
+  }
+
+  FindClose(search_handle);
+
+  return find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/directory_close.cc
similarity index 64%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/directory_close.cc
index 51e1f2e..6d7765a 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/directory_close.cc
@@ -12,9 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/directory.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+#include "starboard/shared/win32/directory_internal.h"
+
+bool SbDirectoryClose(SbDirectory directory) {
+  if (!SbDirectoryIsValid(directory)) {
+    return false;
+  }
+
+  bool success = CloseHandle(directory->directory_handle);
+
+  delete directory;
+
+  return success;
+}
diff --git a/src/starboard/shared/win32/directory_create.cc b/src/starboard/shared/win32/directory_create.cc
new file mode 100644
index 0000000..26b1845
--- /dev/null
+++ b/src/starboard/shared/win32/directory_create.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/directory.h"
+
+#include <windows.h>
+
+#include "starboard/shared/win32/directory_internal.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+bool SbDirectoryCreate(const char* path) {
+  if ((path == nullptr) || (path[0] == '\0')) {
+    return false;
+  }
+
+  std::wstring path_wstring = starboard::shared::win32::CStringToWString(path);
+
+  starboard::shared::win32::TrimExtraFileSeparators(&path_wstring);
+
+  if (!starboard::shared::win32::IsAbsolutePath(path_wstring)) {
+    return false;
+  }
+
+  BOOL directory_created = CreateDirectoryW(path_wstring.c_str(), NULL);
+
+  bool directory_exists =
+      directory_created || (GetLastError() == ERROR_ALREADY_EXISTS);
+
+  return directory_exists;
+}
diff --git a/src/starboard/shared/win32/directory_get_next.cc b/src/starboard/shared/win32/directory_get_next.cc
new file mode 100644
index 0000000..514c1b6
--- /dev/null
+++ b/src/starboard/shared/win32/directory_get_next.cc
@@ -0,0 +1,94 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/directory.h"
+
+#include <windows.h>
+
+#include "starboard/log.h"
+#include "starboard/string.h"
+#include "starboard/shared/win32/directory_internal.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+namespace {
+// One of the entries of FILE_ID_BOTH_DIR_INFO is a file path, so make the
+// buffer at-least one path big.
+const std::size_t kDirectoryInfoBufferSize =
+    SB_FILE_MAX_PATH + sizeof(FILE_ID_BOTH_DIR_INFO);
+
+std::deque<std::string> GetDirectoryEntries(HANDLE directory_handle) {
+  // According to
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364226(v=vs.85).aspx,
+  // FILE_ID_BOTH_DIR_INFO must be aligned on a DWORDLONG boundary.
+  alignas(
+      sizeof(DWORDLONG)) char directory_info_buffer[kDirectoryInfoBufferSize];
+
+  std::deque<std::string> entries;
+  BOOL directory_info_success = GetFileInformationByHandleEx(
+      directory_handle, FileIdBothDirectoryInfo, directory_info_buffer,
+      SB_ARRAY_SIZE(directory_info_buffer));
+
+  if (!directory_info_success) {
+    return entries;
+  }
+
+  const char* directory_info_pointer = directory_info_buffer;
+  DWORD next_entry_offset = 0;
+
+  do {
+    auto directory_info =
+        reinterpret_cast<const FILE_ID_BOTH_DIR_INFO*>(directory_info_pointer);
+
+    // FileName is in Unicode, so divide by 2 to get the real length.
+    DWORD number_characters_in_filename = directory_info->FileNameLength / 2;
+    std::string ascii_path = starboard::shared::win32::wchar_tToUTF8(
+        directory_info->FileName, number_characters_in_filename);
+    SB_DCHECK(ascii_path.size() == number_characters_in_filename);
+    bool is_dotted_directory =
+        !ascii_path.compare(".") || !ascii_path.compare("..");
+    if (!is_dotted_directory) {
+      entries.emplace_back(std::move(ascii_path));
+    }
+    next_entry_offset = directory_info->NextEntryOffset;
+    directory_info_pointer += next_entry_offset;
+  } while (next_entry_offset != 0);
+
+  return entries;
+}
+
+}  // namespace
+
+bool SbDirectoryGetNext(SbDirectory directory, SbDirectoryEntry* out_entry) {
+  if (!SbDirectoryIsValid(directory) || (out_entry == nullptr)) {
+    return false;
+  }
+
+  auto& next_directory_entries = directory->next_directory_entries;
+  if (next_directory_entries.empty()) {
+    next_directory_entries = GetDirectoryEntries(directory->directory_handle);
+  }
+
+  if (next_directory_entries.empty()) {
+    return false;
+  }
+
+  bool success = true;
+  const int entry_name_size = SB_ARRAY_SIZE_INT(out_entry->name);
+  if (SbStringCopy(out_entry->name, next_directory_entries.rbegin()->c_str(),
+                   entry_name_size) >= entry_name_size) {
+    success = false;
+  }
+  directory->next_directory_entries.pop_back();
+  return success;
+}
diff --git a/src/starboard/shared/win32/directory_internal.h b/src/starboard/shared/win32/directory_internal.h
new file mode 100644
index 0000000..f27fff9
--- /dev/null
+++ b/src/starboard/shared/win32/directory_internal.h
@@ -0,0 +1,97 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_WIN32_DIRECTORY_INTERNAL_H_
+#define STARBOARD_SHARED_WIN32_DIRECTORY_INTERNAL_H_
+
+#include "starboard/directory.h"
+
+#include <algorithm>
+#include <deque>
+#include <string>
+
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/shared/internal_only.h"
+#include "starboard/shared/win32/file_internal.h"
+
+#pragma warning(push)
+
+// SbFilePrivate is defined as a struct, but for windows implementation
+// enough functionality has been added so that it warrants being a class
+// per Google's C++ style guide.  This mismatch causes the Microsoft's compiler
+// to generate a warning.
+#pragma warning(disable : 4099)
+
+class SbDirectoryPrivate {
+ public:
+  explicit SbDirectoryPrivate(HANDLE handle) : directory_handle(handle) {}
+
+  bool HasValidHandle() const {
+    return starboard::shared::win32::IsValidHandle(directory_handle);
+  }
+
+  HANDLE directory_handle;
+  std::deque<std::string> next_directory_entries;
+
+  // SbDirectoryPrivate is neither copyable nor movable.
+  SbDirectoryPrivate(const SbDirectoryPrivate&) = delete;
+  SbDirectoryPrivate& operator=(const SbDirectoryPrivate&) = delete;
+};
+#pragma warning(pop)
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+inline bool HasValidHandle(SbDirectory directory) {
+  if (!SbDirectoryIsValid(directory)) {
+    return false;
+  }
+
+  return directory->HasValidHandle();
+}
+
+// This function strips trailing file separators from a directory name.
+// For example if the directory name was "C:\\Temp\\\\\\", it would
+// strip them, so that the directory name is now to be "C:\\temp".
+inline void TrimExtraFileSeparators(std::wstring* dirname_pointer) {
+  SB_DCHECK(dirname_pointer);
+  std::wstring& dirname = *dirname_pointer;
+  auto new_end =
+      std::find_if_not(dirname.rbegin(), dirname.rend(), [](wchar_t c) {
+        return c == SB_FILE_SEP_CHAR || c == SB_FILE_ALT_SEP_CHAR;
+      });
+  dirname.erase(new_end.base(), dirname.end());
+}
+
+inline bool IsAbsolutePath(const std::wstring& path) {
+  wchar_t full_path[SB_FILE_MAX_PATH];
+  DWORD full_path_size =
+      GetFullPathNameW(path.c_str(), SB_ARRAY_SIZE(full_path), full_path, NULL);
+  if (full_path_size == 0) {
+    return false;
+  }
+
+  int path_size = static_cast<int>(path.size());
+  return CompareStringEx(LOCALE_NAME_USER_DEFAULT, NORM_IGNORECASE,
+                         path.c_str(), path_size, full_path, full_path_size,
+                         NULL, NULL, 0) == CSTR_EQUAL;
+}
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_WIN32_DIRECTORY_INTERNAL_H_
diff --git a/src/starboard/shared/win32/directory_open.cc b/src/starboard/shared/win32/directory_open.cc
new file mode 100644
index 0000000..6dade7e
--- /dev/null
+++ b/src/starboard/shared/win32/directory_open.cc
@@ -0,0 +1,58 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/directory.h"
+
+#include "starboard/shared/win32/directory_internal.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+SbDirectory SbDirectoryOpen(const char* path, SbFileError* out_error) {
+  if ((path == nullptr) || (path[0] == '\0')) {
+    if (out_error) {
+      *out_error = kSbFileErrorNotFound;
+    }
+    return kSbDirectoryInvalid;
+  }
+
+  std::wstring path_wstring = starboard::shared::win32::CStringToWString(path);
+
+  if (!starboard::shared::win32::IsAbsolutePath(path_wstring)) {
+    if (out_error) {
+      *out_error = kSbFileErrorNotFound;
+    }
+    return kSbDirectoryInvalid;
+  }
+
+  HANDLE directory_handle = starboard::shared::win32::OpenFileOrDirectory(
+      path, kSbFileOpenOnly | kSbFileRead, nullptr, out_error);
+
+  if (!starboard::shared::win32::IsValidHandle(directory_handle)) {
+    return kSbDirectoryInvalid;
+  }
+
+  FILE_BASIC_INFO basic_info = {0};
+  BOOL basic_info_success = GetFileInformationByHandleEx(
+      directory_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO));
+
+  if (!basic_info_success ||
+      !(basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+    CloseHandle(directory_handle);
+    if (out_error) {
+      *out_error = kSbFileErrorNotADirectory;
+    }
+    return kSbDirectoryInvalid;
+  }
+
+  return new SbDirectoryPrivate(directory_handle);
+}
diff --git a/src/starboard/shared/win32/file_can_open.cc b/src/starboard/shared/win32/file_can_open.cc
new file mode 100644
index 0000000..f4f19f6
--- /dev/null
+++ b/src/starboard/shared/win32/file_can_open.cc
@@ -0,0 +1,53 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/file.h"
+
+#include <windows.h>
+
+#include "starboard/shared/win32/file_internal.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+bool SbFileCanOpen(const char* path, int flags) {
+  if ((path == nullptr) || (path[0] == '\0')) {
+    return false;
+  }
+
+  bool can_read = flags & kSbFileRead;
+  bool can_write = flags & kSbFileWrite;
+  if (!can_read && !can_write) {
+    return false;
+  }
+
+  std::wstring path_wstring = starboard::shared::win32::CStringToWString(path);
+  WIN32_FIND_DATA find_data = {0};
+
+  HANDLE search_handle = FindFirstFileExW(
+      path_wstring.c_str(), FindExInfoStandard, &find_data,
+      FindExSearchNameMatch, NULL, FIND_FIRST_EX_CASE_SENSITIVE);
+  if (!starboard::shared::win32::IsValidHandle(search_handle)) {
+    return false;
+  }
+
+  bool can_open = true;
+
+  if (((find_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) && can_write) ||
+      !starboard::shared::win32::PathEndsWith(path_wstring, find_data.cFileName)) {
+    can_open = false;
+  }
+
+  FindClose(search_handle);
+
+  return can_open;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/file_close.cc
similarity index 68%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/file_close.cc
index 51e1f2e..ce61c54 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/file_close.cc
@@ -12,9 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/file.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+#include "starboard/shared/win32/file_internal.h"
+
+bool SbFileClose(SbFile file) {
+  if (!SbFileIsValid(file)) {
+    return false;
+  }
+
+  bool success = CloseHandle(file->file_handle);
+
+  delete file;
+
+  return success;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/file_delete.cc
similarity index 61%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/file_delete.cc
index 51e1f2e..fecbfd1 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/file_delete.cc
@@ -12,9 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/file.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+#include "starboard/shared/win32/file_internal.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+bool SbFileDelete(const char* path) {
+  if ((path == nullptr) || *path == '\0') {
+    return false;
+  }
+
+  std::wstring path_wstring = starboard::shared::win32::CStringToWString(path);
+
+  return DeleteFileW(path_wstring.c_str());
+}
diff --git a/src/starboard/shared/win32/file_exists.cc b/src/starboard/shared/win32/file_exists.cc
new file mode 100644
index 0000000..160f17d
--- /dev/null
+++ b/src/starboard/shared/win32/file_exists.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/file.h"
+
+#include <windows.h>
+
+#include "starboard/shared/win32/file_internal.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+bool SbFileExists(const char* path) {
+  if ((path == nullptr) || (path[0] == '\0')) {
+    return false;
+  }
+
+  std::wstring path_wstring = starboard::shared::win32::CStringToWString(path);
+  WIN32_FIND_DATA find_data = {0};
+
+  HANDLE search_handle = FindFirstFileExW(
+      path_wstring.c_str(), FindExInfoStandard, &find_data,
+      FindExSearchNameMatch, NULL, FIND_FIRST_EX_CASE_SENSITIVE);
+
+  if (!starboard::shared::win32::IsValidHandle(search_handle)) {
+    return false;
+  }
+
+  FindClose(search_handle);
+
+  return starboard::shared::win32::PathEndsWith(path_wstring, find_data.cFileName);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/file_flush.cc
similarity index 67%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/file_flush.cc
index 51e1f2e..1c9655c 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/file_flush.cc
@@ -12,9 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/file.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/file_internal.h"
+
+bool SbFileFlush(SbFile file) {
+  if (!starboard::shared::win32::HasValidHandle(file)) {
+    return false;
+  }
+
+  return FlushFileBuffers(file->file_handle);
+}
diff --git a/src/starboard/shared/win32/file_get_info.cc b/src/starboard/shared/win32/file_get_info.cc
new file mode 100644
index 0000000..9a25753
--- /dev/null
+++ b/src/starboard/shared/win32/file_get_info.cc
@@ -0,0 +1,59 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/file.h"
+
+#include <windows.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/file_internal.h"
+#include "starboard/shared/win32/time_utils.h"
+
+bool SbFileGetInfo(SbFile file, SbFileInfo* out_info) {
+  if (!starboard::shared::win32::HasValidHandle(file) || !out_info) {
+    return false;
+  }
+
+  FILE_BASIC_INFO basic_info = {0};
+  BOOL basic_info_success = GetFileInformationByHandleEx(
+      file->file_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO));
+  if (!basic_info_success) {
+    return false;
+  }
+
+  FILE_STANDARD_INFO standard_info = {0};
+  BOOL standard_info_success =
+      GetFileInformationByHandleEx(file->file_handle, FileStandardInfo,
+                                   &standard_info, sizeof(FILE_STANDARD_INFO));
+  if (!standard_info_success) {
+    return false;
+  }
+
+  out_info->size = standard_info.EndOfFile.QuadPart;
+  SB_DCHECK(out_info->size >= 0);
+
+  using starboard::shared::win32::ConvertFileTimeTicksToSbTime;
+
+  out_info->creation_time =
+      ConvertFileTimeTicksToSbTime(basic_info.CreationTime);
+  out_info->last_accessed =
+      ConvertFileTimeTicksToSbTime(basic_info.LastAccessTime);
+  out_info->last_modified =
+      ConvertFileTimeTicksToSbTime(basic_info.LastWriteTime);
+
+  out_info->is_symbolic_link = false;
+  out_info->is_directory = standard_info.Directory;
+
+  return true;
+}
diff --git a/src/starboard/shared/win32/file_get_path_info.cc b/src/starboard/shared/win32/file_get_path_info.cc
new file mode 100644
index 0000000..4ac6928
--- /dev/null
+++ b/src/starboard/shared/win32/file_get_path_info.cc
@@ -0,0 +1,55 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/file.h"
+
+#include <windows.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/file_internal.h"
+#include "starboard/shared/win32/time_utils.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+bool SbFileGetPathInfo(const char* path, SbFileInfo* out_info) {
+  if (!path || path[0] == '\0' || !out_info) {
+    return false;
+  }
+
+  std::wstring path_wstring = starboard::shared::win32::CStringToWString(path);
+
+  WIN32_FILE_ATTRIBUTE_DATA attribute_data = {0};
+  if (!GetFileAttributesExW(path_wstring.c_str(), GetFileExInfoStandard,
+                            &attribute_data)) {
+    return false;
+  }
+
+  out_info->size = static_cast<int64_t>(attribute_data.nFileSizeHigh) << 32 |
+                   attribute_data.nFileSizeLow;
+  SB_DCHECK(out_info->size >= 0);
+
+  using starboard::shared::win32::ConvertFileTimeToSbTime;
+
+  out_info->creation_time =
+      ConvertFileTimeToSbTime(attribute_data.ftCreationTime);
+  out_info->last_accessed =
+      ConvertFileTimeToSbTime(attribute_data.ftLastAccessTime);
+  out_info->last_modified =
+      ConvertFileTimeToSbTime(attribute_data.ftLastWriteTime);
+
+  out_info->is_symbolic_link = false;
+  out_info->is_directory =
+      (attribute_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+
+  return true;
+}
diff --git a/src/starboard/shared/win32/file_internal.cc b/src/starboard/shared/win32/file_internal.cc
new file mode 100644
index 0000000..a2d7621
--- /dev/null
+++ b/src/starboard/shared/win32/file_internal.cc
@@ -0,0 +1,142 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/win32/file_internal.h"
+
+#include <windows.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+HANDLE OpenFileOrDirectory(const char* path,
+                           int flags,
+                           bool* out_created,
+                           SbFileError* out_error) {
+  const DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+  DWORD creation_disposition = 0;
+  if (flags & kSbFileCreateOnly) {
+    SB_DCHECK(!creation_disposition);
+    SB_DCHECK(!(flags & kSbFileCreateAlways));
+    creation_disposition = CREATE_NEW;
+  }
+
+  if (out_created) {
+    *out_created = false;
+  }
+
+  if (flags & kSbFileCreateAlways) {
+    SB_DCHECK(!creation_disposition);
+    SB_DCHECK(!(flags & kSbFileCreateOnly));
+    creation_disposition = CREATE_ALWAYS;
+  }
+
+  if (flags & kSbFileOpenTruncated) {
+    SB_DCHECK(!creation_disposition);
+    SB_DCHECK(flags & kSbFileWrite);
+    creation_disposition = TRUNCATE_EXISTING;
+  }
+
+  if (flags & kSbFileOpenOnly) {
+    SB_DCHECK(!(flags & kSbFileOpenAlways));
+    creation_disposition = OPEN_EXISTING;
+  }
+
+  if (flags & kSbFileOpenAlways) {
+    SB_DCHECK(!(flags & kSbFileOpenOnly));
+    creation_disposition = OPEN_ALWAYS;
+  }
+
+  if (!creation_disposition && !(flags & kSbFileOpenOnly) &&
+      !(flags & kSbFileOpenAlways)) {
+    SB_NOTREACHED();
+    errno = ENOTSUP;
+    if (out_error) {
+      *out_error = kSbFileErrorFailed;
+    }
+
+    return kSbFileInvalid;
+  }
+
+  DWORD desired_access = 0;
+  if (flags & kSbFileRead) {
+    desired_access |= GENERIC_READ;
+  }
+
+  const bool open_file_in_write_mode = flags & kSbFileWrite;
+  if (open_file_in_write_mode) {
+    desired_access |= GENERIC_WRITE;
+  }
+
+  // TODO: Support asynchronous IO, if necessary.
+  SB_DCHECK(!(flags & kSbFileAsync));
+
+  SB_DCHECK(desired_access != 0) << "Invalid permission flag.";
+
+  std::wstring path_wstring = starboard::shared::win32::CStringToWString(path);
+
+  CREATEFILE2_EXTENDED_PARAMETERS create_ex_params = {0};
+  // Enabling |FILE_FLAG_BACKUP_SEMANTICS| allows us to figure out if the path
+  // is a directory.
+  create_ex_params.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
+  create_ex_params.dwFileFlags |= FILE_FLAG_POSIX_SEMANTICS;
+  create_ex_params.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
+  create_ex_params.dwSecurityQosFlags = SECURITY_ANONYMOUS;
+  create_ex_params.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
+
+  HANDLE file_handle =
+      CreateFile2(path_wstring.c_str(), desired_access, share_mode,
+                  creation_disposition, &create_ex_params);
+
+  if (out_created) {
+    if (flags & (kSbFileCreateAlways | kSbFileCreateOnly)) {
+      *out_created = starboard::shared::win32::IsValidHandle(file_handle);
+    }
+
+    if ((creation_disposition == OPEN_ALWAYS) && (open_file_in_write_mode)) {
+      *out_created = (GetLastError() != ERROR_ALREADY_EXISTS);
+    }
+  }
+
+  if (out_error) {
+    if (starboard::shared::win32::IsValidHandle(file_handle)) {
+      *out_error = kSbFileOk;
+    } else {
+      const DWORD last_error = GetLastError();
+      switch (last_error) {
+        case ERROR_ACCESS_DENIED:
+          *out_error = kSbFileErrorAccessDenied;
+          break;
+        case ERROR_FILE_EXISTS:
+          *out_error = kSbFileErrorAccessDenied;
+          break;
+        case ERROR_FILE_NOT_FOUND:
+          *out_error = kSbFileErrorNotFound;
+          break;
+        default:
+          *out_error = kSbFileErrorFailed;
+      }
+    }
+  }
+
+  return file_handle;
+}
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/win32/file_internal.h b/src/starboard/shared/win32/file_internal.h
new file mode 100644
index 0000000..56a8a13
--- /dev/null
+++ b/src/starboard/shared/win32/file_internal.h
@@ -0,0 +1,94 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_WIN32_FILE_INTERNAL_H_
+#define STARBOARD_SHARED_WIN32_FILE_INTERNAL_H_
+
+#include <wtypes.h>
+
+#include <cwchar>  // This file included for std::wcslen.
+#include <string>
+
+#include "starboard/file.h"
+#include "starboard/shared/internal_only.h"
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+inline bool IsValidHandle(HANDLE handle) {
+  return handle != INVALID_HANDLE_VALUE;
+}
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+#pragma warning(push)
+
+// SbFilePrivate is defined as a struct, but for windows implementation
+// enough functionality has been added so that it warrants being a class
+// per Google's C++ style guide.  This mismatch causes the Microsoft's compiler
+// to generate a warning.
+#pragma warning(disable : 4099)
+
+class SbFilePrivate {
+ public:
+  explicit SbFilePrivate(HANDLE handle) : file_handle(handle) {}
+
+  bool HasValidHandle() const {
+    return starboard::shared::win32::IsValidHandle(file_handle);
+  }
+
+  HANDLE file_handle;
+
+  // SbFilePrivate is neither copyable nor movable.
+  SbFilePrivate(const SbFilePrivate&) = delete;
+  SbFilePrivate& operator=(const SbFilePrivate&) = delete;
+};
+#pragma warning(pop)
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+inline bool HasValidHandle(SbFile file) {
+  if (!SbFileIsValid(file)) {
+    return false;
+  }
+
+  return file->HasValidHandle();
+}
+
+inline bool PathEndsWith(const std::wstring& path, const wchar_t* filename) {
+  size_t filename_length = std::wcslen(filename);
+  if (filename_length > path.size()) {
+    return false;
+  }
+
+  size_t path_offset = path.size() - filename_length;
+
+  return wcscmp(path.c_str() + path_offset, filename) == 0;
+}
+
+HANDLE OpenFileOrDirectory(const char* path,
+                           int flags,
+                           bool* out_created,
+                           SbFileError* out_error);
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_WIN32_FILE_INTERNAL_H_
diff --git a/src/starboard/shared/win32/file_open.cc b/src/starboard/shared/win32/file_open.cc
new file mode 100644
index 0000000..78407c5
--- /dev/null
+++ b/src/starboard/shared/win32/file_open.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/file.h"
+
+#include "starboard/shared/win32/file_internal.h"
+
+SbFile SbFileOpen(const char* path,
+                  int flags,
+                  bool* out_created,
+                  SbFileError* out_error) {
+  if ((path == nullptr) || (path[0] == '\0')) {
+    if (out_created) {
+      *out_created = false;
+    }
+    if (out_error) {
+      *out_error = kSbFileErrorNotAFile;
+    }
+    return kSbFileInvalid;
+  }
+
+  HANDLE file_handle =
+      starboard::shared::win32::OpenFileOrDirectory(path, flags, out_created, out_error);
+
+  if (!starboard::shared::win32::IsValidHandle(file_handle)) {
+    return kSbFileInvalid;
+  }
+
+  return new SbFilePrivate(file_handle);
+}
diff --git a/src/starboard/shared/win32/file_read.cc b/src/starboard/shared/win32/file_read.cc
new file mode 100644
index 0000000..b2e6db8
--- /dev/null
+++ b/src/starboard/shared/win32/file_read.cc
@@ -0,0 +1,47 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/file.h"
+
+#include <windows.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/file_internal.h"
+
+int SbFileRead(SbFile file, char* data, int size) {
+  SB_DCHECK((size == 0) || (data != nullptr));
+
+  if (!starboard::shared::win32::HasValidHandle(file)) {
+    return -1;
+  }
+
+  if (size < 0) {
+    SB_NOTREACHED();
+    return -1;
+  } else if (size == 0) {
+    return 0;
+  }
+
+  DWORD number_bytes_read = 0;
+  BOOL success =
+      ReadFile(file->file_handle, data, size, &number_bytes_read, nullptr);
+
+  // Since we are only doing synchornous IO, success == FALSE implies that
+  // something is wrong.
+  if (!success) {
+    return -1;
+  }
+
+  return number_bytes_read;
+}
diff --git a/src/starboard/shared/win32/file_seek.cc b/src/starboard/shared/win32/file_seek.cc
new file mode 100644
index 0000000..54f56fa
--- /dev/null
+++ b/src/starboard/shared/win32/file_seek.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/file.h"
+
+#include <windows.h>
+
+#include "starboard/shared/win32/file_internal.h"
+
+int64_t SbFileSeek(SbFile file, SbFileWhence whence, int64_t offset) {
+  if (!starboard::shared::win32::HasValidHandle(file)) {
+    return -1;
+  }
+
+  LARGE_INTEGER new_file_pointer = {0};
+  LARGE_INTEGER offset_argument = {0};
+  offset_argument.QuadPart = offset;
+  BOOL success =
+      SetFilePointerEx(file->file_handle, offset_argument, &new_file_pointer,
+                       static_cast<DWORD>(whence));
+
+  if (!success) {
+    return -1;
+  }
+
+  return new_file_pointer.QuadPart;
+}
diff --git a/src/starboard/shared/win32/file_truncate.cc b/src/starboard/shared/win32/file_truncate.cc
new file mode 100644
index 0000000..dd2626b
--- /dev/null
+++ b/src/starboard/shared/win32/file_truncate.cc
@@ -0,0 +1,102 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/file.h"
+
+#include <windows.h>
+
+#include <algorithm>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/file_internal.h"
+
+namespace {
+static const char k4KZeroPage[4 * 1024] = {0};
+
+bool WriteZerosToFile(HANDLE file_handle,
+                      LARGE_INTEGER begin,
+                      LARGE_INTEGER end) {
+  SB_DCHECK(starboard::shared::win32::IsValidHandle(file_handle));
+  int64_t bytes_left_to_write = end.QuadPart - begin.QuadPart;
+  if (bytes_left_to_write <= 0) {
+    return true;
+  }
+
+  // Set the file pointer to |begin|.
+  if (!SetFilePointerEx(file_handle, begin, NULL, FILE_BEGIN)) {
+    return false;
+  }
+
+  // Write from zeros from |begin| to |end|.
+  while (bytes_left_to_write > 0) {
+    int64_t bytes_to_write =
+        std::min<int64_t>(SB_ARRAY_SIZE(k4KZeroPage), bytes_left_to_write);
+    SB_DCHECK(bytes_to_write <= kSbInt32Max);
+
+    DWORD bytes_written = 0;
+    if (!WriteFile(file_handle, k4KZeroPage, static_cast<int>(bytes_to_write),
+                   &bytes_written, NULL)) {
+      return false;
+    }
+
+    bytes_left_to_write -= bytes_written;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+bool SbFileTruncate(SbFile file, int64_t length) {
+  if (!starboard::shared::win32::HasValidHandle(file) || length < 0) {
+    return false;
+  }
+
+  HANDLE file_handle = file->file_handle;
+
+  // Get current position.
+  LARGE_INTEGER current_position = {0};
+  BOOL success =
+      SetFilePointerEx(file_handle, {0}, &current_position, FILE_CURRENT);
+
+  if (!success) {
+    return false;
+  }
+
+  bool return_value = false;
+  do {
+    LARGE_INTEGER old_eof = {0};
+    if (!SetFilePointerEx(file_handle, {0}, &old_eof, FILE_END)) {
+      break;
+    }
+
+    LARGE_INTEGER new_eof = {0};
+    new_eof.QuadPart = length;
+    if (!SetFilePointerEx(file_handle, new_eof, NULL, FILE_BEGIN)) {
+      break;
+    }
+
+    if (!SetEndOfFile(file_handle)) {
+      break;
+    }
+
+    WriteZerosToFile(file_handle, old_eof, new_eof);
+    return_value = true;
+  } while (0);
+
+  // Set the file pointer position back where it was.
+  SetFilePointerEx(file_handle, current_position, NULL, FILE_BEGIN);
+
+  return return_value;
+}
diff --git a/src/starboard/shared/win32/file_write.cc b/src/starboard/shared/win32/file_write.cc
new file mode 100644
index 0000000..d63bf68
--- /dev/null
+++ b/src/starboard/shared/win32/file_write.cc
@@ -0,0 +1,42 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/file.h"
+
+#include <windows.h>
+
+#include "starboard/log.h"
+#include "starboard/shared/win32/file_internal.h"
+
+int SbFileWrite(SbFile file, const char* data, int size) {
+  // TODO: Support asynchronous IO, if necessary.
+  SB_DCHECK((size == 0) || (data != nullptr));
+  if (!SbFileIsValid(file)) {
+    return -1;
+  }
+  if (size < 0) {
+    SB_NOTREACHED();
+    return -1;
+  } else if (size == 0) {
+    return 0;
+  }
+
+  DWORD bytes_written = 0;
+  bool success = WriteFile(file->file_handle, data, size, &bytes_written, NULL);
+  if (!success) {
+    return -1;
+  }
+
+  return bytes_written;
+}
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/log.cc
similarity index 76%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/log.cc
index 4723bfb..7e1cb85 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/log.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/log.h"
 
-#include <cmath>
-
-#endif  // COBALT_BASE_MATH_H_
+void SbLog(SbLogPriority /*priority*/, const char* message) {
+  SbLogRaw(message);
+}
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/log_flush.cc
similarity index 77%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/log_flush.cc
index 4723bfb..a75af43 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/log_flush.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/log.h"
 
-#include <cmath>
+#include <stdio.h>
 
-#endif  // COBALT_BASE_MATH_H_
+void SbLogFlush() {
+  fflush(stderr);
+}
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/log_format.cc
similarity index 75%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/log_format.cc
index 4723bfb..ef5430b 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/log_format.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/log.h"
 
-#include <cmath>
-
-#endif  // COBALT_BASE_MATH_H_
+void SbLogFormat(const char* format, va_list arguments) {
+  SbLogRawFormat(format, arguments);
+}
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/log_is_tty.cc
similarity index 77%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/log_is_tty.cc
index 4723bfb..40dbc77 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/log_is_tty.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/log.h"
 
-#include <cmath>
-
-#endif  // COBALT_BASE_MATH_H_
+bool SbLogIsTty() {
+  return false;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/log_raw.cc
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/log_raw.cc
index 51e1f2e..d33f086 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/log_raw.cc
@@ -12,9 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/log.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <stdio.h>
+#include <windows.h>
+
+void SbLogRaw(const char* message) {
+  fprintf(stderr, "%s", message);
+  OutputDebugStringA(message);
+}
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/log_raw_dump_stack.cc
similarity index 75%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/log_raw_dump_stack.cc
index 4723bfb..142a056 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/log_raw_dump_stack.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/log.h"
 
-#include <cmath>
-
-#endif  // COBALT_BASE_MATH_H_
+void SbLogRawDumpStack(int /*frames_to_skip*/) {
+  SbLogRaw("TODO stack dump not implemented\n");
+}
diff --git a/src/starboard/shared/win32/log_raw_format.cc b/src/starboard/shared/win32/log_raw_format.cc
new file mode 100644
index 0000000..5b6c59e
--- /dev/null
+++ b/src/starboard/shared/win32/log_raw_format.cc
@@ -0,0 +1,31 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/log.h"
+
+#include <stdio.h>
+#include <windows.h>
+
+static const int kMaxLogLineChars = 16 * 1024;
+
+void SbLogRawFormat(const char* format, va_list arguments) {
+  vfprintf(stderr, format, arguments);
+  char log_buffer[kMaxLogLineChars];
+  int result = vsprintf_s(log_buffer, kMaxLogLineChars, format, arguments);
+  if (result >= 0) {
+    OutputDebugStringA(log_buffer);
+  } else {
+    OutputDebugStringA("[log line too long]");
+  }
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/memory_allocate_aligned_unchecked.cc
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/memory_allocate_aligned_unchecked.cc
index 51e1f2e..0b161fb 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/memory_allocate_aligned_unchecked.cc
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/memory.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <malloc.h>
+
+void* SbMemoryAllocateAlignedUnchecked(size_t alignment, size_t size) {
+  return _aligned_malloc(size, alignment);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/memory_allocate_unchecked.cc
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/memory_allocate_unchecked.cc
index 51e1f2e..c185f91 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/memory_allocate_unchecked.cc
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/memory.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+void* SbMemoryAllocateUnchecked(size_t size) {
+  return HeapAlloc(GetProcessHeap(), 0, size);
+}
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/memory_free.cc
similarity index 75%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/memory_free.cc
index 4723bfb..42b83fc 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/memory_free.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/memory.h"
 
-#include <cmath>
+#include <windows.h>
 
-#endif  // COBALT_BASE_MATH_H_
+void SbMemoryFree(void* memory) {
+  HeapFree(GetProcessHeap(), 0, memory);
+}
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/memory_free_aligned.cc
similarity index 76%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/memory_free_aligned.cc
index 4723bfb..f40d0c6 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/memory_free_aligned.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/memory.h"
 
-#include <cmath>
+#include <malloc.h>
 
-#endif  // COBALT_BASE_MATH_H_
+void SbMemoryFreeAligned(void* memory) {
+  _aligned_free(memory);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/memory_get_stack_bounds.cc
similarity index 66%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/memory_get_stack_bounds.cc
index 51e1f2e..5a92b61 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/memory_get_stack_bounds.cc
@@ -12,9 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/memory.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include "starboard/log.h"
+
+void SbMemoryGetStackBounds(void** /*out_high*/, void** /*out_low*/) {
+  // TODO the common way to do this is with NtQueryInformationThread
+  // for ThreadBasicInformation but that may not be available on UWP.
+  SB_NOTIMPLEMENTED();
+}
diff --git a/src/starboard/shared/win32/memory_map.cc b/src/starboard/shared/win32/memory_map.cc
new file mode 100644
index 0000000..8ec19f5
--- /dev/null
+++ b/src/starboard/shared/win32/memory_map.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/memory.h"
+
+#include <windows.h>
+
+#include "starboard/log.h"
+
+void* SbMemoryMap(int64_t size_bytes, int flags, const char* name) {
+  if (size_bytes == 0) {
+    return SB_MEMORY_MAP_FAILED;
+  }
+  ULONG protect;
+  // |flags| is a bitmask of SbMemoryMapFlags, but |protect| is not a bitmask.
+  switch (flags) {
+    case kSbMemoryMapProtectRead:
+      protect = PAGE_READONLY;
+      break;
+    case kSbMemoryMapProtectReadWrite:
+      protect = PAGE_READWRITE;
+      break;
+    default:
+      SB_NOTREACHED();
+  }
+  return VirtualAllocFromApp(NULL, size_bytes, MEM_COMMIT, protect);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/memory_reallocate_unchecked.cc
similarity index 70%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/memory_reallocate_unchecked.cc
index 51e1f2e..68ee689 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/memory_reallocate_unchecked.cc
@@ -12,9 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/memory.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+void* SbMemoryReallocateUnchecked(void* memory, size_t size) {
+  if (memory == NULL) {
+    return SbMemoryAllocateUnchecked(size);
+  }
+  return HeapReAlloc(GetProcessHeap(), 0, memory, size);
+}
diff --git a/src/starboard/shared/win32/memory_unmap.cc b/src/starboard/shared/win32/memory_unmap.cc
new file mode 100644
index 0000000..970fc9f
--- /dev/null
+++ b/src/starboard/shared/win32/memory_unmap.cc
@@ -0,0 +1,24 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/memory.h"
+
+#include <windows.h>
+
+bool SbMemoryUnmap(void* virtual_address, int64_t size_bytes) {
+  // Note that SbMemoryUnmap documentation says that "This function can
+  // unmap multiple contiguous regions that were mapped with separate calls
+  // to SbMemoryMap()". Because of that, we cannot use MEM_FREE here.
+  return VirtualFree(virtual_address, size_bytes, MEM_DECOMMIT);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/mutex_acquire.cc
similarity index 74%
rename from src/cobalt/dom/media_key_system_media_capability.idl
rename to src/starboard/shared/win32/mutex_acquire.cc
index 51e1f2e..daca05d 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/mutex_acquire.cc
@@ -12,9 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/mutex.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+SbMutexResult SbMutexAcquire(SbMutex* mutex) {
+  AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(mutex));
+  return kSbMutexAcquired;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/mutex_acquire_try.cc
similarity index 71%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/mutex_acquire_try.cc
index 51e1f2e..0c4cee2 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/mutex_acquire_try.cc
@@ -12,9 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/mutex.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+SbMutexResult SbMutexAcquireTry(SbMutex* mutex) {
+  bool result = TryAcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(mutex));
+  return result ? kSbMutexAcquired : kSbMutexBusy;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/mutex_create.cc
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/mutex_create.cc
index 51e1f2e..5e4c1ce 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/mutex_create.cc
@@ -12,9 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/mutex.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+bool SbMutexCreate(SbMutex* mutex) {
+  if (!mutex) {
+    return false;
+  }
+  InitializeSRWLock(reinterpret_cast<PSRWLOCK>(mutex));
+  return true;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/mutex_destroy.cc
similarity index 73%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/mutex_destroy.cc
index 51e1f2e..1028687 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/mutex_destroy.cc
@@ -12,9 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/mutex.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+bool SbMutexDestroy(SbMutex* mutex) {
+  if (!mutex) {
+    return false;
+  }
+  if (SbMutexAcquireTry(mutex) == kSbMutexBusy) {
+    return false;
+  }
+  return true;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/mutex_release.cc
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/mutex_release.cc
index 51e1f2e..ac50090 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/mutex_release.cc
@@ -12,9 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/mutex.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+bool SbMutexRelease(SbMutex* mutex) {
+  ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(mutex));
+  return true;
+}
diff --git a/src/starboard/shared/win32/once.cc b/src/starboard/shared/win32/once.cc
new file mode 100644
index 0000000..2a31d3a
--- /dev/null
+++ b/src/starboard/shared/win32/once.cc
@@ -0,0 +1,35 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/once.h"
+
+#include <windows.h>
+
+namespace {
+BOOL CALLBACK OnceTrampoline(PINIT_ONCE once_control,
+                             void* parameter,
+                             void** context) {
+  static_cast<SbOnceInitRoutine>(parameter)();
+  return true;
+}
+
+}  // namespace
+
+bool SbOnce(SbOnceControl* once_control, SbOnceInitRoutine init_routine) {
+  if (!once_control || !init_routine) {
+    return false;
+  }
+  return InitOnceExecuteOnce(reinterpret_cast<PINIT_ONCE>(once_control),
+                             OnceTrampoline, init_routine, NULL);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/string_compare_no_case.cc
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/string_compare_no_case.cc
index 51e1f2e..39a9f2b 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/string_compare_no_case.cc
@@ -12,9 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/string.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <string.h>
+
+int SbStringCompareNoCase(const char* string1, const char* string2) {
+  return _stricmp(string1, string2);
+}
+
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/string_compare_no_case_n.cc
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/string_compare_no_case_n.cc
index 51e1f2e..cca7b9d 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/string_compare_no_case_n.cc
@@ -12,9 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/string.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <string.h>
+
+int SbStringCompareNoCaseN(const char* string1,
+  const char* string2, size_t count) {
+  return _strnicmp(string1, string2, count);
+}
+
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/string_compare_wide.cc
similarity index 73%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/string_compare_wide.cc
index 51e1f2e..876d5b7 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/string_compare_wide.cc
@@ -12,9 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/string.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <string.h>
+
+int SbStringCompareWide(const wchar_t* string1, const wchar_t* string2,
+                        size_t count) {
+  return wcsncmp(string1, string2, count);
+}
+
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/string_format.cc
similarity index 68%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/string_format.cc
index 51e1f2e..1239718 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/string_format.cc
@@ -12,9 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/string.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <stdio.h>
+
+int SbStringFormat(char* out_buffer,
+                   size_t buffer_size,
+                   const char* format,
+                   va_list arguments) {
+  return vsnprintf(out_buffer, buffer_size, format, arguments);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/string_format_wide.cc
similarity index 66%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/string_format_wide.cc
index 51e1f2e..29258dc 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/string_format_wide.cc
@@ -12,9 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/string.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <stdio.h>
+
+int SbStringFormatWide(wchar_t* out_buffer,
+                       size_t buffer_size,
+                       const wchar_t* format,
+                       va_list arguments) {
+  return _vsnwprintf(out_buffer, buffer_size, format, arguments);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/system_break_into_debugger.cc
similarity index 74%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/system_break_into_debugger.cc
index 51e1f2e..121d052 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/system_break_into_debugger.cc
@@ -12,9 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/system.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+void SbSystemBreakIntoDebugger() {
+  // TODO: neither of these may be valid on some platforms.
+  DebugBreak();
+  ExitProcess(1);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/system_get_random_uint64.cc
similarity index 61%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/system_get_random_uint64.cc
index 51e1f2e..632c39d 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/system_get_random_uint64.cc
@@ -12,9 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/system.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+#include "starboard/log.h"
+#include "starboard/time.h"
+
+uint64_t SbSystemGetRandomUInt64() {
+  // TODO: This is DEFINITELY not cryptographically secure.
+  static bool initialized = false;
+  if (!initialized) {
+    srand(GetTickCount());
+    initialized = true;
+  }
+  return (static_cast<uint64_t>(std::rand()) << 32) | rand();
+}
diff --git a/src/starboard/shared/win32/thread_create.cc b/src/starboard/shared/win32/thread_create.cc
new file mode 100644
index 0000000..5220aad
--- /dev/null
+++ b/src/starboard/shared/win32/thread_create.cc
@@ -0,0 +1,119 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/thread.h"
+
+#include <process.h>
+#include <memory>
+
+#include "starboard/log.h"
+#include "starboard/once.h"
+#include "starboard/shared/win32/thread_private.h"
+
+using starboard::shared::win32::GetThreadSubsystemSingleton;
+using starboard::shared::win32::SbThreadPrivate;
+using starboard::shared::win32::ThreadSubsystemSingleton;
+
+namespace {
+
+class ThreadCreateInfo {
+ public:
+  SbThreadPrivate thread_private_;
+  SbThreadEntryPoint entry_point_;
+  void* user_context_;
+  std::string name_;
+};
+
+void CallThreadLocalDestructors() {
+  ThreadSubsystemSingleton* singleton = GetThreadSubsystemSingleton();
+
+  // TODO note that the implementation below holds a global lock
+  // while processing TLS destructors on thread exit. This could
+  // be a bottleneck in some scenarios. A lockless approach may be preferrable.
+  SbMutexAcquire(&singleton->mutex_);
+  for (auto it = singleton->thread_local_keys_.begin();
+       it != singleton->thread_local_keys_.end(); ++it) {
+    if (!it->second->destructor) {
+      continue;
+    }
+    void* entry = SbThreadGetLocalValue(it->second);
+    if (!entry) {
+      continue;
+    }
+    it->second->destructor(entry);
+  }
+  SbMutexRelease(&singleton->mutex_);
+}
+
+unsigned ThreadTrampoline(void* thread_create_info_context) {
+  std::unique_ptr<ThreadCreateInfo> info(
+      static_cast<ThreadCreateInfo*>(thread_create_info_context));
+
+  ThreadSubsystemSingleton* singleton = GetThreadSubsystemSingleton();
+
+  SbThreadSetLocalValue(singleton->thread_private_key_, &info->thread_private_);
+
+  SbThreadSetName(info->name_.c_str());
+
+  void* result = info->entry_point_(info->user_context_);
+
+  CallThreadLocalDestructors();
+
+  SbMutexAcquire(&info->thread_private_.mutex_);
+  info->thread_private_.result_ = result;
+  info->thread_private_.result_is_valid_ = true;
+  SbConditionVariableSignal(&info->thread_private_.condition_);
+  while (info->thread_private_.wait_for_join_) {
+    SbConditionVariableWait(&info->thread_private_.condition_,
+                            &info->thread_private_.mutex_);
+  }
+  SbMutexRelease(&info->thread_private_.mutex_);
+
+  return 0;
+}
+
+}  // namespace
+
+SbThread SbThreadCreate(int64_t stack_size,
+                        SbThreadPriority /*priority*/,
+                        SbThreadAffinity /*affinity*/,
+                        bool joinable,
+                        const char* name,
+                        SbThreadEntryPoint entry_point,
+                        void* context) {
+  if (entry_point == NULL) {
+    return kSbThreadInvalid;
+  }
+  ThreadCreateInfo* info = new ThreadCreateInfo();
+
+  info->entry_point_ = entry_point;
+  info->user_context_ = context;
+  info->thread_private_.wait_for_join_ = joinable;
+  if (name) {
+    info->name_ = name;
+  }
+
+  // Create the thread suspended, and then resume once ThreadCreateInfo::handle_
+  // has been set, so that it's alway valid in the ThreadCreateInfo
+  // destructor.
+  uintptr_t handle =
+      _beginthreadex(NULL, static_cast<unsigned int>(stack_size),
+                     ThreadTrampoline, info, CREATE_SUSPENDED, NULL);
+
+  info->thread_private_.handle_ = reinterpret_cast<HANDLE>(handle);
+
+  ResumeThread(info->thread_private_.handle_);
+
+  return &info->thread_private_;
+}
diff --git a/src/starboard/shared/win32/thread_create_local_key.cc b/src/starboard/shared/win32/thread_create_local_key.cc
new file mode 100644
index 0000000..7f786ab
--- /dev/null
+++ b/src/starboard/shared/win32/thread_create_local_key.cc
@@ -0,0 +1,62 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/thread.h"
+
+#include <windows.h>
+
+#include "starboard/memory.h"
+#include "starboard/mutex.h"
+#include "starboard/shared/win32/thread_private.h"
+
+using starboard::shared::win32::GetThreadSubsystemSingleton;
+using starboard::shared::win32::ThreadSubsystemSingleton;
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+SbThreadLocalKey SbThreadCreateLocalKeyInternal(
+    SbThreadLocalDestructor destructor,
+    ThreadSubsystemSingleton* singleton) {
+  DWORD index = TlsAlloc();
+
+  if (index == TLS_OUT_OF_INDEXES) {
+    return kSbThreadLocalKeyInvalid;
+  }
+
+  SbThreadLocalKeyPrivate* result = static_cast<SbThreadLocalKeyPrivate*>(
+      SbMemoryAllocateNoReport(sizeof(SbThreadLocalKeyPrivate)));
+
+  if (result == nullptr) {
+    return kSbThreadLocalKeyInvalid;
+  }
+
+  result->tls_index = index;
+  result->destructor = destructor;
+
+  SbMutexAcquire(&singleton->mutex_);
+  singleton->thread_local_keys_.insert(std::make_pair(index, result));
+  SbMutexRelease(&singleton->mutex_);
+  return result;
+}
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+SbThreadLocalKey SbThreadCreateLocalKey(SbThreadLocalDestructor destructor) {
+  ThreadSubsystemSingleton* singleton = GetThreadSubsystemSingleton();
+  return SbThreadCreateLocalKeyInternal(destructor, singleton);
+}
diff --git a/src/starboard/shared/win32/thread_destroy_local_key.cc b/src/starboard/shared/win32/thread_destroy_local_key.cc
new file mode 100644
index 0000000..201fc75
--- /dev/null
+++ b/src/starboard/shared/win32/thread_destroy_local_key.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/thread.h"
+
+#include <windows.h>
+
+#include "starboard/memory.h"
+#include "starboard/shared/win32/thread_private.h"
+
+using starboard::shared::win32::GetThreadSubsystemSingleton;
+using starboard::shared::win32::ThreadSubsystemSingleton;
+
+void SbThreadDestroyLocalKey(SbThreadLocalKey key) {
+  if (!SbThreadIsValidLocalKey(key)) {
+    return;
+  }
+  DWORD tls_index = static_cast<SbThreadLocalKeyPrivate*>(key)->tls_index;
+  ThreadSubsystemSingleton* singleton = GetThreadSubsystemSingleton();
+
+  SbMutexAcquire(&singleton->mutex_);
+  singleton->thread_local_keys_.erase(tls_index);
+  SbMutexRelease(&singleton->mutex_);
+
+  TlsFree(tls_index);
+  SbMemoryDeallocateNoReport(key);
+}
diff --git a/src/starboard/shared/win32/thread_detach.cc b/src/starboard/shared/win32/thread_detach.cc
new file mode 100644
index 0000000..422a12d
--- /dev/null
+++ b/src/starboard/shared/win32/thread_detach.cc
@@ -0,0 +1,33 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/thread.h"
+
+#include "starboard/condition_variable.h"
+#include "starboard/mutex.h"
+#include "starboard/shared/win32/thread_private.h"
+
+using starboard::shared::win32::SbThreadPrivate;
+
+void SbThreadDetach(SbThread thread) {
+  if (thread == kSbThreadInvalid) {
+    return;
+  }
+  SbThreadPrivate* thread_private = static_cast<SbThreadPrivate*>(thread);
+
+  SbMutexAcquire(&thread_private->mutex_);
+  thread_private->wait_for_join_ = false;
+  SbConditionVariableSignal(&thread_private->condition_);
+  SbMutexRelease(&thread_private->mutex_);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/thread_get_current.cc
similarity index 69%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/thread_get_current.cc
index 51e1f2e..12ba544 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/thread_get_current.cc
@@ -12,9 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/thread.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include "starboard/shared/win32/thread_private.h"
+
+using starboard::shared::win32::GetCurrentSbThreadPrivate;
+using starboard::shared::win32::SbThreadPrivate;
+
+SbThread SbThreadGetCurrent() {
+  return GetCurrentSbThreadPrivate();
+}
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/thread_get_id.cc
similarity index 76%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/thread_get_id.cc
index 4723bfb..b6a7293 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/thread_get_id.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/thread.h"
 
-#include <cmath>
+#include <windows.h>
 
-#endif  // COBALT_BASE_MATH_H_
+SbThreadId SbThreadGetId() {
+  return GetCurrentThreadId();
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/thread_get_local_value.cc
similarity index 64%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/thread_get_local_value.cc
index 51e1f2e..64603b6 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/thread_get_local_value.cc
@@ -12,9 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/thread.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+#include "starboard/shared/win32/thread_private.h"
+
+void* SbThreadGetLocalValue(SbThreadLocalKey key) {
+  if (!SbThreadIsValidLocalKey(key)) {
+    return NULL;
+  }
+  DWORD tls_index = static_cast<SbThreadLocalKeyPrivate*>(key)->tls_index;
+  return TlsGetValue(tls_index);
+}
diff --git a/src/starboard/shared/win32/thread_get_name.cc b/src/starboard/shared/win32/thread_get_name.cc
new file mode 100644
index 0000000..a3dd3d7
--- /dev/null
+++ b/src/starboard/shared/win32/thread_get_name.cc
@@ -0,0 +1,28 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/thread.h"
+
+#include <windows.h>
+
+#include "starboard/string.h"
+#include "starboard/shared/win32/thread_private.h"
+
+using starboard::shared::win32::GetCurrentSbThreadPrivate;
+using starboard::shared::win32::SbThreadPrivate;
+
+void SbThreadGetName(char* buffer, int buffer_size) {
+  SbThreadPrivate* thread_private = GetCurrentSbThreadPrivate();
+  SbStringCopy(buffer, thread_private->name_.c_str(), buffer_size);
+}
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/thread_is_equal.cc
similarity index 75%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/thread_is_equal.cc
index 4723bfb..ccc2d64 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/thread_is_equal.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/thread.h"
 
-#include <cmath>
-
-#endif  // COBALT_BASE_MATH_H_
+bool SbThreadIsEqual(SbThread thread1, SbThread thread2) {
+  return thread1 == thread2;
+}
diff --git a/src/starboard/shared/win32/thread_join.cc b/src/starboard/shared/win32/thread_join.cc
new file mode 100644
index 0000000..44e1589
--- /dev/null
+++ b/src/starboard/shared/win32/thread_join.cc
@@ -0,0 +1,47 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/thread.h"
+
+#include "starboard/condition_variable.h"
+#include "starboard/mutex.h"
+#include "starboard/shared/win32/thread_private.h"
+
+using starboard::shared::win32::SbThreadPrivate;
+
+bool SbThreadJoin(SbThread thread, void** out_return) {
+  if (thread == kSbThreadInvalid) {
+    return false;
+  }
+
+  SbThreadPrivate* thread_private = static_cast<SbThreadPrivate*>(thread);
+
+  SbMutexAcquire(&thread_private->mutex_);
+  if (!thread_private->wait_for_join_) {
+    // Thread has already been detached.
+    SbMutexRelease(&thread_private->mutex_);
+    return false;
+  }
+  while (!thread_private->result_is_valid_) {
+    SbConditionVariableWait(&thread_private->condition_,
+                            &thread_private->mutex_);
+  }
+  thread_private->wait_for_join_ = false;
+  SbConditionVariableSignal(&thread_private->condition_);
+  if (out_return != NULL) {
+    *out_return = thread_private->result_;
+  }
+  SbMutexRelease(&thread_private->mutex_);
+  return true;
+}
diff --git a/src/starboard/shared/win32/thread_private.cc b/src/starboard/shared/win32/thread_private.cc
new file mode 100644
index 0000000..e0ee6b1
--- /dev/null
+++ b/src/starboard/shared/win32/thread_private.cc
@@ -0,0 +1,61 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/thread.h"
+
+#include <process.h>
+#include <memory>
+
+#include "starboard/log.h"
+#include "starboard/once.h"
+#include "starboard/shared/win32/thread_private.h"
+
+using starboard::shared::win32::GetThreadSubsystemSingleton;
+using starboard::shared::win32::SbThreadPrivate;
+using starboard::shared::win32::ThreadSubsystemSingleton;
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+SB_ONCE_INITIALIZE_FUNCTION(ThreadSubsystemSingleton,
+                            GetThreadSubsystemSingleton);
+
+void RegisterMainThread() {
+  std::unique_ptr<SbThreadPrivate> thread_private(new SbThreadPrivate());
+
+  // GetCurrentThread() returns a pseudo-handle that must be duplicated
+  // to be used in general cases.
+  HANDLE pseudo_handle = GetCurrentThread();
+  HANDLE handle;
+  BOOL success =
+      DuplicateHandle(GetCurrentProcess(), pseudo_handle, GetCurrentProcess(),
+                      &handle, 0, false, DUPLICATE_SAME_ACCESS);
+  SB_DCHECK(success) << "DuplicateHandle failed";
+
+  thread_private->handle_ = handle;
+  thread_private->wait_for_join_ = false;
+
+  SbThreadSetLocalValue(GetThreadSubsystemSingleton()->thread_private_key_,
+                        thread_private.release());
+}
+
+SbThreadPrivate* GetCurrentSbThreadPrivate() {
+  return static_cast<SbThreadPrivate*>(SbThreadGetLocalValue(
+      GetThreadSubsystemSingleton()->thread_private_key_));
+}
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/win32/thread_private.h b/src/starboard/shared/win32/thread_private.h
new file mode 100644
index 0000000..4bacbd8
--- /dev/null
+++ b/src/starboard/shared/win32/thread_private.h
@@ -0,0 +1,109 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_WIN32_THREAD_PRIVATE_H_
+#define STARBOARD_WIN32_THREAD_PRIVATE_H_
+
+#include <windows.h>
+#include <string>
+#include <unordered_map>
+
+#include "starboard/condition_variable.h"
+#include "starboard/mutex.h"
+#include "starboard/once.h"
+#include "starboard/shared/internal_only.h"
+#include "starboard/thread.h"
+
+struct SbThreadLocalKeyPrivate {
+  DWORD tls_index;
+  SbThreadLocalDestructor destructor;
+};
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+class ThreadSubsystemSingleton;
+
+// Creates a SbThreadLocalKey given a ThreadSubsystemSingleton. Used
+// to create the first SbThreadLocalKey.
+SbThreadLocalKey SbThreadCreateLocalKeyInternal(
+    SbThreadLocalDestructor destructor,
+    ThreadSubsystemSingleton* singleton);
+
+// Singleton state for the thread subsystem.
+class ThreadSubsystemSingleton {
+ public:
+  ThreadSubsystemSingleton()
+      : mutex_(SB_MUTEX_INITIALIZER),
+        thread_private_key_(SbThreadCreateLocalKeyInternal(NULL, this)) {}
+  // This mutex protects all class members
+  SbMutex mutex_;
+  // Allocated thread_local_keys
+  std::unordered_map<DWORD, SbThreadLocalKeyPrivate*> thread_local_keys_;
+  // Thread-local key for the thread's SbThreadPrivate
+  SbThreadLocalKey thread_private_key_;
+};
+
+// Obtains the ThreadsSubsystemSingleton();
+ThreadSubsystemSingleton* GetThreadSubsystemSingleton();
+
+// Registers the main thread. setting it's SbThreadPrivate*
+void RegisterMainThread();
+
+// Private thread state, stored in thread local storage and
+// cleaned up when thread exits.
+class SbThreadPrivate {
+ public:
+  SbThreadPrivate()
+      : mutex_(SB_MUTEX_INITIALIZER),
+        condition_(SB_CONDITION_VARIABLE_INITIALIZER),
+        handle_(NULL),
+        result_(NULL),
+        wait_for_join_(false),
+        result_is_valid_(false) {}
+
+  ~SbThreadPrivate() {
+    if (handle_) {
+      CloseHandle(handle_);
+    }
+
+    SbMutexDestroy(&mutex_);
+    SbConditionVariableDestroy(&condition_);
+  }
+
+  // This mutex protects all class members
+  SbMutex mutex_;
+  SbConditionVariable condition_;
+  std::string name_;
+  HANDLE handle_;
+  // The result of the thread. The return value of SbThreadEntryPoint
+  // to return to SbThreadJoin.
+  void* result_;
+  // True if a thread must wait to be joined before completely exiting.
+  // Changes to this must signal |condition_|.
+  bool wait_for_join_;
+  // True if |result_| is valid (the thread has completed and is waiting
+  // to exit). Changes to this must signal |condition_|.
+  bool result_is_valid_;
+};
+
+// Obtains the current thread's SbThreadPrivate* from thread-local storage.
+SbThreadPrivate* GetCurrentSbThreadPrivate();
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_WIN32_THREAD_PRIVATE_H_
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/thread_set_local_value.cc
similarity index 63%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/thread_set_local_value.cc
index 51e1f2e..95a1840 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/thread_set_local_value.cc
@@ -12,9 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/thread.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+#include "starboard/shared/win32/thread_private.h"
+
+bool SbThreadSetLocalValue(SbThreadLocalKey key, void* value) {
+  if (!SbThreadIsValidLocalKey(key)) {
+    return false;
+  }
+  DWORD tls_index = static_cast<SbThreadLocalKeyPrivate*>(key)->tls_index;
+  return TlsSetValue(tls_index, value);
+}
diff --git a/src/starboard/shared/win32/thread_set_name.cc b/src/starboard/shared/win32/thread_set_name.cc
new file mode 100644
index 0000000..aca4ad2
--- /dev/null
+++ b/src/starboard/shared/win32/thread_set_name.cc
@@ -0,0 +1,66 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/thread.h"
+
+#include <windows.h>
+
+#include "starboard/shared/win32/thread_private.h"
+
+using starboard::shared::win32::GetCurrentSbThreadPrivate;
+using starboard::shared::win32::SbThreadPrivate;
+
+namespace {
+
+// The code below is from
+// https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+// A |dwThreadID| of -1 means "current thread";
+//
+// Usage: SetThreadName ((DWORD)-1, "MainThread");
+//
+const DWORD MS_VC_EXCEPTION = 0x406D1388;
+#pragma pack(push, 8)
+typedef struct tagTHREADNAME_INF {
+  DWORD dwType;      // Must be 0x1000.
+  LPCSTR szName;     // Pointer to name (in user addr space).
+  DWORD dwThreadID;  // Thread ID (-1=caller thread).
+  DWORD dwFlags;     // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+#pragma pack(pop)
+void SetThreadName(DWORD dwThreadID, const char* threadName) {
+  THREADNAME_INFO info;
+  info.dwType = 0x1000;
+  info.szName = threadName;
+  info.dwThreadID = dwThreadID;
+  info.dwFlags = 0;
+#pragma warning(push)
+#pragma warning(disable : 6320 6322)
+  __try {
+    RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR),
+                   reinterpret_cast<ULONG_PTR*>(&info));
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+  }
+#pragma warning(pop)
+}
+
+}  // namespace
+
+void SbThreadSetName(const char* name) {
+  SbThreadPrivate* thread_private = GetCurrentSbThreadPrivate();
+
+  // We store the thread name in our own TLS context as well as telling
+  // the OS because it's much easier to retrieve from our own TLS context.
+  thread_private->name_ = name;
+  SetThreadName(-1, name);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/thread_sleep.cc
similarity index 67%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/thread_sleep.cc
index 51e1f2e..85c965d 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/thread_sleep.cc
@@ -12,9 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/thread.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+#include "starboard/shared/win32/time_utils.h"
+
+using starboard::shared::win32::ConvertSbTimeToMillisRoundUp;
+
+void SbThreadSleep(SbTime duration) {
+  if (duration < 0) {
+    return;
+  }
+  Sleep(ConvertSbTimeToMillisRoundUp(duration));
+}
diff --git a/src/starboard/shared/win32/thread_types_public.h b/src/starboard/shared/win32/thread_types_public.h
new file mode 100644
index 0000000..3443068
--- /dev/null
+++ b/src/starboard/shared/win32/thread_types_public.h
@@ -0,0 +1,63 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Includes threading primitive types and initializers.
+
+#ifndef STARBOARD_SHARED_WIN32_THREAD_TYPES_PUBLIC_H_
+#define STARBOARD_SHARED_WIN32_THREAD_TYPES_PUBLIC_H_
+
+// --- SbConditionVariable ---
+
+// Transparent Condition Variable handle.
+// Note: replica of RTL_CONDITION_VARIABLE in um/winnt.h to avoid include.
+typedef struct WindowsConditionVariable { void* ptr; } SbConditionVariable;
+
+// Condition Variable static initializer.
+// Note: replica of RTL_CONDITION_VARIABILE_INIT in um/winnt.h to avoid include.
+#define SB_CONDITION_VARIABLE_INITIALIZER \
+  { 0 }
+
+// --- SbMutex ---
+
+// Transparent Mutex handle.
+// Note SRWLock's are used for SbMutex because:
+// - Normal Windows CreateMutex() mutexes are very heavy-weight
+// - Critical sections do not have a static initializer
+// Note: replica of RTL_SRWLOCK in um/winnt.h to avoid include.
+typedef struct WindowsSrwLock { void* ptr; } SbMutex;
+
+// Mutex static initializer.
+// Note: replica of RTL_SRWLOCK_INIT in um/winnt.h to avoid include.
+#define SB_MUTEX_INITIALIZER \
+  { 0 }
+
+// --- SbOnce ---
+
+// Transparent Once control handle.
+typedef union WindowsRunOnce { void* ptr; } SbOnceControl;
+
+// Once static initializer.
+// Note: replica of RTL_RUN_ONCE_INIT in um/winnt.h to avoid include.
+#define SB_ONCE_INITIALIZER \
+  { 0 }
+
+// --- SbThread ---
+
+// Transparent pthread handle.
+typedef void* SbThread;
+
+// Well-defined constant value to mean "no thread handle."
+#define kSbThreadInvalid (SbThread) NULL
+
+#endif  // STARBOARD_SHARED_WIN32_THREAD_TYPES_PUBLIC_H_
diff --git a/src/cobalt/base/math.h b/src/starboard/shared/win32/thread_yield.cc
similarity index 77%
copy from src/cobalt/base/math.h
copy to src/starboard/shared/win32/thread_yield.cc
index 4723bfb..2687852 100644
--- a/src/cobalt/base/math.h
+++ b/src/starboard/shared/win32/thread_yield.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
+// Copyright 2017 Google Inc. All Rights Reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef COBALT_BASE_MATH_H_
-#define COBALT_BASE_MATH_H_
+#include "starboard/thread.h"
 
-#include <cmath>
+#include <windows.h>
 
-#endif  // COBALT_BASE_MATH_H_
+void SbThreadYield() {
+  Sleep(0);
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/time_get_monotonic_now.cc
similarity index 73%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/time_get_monotonic_now.cc
index 51e1f2e..56a162a 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/time_get_monotonic_now.cc
@@ -12,9 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/time.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+SbTimeMonotonic SbTimeGetMonotonicNow() {
+  ULONGLONG result;
+  QueryUnbiasedInterruptTimePrecise(&result);
+
+  return static_cast<SbTimeMonotonic>(result) / 10;
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
similarity index 73%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/time_get_monotonic_thread_now.cc
index 51e1f2e..fff4bd9 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/time_get_monotonic_thread_now.cc
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/time.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+SbTimeMonotonic SbTimeGetMonotonicThreadNow() {
+  // Neither QueryThreadCycleTime nor GetThreadTimes are listed as being
+  // available in UWP.
+  return SbTimeGetMonotonicNow();
+}
diff --git a/src/cobalt/dom/media_key_system_media_capability.idl b/src/starboard/shared/win32/time_get_now.cc
similarity index 60%
copy from src/cobalt/dom/media_key_system_media_capability.idl
copy to src/starboard/shared/win32/time_get_now.cc
index 51e1f2e..eaa1fbc 100644
--- a/src/cobalt/dom/media_key_system_media_capability.idl
+++ b/src/starboard/shared/win32/time_get_now.cc
@@ -12,9 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// https://www.w3.org/TR/2016/CR-encrypted-media-20160705/#mediakeysystemmediacapability-dictionary
+#include "starboard/time.h"
 
-dictionary MediaKeySystemMediaCapability {
-  DOMString contentType = "";
-  DOMString robustness = "";
-};
+#include <windows.h>
+
+SbTime SbTimeGetNow() {
+  SYSTEMTIME system_time;
+  GetSystemTime(&system_time);
+
+  FILETIME file_time;
+  SystemTimeToFileTime(&system_time, &file_time);
+
+  ULARGE_INTEGER large_int;
+  large_int.LowPart = file_time.dwLowDateTime;
+  large_int.HighPart = file_time.dwHighDateTime;
+  return static_cast<SbTime>(large_int.QuadPart) / 10;
+}
diff --git a/src/starboard/shared/win32/time_utils.h b/src/starboard/shared/win32/time_utils.h
new file mode 100644
index 0000000..cad1368
--- /dev/null
+++ b/src/starboard/shared/win32/time_utils.h
@@ -0,0 +1,64 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_WIN32_TIME_UTILS_H_
+#define STARBOARD_SHARED_WIN32_TIME_UTILS_H_
+
+#include "starboard/log.h"
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+inline SbTime ConvertFileTimeTicksToSbTime(const LARGE_INTEGER ticks) {
+  // According to
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx
+  // FILETIME format is "Contains a 64-bit value representing the number of
+  // 100-nanosecond intervals since January 1, 1601 (UTC)"
+  const uint64_t kNumber100nanosecondTicksInMicrosecond = 10;
+  return ticks.QuadPart / kNumber100nanosecondTicksInMicrosecond;
+}
+
+inline SbTime ConvertFileTimeToSbTime(const FILETIME file_time) {
+  // According to
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx
+  // FILETIME format is "Contains a 64-bit value representing the number of
+  // 100-nanosecond intervals since January 1, 1601 (UTC)"
+  LARGE_INTEGER ticks;
+  ticks.QuadPart = (static_cast<LONGLONG>(file_time.dwHighDateTime) << 32) |
+                   file_time.dwLowDateTime;
+  return ConvertFileTimeTicksToSbTime(ticks);
+}
+
+inline SbTime ConvertSystemTimeToSbTime(const SYSTEMTIME system_time) {
+  FILETIME file_time = {0};
+  SystemTimeToFileTime(&system_time, &file_time);
+  return ConvertFileTimeToSbTime(file_time);
+}
+
+// Many Win32 calls take millis, but SbTime is microseconds.
+// Many nplb tests assume waits are at least as long as requested, so
+// round up.
+inline DWORD ConvertSbTimeToMillisRoundUp(SbTime duration) {
+  const int64_t milliseconds_to_sleep =
+      (duration + kSbTimeMillisecond - 1) / kSbTimeMillisecond;
+  SB_DCHECK(milliseconds_to_sleep <= kSbInt32Max);
+  return static_cast<DWORD>(milliseconds_to_sleep);
+}
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_WIN32_TIME_UTILS_H_
diff --git a/src/starboard/shared/win32/time_zone_get_current.cc b/src/starboard/shared/win32/time_zone_get_current.cc
new file mode 100644
index 0000000..b040059
--- /dev/null
+++ b/src/starboard/shared/win32/time_zone_get_current.cc
@@ -0,0 +1,36 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/time_zone.h"
+
+#include <windows.h>
+
+#include "starboard/log.h"
+SbTimeZone SbTimeZoneGetCurrent() {
+  DYNAMIC_TIME_ZONE_INFORMATION time_zone_info;
+
+  DWORD zone_id = GetDynamicTimeZoneInformation(&time_zone_info);
+
+  switch (zone_id) {
+  case TIME_ZONE_ID_UNKNOWN:
+    return time_zone_info.Bias;
+  case TIME_ZONE_ID_STANDARD:
+    return time_zone_info.StandardBias;
+  case TIME_ZONE_ID_DAYLIGHT:
+    return time_zone_info.DaylightBias;
+  default:
+    SB_NOTREACHED();
+    return 0;
+  }
+}
diff --git a/src/starboard/shared/win32/wchar_utils.h b/src/starboard/shared/win32/wchar_utils.h
new file mode 100644
index 0000000..948b025
--- /dev/null
+++ b/src/starboard/shared/win32/wchar_utils.h
@@ -0,0 +1,47 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_WIN32_WCHAR_UTILS_H_
+#define STARBOARD_WIN32_WCHAR_UTILS_H_
+
+#include <codecvt>
+#include <cwchar>
+#include <locale>
+#include <string>
+
+namespace starboard {
+namespace shared {
+namespace win32 {
+
+inline std::string wchar_tToUTF8(const wchar_t* const str) {
+  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
+  return converter.to_bytes(str);
+}
+
+inline std::string wchar_tToUTF8(const wchar_t* const str,
+                                 const std::size_t size) {
+  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
+  return converter.to_bytes(str, str + size);
+}
+
+inline std::wstring CStringToWString(const char* str) {
+  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
+  return converter.from_bytes(str);
+}
+
+}  // namespace win32
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_WIN32_WCHAR_UTILS_H_
diff --git a/src/starboard/stub/gyp_configuration.gypi b/src/starboard/stub/gyp_configuration.gypi
index 3a62ad7..10e4c16 100644
--- a/src/starboard/stub/gyp_configuration.gypi
+++ b/src/starboard/stub/gyp_configuration.gypi
@@ -24,7 +24,9 @@
 
     # This should have a default value in cobalt/base.gypi. See the comment
     # there for acceptable values for this variable.
-    'javascript_engine': 'mozjs',
+    'javascript_engine': 'mozjs-45',
+
+    'cobalt_enable_jit': 0,
 
     'cobalt_media_source_2016': 1,
 
@@ -87,6 +89,9 @@
           '-Wno-unnamed-type-template-args',
           # Triggered by the COMPILE_ASSERT macro.
           '-Wno-unused-local-typedef',
+          # Do not warn if a function or variable cannot be implicitly
+          # instantiated.
+          '-Wno-undefined-var-template',
         ],
       }],
       ['cobalt_fastbuild==0', {
@@ -118,11 +123,7 @@
       #'-std=c99',
     ],
     'cflags_cc': [
-      # Limit to gnu++98. This allows stub to be a canary build for any
-      # C++11 features that are not supported on some platforms' compilers.
-      # We do allow ourselves GNU extensions, which are assumed to exist
-      # by Chromium code.
-      #'-std=gnu++98',
+      '-std=gnu++11',
     ],
     'default_configuration': 'stub_debug',
     'configurations': {
diff --git a/src/starboard/tools/raspi/run_test.py b/src/starboard/tools/raspi/run_test.py
index 5119c3a..b837307 100755
--- a/src/starboard/tools/raspi/run_test.py
+++ b/src/starboard/tools/raspi/run_test.py
@@ -21,9 +21,11 @@
 import functools
 import logging
 import os
+import re
 import signal
 import sys
 import textwrap
+import time
 
 import pexpect
 
@@ -68,6 +70,9 @@
   if not os.path.isfile(test_path):
     raise ValueError('test_path ({}) must be a file.'.format(test_path))
 
+  # This is used to strip ansi color codes from output.
+  sanitize_line_re = re.compile(r'\x1b[^m]*m')
+
   sys.stdout.write('Process launched, ID={}\n'.format(os.getpid()))
   sys.stdout.flush()
 
@@ -81,19 +86,19 @@
   options = '-avzh --exclude obj*'
   source = test_dir_path
   destination = raspi_user_hostname + ':~/'
-  command = 'rsync ' + options + ' ' + source + ' ' + destination
-  process = pexpect.spawn(command, timeout=120)
+  rsync_command = 'rsync ' + options + ' ' + source + ' ' + destination
+  rsync_process = pexpect.spawn(rsync_command, timeout=120)
 
   signal.signal(signal.SIGINT,
-                functools.partial(_SigIntOrSigTermHandler, process))
+                functools.partial(_SigIntOrSigTermHandler, rsync_process))
   signal.signal(signal.SIGTERM,
-                functools.partial(_SigIntOrSigTermHandler, process))
+                functools.partial(_SigIntOrSigTermHandler, rsync_process))
 
-  process.expect(r'\S+ password:')
-  process.sendline(_RASPI_PASSWORD)
+  rsync_process.expect(r'\S+ password:')
+  rsync_process.sendline(_RASPI_PASSWORD)
 
   while True:
-    line = process.readline()
+    line = sanitize_line_re.sub('', rsync_process.readline())
     if line:
       sys.stdout.write(line)
       sys.stdout.flush()
@@ -101,21 +106,24 @@
       break
 
   # ssh into the raspi and run the test
-  command = 'ssh ' + raspi_user_hostname
-  process = pexpect.spawn(command, timeout=120)
+  ssh_command = 'ssh ' + raspi_user_hostname
+  ssh_process = pexpect.spawn(ssh_command, timeout=120)
 
   signal.signal(signal.SIGINT,
-                functools.partial(_SigIntOrSigTermHandler, process))
+                functools.partial(_SigIntOrSigTermHandler, ssh_process))
   signal.signal(signal.SIGTERM,
-                functools.partial(_SigIntOrSigTermHandler, process))
+                functools.partial(_SigIntOrSigTermHandler, ssh_process))
 
-  process.expect(r'\S+ password:')
-  process.sendline(_RASPI_PASSWORD)
-  process.sendline(raspi_test_path + ' ' + flags)
+  ssh_process.expect(r'\S+ password:')
+  ssh_process.sendline(_RASPI_PASSWORD)
+
+  test_command = raspi_test_path + ' ' + flags
+  test_end_tag = 'END_TEST-{time}'.format(time=time.time())
+  ssh_process.sendline(test_command + '; echo ' + test_end_tag)
 
   while True:
-    line = process.readline()
-    if line:
+    line = sanitize_line_re.sub('', ssh_process.readline())
+    if line and not line.startswith(test_end_tag):
       sys.stdout.write(line)
       sys.stdout.flush()
     else:
diff --git a/src/third_party/mozjs-45/js/src/js.msg b/src/third_party/mozjs-45/js/src/js.msg
index 908a188..14834ec 100644
--- a/src/third_party/mozjs-45/js/src/js.msg
+++ b/src/third_party/mozjs-45/js/src/js.msg
@@ -149,8 +149,13 @@
 MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large")
 
 // CSP
+#if defined(COBALT)
+MSG_DEF(JSMSG_CSP_BLOCKED_EVAL,        0, JSEXN_EVALERR, "call to eval() blocked by CSP")
+MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION,    0, JSEXN_EVALERR, "call to Function() blocked by CSP")
+#else
 MSG_DEF(JSMSG_CSP_BLOCKED_EVAL,        0, JSEXN_ERR, "call to eval() blocked by CSP")
 MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION,    0, JSEXN_ERR, "call to Function() blocked by CSP")
+#endif
 
 // Wrappers
 MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED,     1, JSEXN_ERR, "Permission denied to define accessor property {0}")
diff --git a/src/third_party/openssl/README.chromium b/src/third_party/openssl/README.chromium
index 6c8889b..d49796a 100644
--- a/src/third_party/openssl/README.chromium
+++ b/src/third_party/openssl/README.chromium
@@ -1,6 +1,6 @@
 Name: openssl
 URL: http://openssl.org/source/
-Version: 1.0.1p
+Version: 1.0.1r
 License: BSDish
 License File: openssl/LICENSE
 License Android Compatible: yes
diff --git a/src/third_party/openssl/openssl/.travis-create-release.sh b/src/third_party/openssl/openssl/.travis-create-release.sh
new file mode 100644
index 0000000..0404fc1
--- /dev/null
+++ b/src/third_party/openssl/openssl/.travis-create-release.sh
@@ -0,0 +1,10 @@
+#! /bin/sh
+
+# $1 is expected to be $TRAVIS_OS_NAME
+
+if [ "$1" == osx ]; then
+    make -f Makefile.org \
+	 DISTTARVARS="NAME=_srcdist TAR_COMMAND='\$\$(TAR) \$\$(TARFLAGS) -s \"|^|\$\$(NAME)/|\" -T \$\$(TARFILE).list -cvf -' TARFLAGS='-n' TARFILE=_srcdist.tar" SHELL='sh -vx' dist
+else
+    make -f Makefile.org DISTTARVARS='TARFILE=_srcdist.tar NAME=_srcdist' SHELL='sh -v' dist
+fi
diff --git a/src/third_party/openssl/openssl/.travis.yml b/src/third_party/openssl/openssl/.travis.yml
new file mode 100644
index 0000000..ad05909
--- /dev/null
+++ b/src/third_party/openssl/openssl/.travis.yml
@@ -0,0 +1,60 @@
+language: c
+
+addons:
+    apt_packages:
+        - binutils-mingw-w64
+        - gcc-mingw-w64
+
+os:
+    - linux
+    - osx
+
+compiler:
+    - clang
+    - gcc
+    - i686-w64-mingw32-gcc
+    - x86_64-w64-mingw32-gcc
+
+env:
+    - CONFIG_OPTS=""
+    - CONFIG_OPTS="shared"
+    - CONFIG_OPTS="-d --strict-warnings"
+
+matrix:
+    exclude:
+        - os: osx
+          compiler: i686-w64-mingw32-gcc
+        - os: osx
+          compiler: x86_64-w64-mingw32-gcc
+        - compiler: i686-w64-mingw32-gcc
+          env: CONFIG_OPTS="-d --strict-warnings"
+        - compiler: x86_64-w64-mingw32-gcc
+          env: CONFIG_OPTS="-d --strict-warnings"
+
+before_script:
+    - sh .travis-create-release.sh $TRAVIS_OS_NAME
+    - tar -xvzf _srcdist.tar.gz
+    - cd _srcdist
+    - if [ "$CC" == i686-w64-mingw32-gcc ]; then
+          export CROSS_COMPILE=${CC%%gcc}; unset CC;
+          ./Configure mingw $CONFIG_OPTS;
+      elif [ "$CC" == x86_64-w64-mingw32-gcc ]; then
+          export CROSS_COMPILE=${CC%%gcc}; unset CC;
+          ./Configure mingw64 $CONFIG_OPTS;
+      else
+          ./config $CONFIG_OPTS;
+      fi
+    - cd ..
+
+script:
+    - cd _srcdist
+    - make
+    - if [ -z "$CROSS_COMPILE" ]; then make test; fi
+    - cd ..
+
+notifications:
+    recipient:
+        - openssl-commits@openssl.org
+    email:
+        on_success: change
+        on_failure: always
diff --git a/src/third_party/openssl/openssl/ACKNOWLEDGMENTS b/src/third_party/openssl/openssl/ACKNOWLEDGMENTS
index 59c6f01..d21dccb 100644
--- a/src/third_party/openssl/openssl/ACKNOWLEDGMENTS
+++ b/src/third_party/openssl/openssl/ACKNOWLEDGMENTS
@@ -1,30 +1,2 @@
-The OpenSSL project depends on volunteer efforts and financial support from
-the end user community. That support comes in the form of donations and paid
-sponsorships, software support contracts, paid consulting services
-and commissioned software development.
-
-Since all these activities support the continued development and improvement
-of OpenSSL we consider all these clients and customers as sponsors of the
-OpenSSL project.
-
-We would like to identify and thank the following such sponsors for their past
-or current significant support of the OpenSSL project:
-
-Major support:
-
-	Qualys		http://www.qualys.com/
-
-Very significant support:
-
-	OpenGear:	http://www.opengear.com/
-
-Significant support:
-
-	PSW Group:	http://www.psw.net/
-	Acano Ltd.	http://acano.com/
-
-Please note that we ask permission to identify sponsors and that some sponsors
-we consider eligible for inclusion here have requested to remain anonymous.
-
-Additional sponsorship or financial support is always welcome: for more
-information please contact the OpenSSL Software Foundation.
+Please https://www.openssl.org/community/thanks.html for the current
+acknowledgements.
diff --git a/src/third_party/openssl/openssl/CHANGES b/src/third_party/openssl/openssl/CHANGES
index 2e888f7..b84ff94 100644
--- a/src/third_party/openssl/openssl/CHANGES
+++ b/src/third_party/openssl/openssl/CHANGES
@@ -2,6 +2,69 @@
  OpenSSL CHANGES
  _______________
 
+ Changes between 1.0.1q and 1.0.1r [28 Jan 2016]
+
+  *) Protection for DH small subgroup attacks
+
+     As a precautionary measure the SSL_OP_SINGLE_DH_USE option has been
+     switched on by default and cannot be disabled. This could have some
+     performance impact.
+     [Matt Caswell]
+
+  *) SSLv2 doesn't block disabled ciphers
+
+     A malicious client can negotiate SSLv2 ciphers that have been disabled on
+     the server and complete SSLv2 handshakes even if all SSLv2 ciphers have
+     been disabled, provided that the SSLv2 protocol was not also disabled via
+     SSL_OP_NO_SSLv2.
+
+     This issue was reported to OpenSSL on 26th December 2015 by Nimrod Aviram
+     and Sebastian Schinzel.
+     (CVE-2015-3197)
+     [Viktor Dukhovni]
+
+  *) Reject DH handshakes with parameters shorter than 1024 bits.
+     [Kurt Roeckx]
+
+ Changes between 1.0.1p and 1.0.1q [3 Dec 2015]
+
+  *) Certificate verify crash with missing PSS parameter
+
+     The signature verification routines will crash with a NULL pointer
+     dereference if presented with an ASN.1 signature using the RSA PSS
+     algorithm and absent mask generation function parameter. Since these
+     routines are used to verify certificate signature algorithms this can be
+     used to crash any certificate verification operation and exploited in a
+     DoS attack. Any application which performs certificate verification is
+     vulnerable including OpenSSL clients and servers which enable client
+     authentication.
+
+     This issue was reported to OpenSSL by Loïc Jonas Etienne (Qnective AG).
+     (CVE-2015-3194)
+     [Stephen Henson]
+
+  *) X509_ATTRIBUTE memory leak
+
+     When presented with a malformed X509_ATTRIBUTE structure OpenSSL will leak
+     memory. This structure is used by the PKCS#7 and CMS routines so any
+     application which reads PKCS#7 or CMS data from untrusted sources is
+     affected. SSL/TLS is not affected.
+
+     This issue was reported to OpenSSL by Adam Langley (Google/BoringSSL) using
+     libFuzzer.
+     (CVE-2015-3195)
+     [Stephen Henson]
+
+  *) Rewrite EVP_DecodeUpdate (base64 decoding) to fix several bugs.
+     This changes the decoding behaviour for some invalid messages,
+     though the change is mostly in the more lenient direction, and
+     legacy behaviour is preserved as much as possible.
+     [Emilia Käsper]
+
+  *) In DSA_generate_parameters_ex, if the provided seed is too short,
+     return an error
+     [Rich Salz and Ismo Puustinen <ismo.puustinen@intel.com>]
+
  Changes between 1.0.1o and 1.0.1p [9 Jul 2015]
 
   *) Alternate chains certificate forgery
@@ -15,10 +78,19 @@
 
      This issue was reported to OpenSSL by Adam Langley/David Benjamin
      (Google/BoringSSL).
+     (CVE-2015-1793)
      [Matt Caswell]
 
- Changes between 1.0.1n and 1.0.1o [12 Jun 2015]
+  *) Race condition handling PSK identify hint
 
+     If PSK identity hints are received by a multi-threaded client then
+     the values are wrongly updated in the parent SSL_CTX structure. This can
+     result in a race condition potentially leading to a double free of the
+     identify hint data.
+     (CVE-2015-3196)
+     [Stephen Henson]
+
+ Changes between 1.0.1n and 1.0.1o [12 Jun 2015]
   *) Fix HMAC ABI incompatibility. The previous version introduced an ABI
      incompatibility in the handling of HMAC. The previous ABI has now been
      restored.
@@ -55,9 +127,9 @@
      callbacks.
 
      This issue was reported to OpenSSL by Robert Swiecki (Google), and
-     independently by Hanno Böck.
+     independently by Hanno Böck.
      (CVE-2015-1789)
-     [Emilia Käsper]
+     [Emilia Käsper]
 
   *) PKCS7 crash with missing EnvelopedContent
 
@@ -71,7 +143,7 @@
 
      This issue was reported to OpenSSL by Michal Zalewski (Google).
      (CVE-2015-1790)
-     [Emilia Käsper]
+     [Emilia Käsper]
 
   *) CMS verify infinite loop with unknown hash function
 
@@ -94,6 +166,9 @@
   *) Reject DH handshakes with parameters shorter than 768 bits.
      [Kurt Roeckx and Emilia Kasper]
 
+  *) dhparam: generate 2048-bit parameters by default.
+     [Kurt Roeckx and Emilia Kasper]
+
  Changes between 1.0.1l and 1.0.1m [19 Mar 2015]
 
   *) Segmentation fault in ASN1_TYPE_cmp fix
@@ -132,7 +207,7 @@
 
      This issue was reported to OpenSSL by Michal Zalewski (Google).
      (CVE-2015-0289)
-     [Emilia Käsper]
+     [Emilia Käsper]
 
   *) DoS via reachable assert in SSLv2 servers fix
 
@@ -140,10 +215,10 @@
      servers that both support SSLv2 and enable export cipher suites by sending
      a specially crafted SSLv2 CLIENT-MASTER-KEY message.
 
-     This issue was discovered by Sean Burford (Google) and Emilia Käsper
+     This issue was discovered by Sean Burford (Google) and Emilia Käsper
      (OpenSSL development team).
      (CVE-2015-0293)
-     [Emilia Käsper]
+     [Emilia Käsper]
 
   *) Use After Free following d2i_ECPrivatekey error fix
 
@@ -288,12 +363,12 @@
       version does not match the session's version. Resuming with a different
       version, while not strictly forbidden by the RFC, is of questionable
       sanity and breaks all known clients.
-      [David Benjamin, Emilia Käsper]
+      [David Benjamin, Emilia Käsper]
 
    *) Tighten handling of the ChangeCipherSpec (CCS) message: reject
       early CCS messages during renegotiation. (Note that because
       renegotiation is encrypted, this early CCS was not exploitable.)
-      [Emilia Käsper]
+      [Emilia Käsper]
 
    *) Tighten client-side session ticket handling during renegotiation:
       ensure that the client only accepts a session ticket if the server sends
@@ -304,7 +379,7 @@
       Similarly, ensure that the client requires a session ticket if one
       was advertised in the ServerHello. Previously, a TLS client would
       ignore a missing NewSessionTicket message.
-      [Emilia Käsper]
+      [Emilia Käsper]
 
  Changes between 1.0.1i and 1.0.1j [15 Oct 2014]
 
@@ -384,10 +459,10 @@
      with a null pointer dereference (read) by specifying an anonymous (EC)DH
      ciphersuite and sending carefully crafted handshake messages.
 
-     Thanks to Felix Gröbert (Google) for discovering and researching this
+     Thanks to Felix Gröbert (Google) for discovering and researching this
      issue.
      (CVE-2014-3510)
-     [Emilia Käsper]
+     [Emilia Käsper]
 
   *) By sending carefully crafted DTLS packets an attacker could cause openssl
      to leak memory. This can be exploited through a Denial of Service attack.
@@ -424,7 +499,7 @@
      properly negotiated with the client. This can be exploited through a
      Denial of Service attack.
 
-     Thanks to Joonas Kuorilehto and Riku Hietamäki (Codenomicon) for
+     Thanks to Joonas Kuorilehto and Riku Hietamäki (Codenomicon) for
      discovering and researching this issue.
      (CVE-2014-5139)
      [Steve Henson]
@@ -436,7 +511,7 @@
 
      Thanks to Ivan Fratric (Google) for discovering this issue.
      (CVE-2014-3508)
-     [Emilia Käsper, and Steve Henson]
+     [Emilia Käsper, and Steve Henson]
 
   *) Fix ec_GFp_simple_points_make_affine (thus, EC_POINTs_mul etc.)
      for corner cases. (Certain input points at infinity could lead to
@@ -466,15 +541,15 @@
      client or server. This is potentially exploitable to run arbitrary
      code on a vulnerable client or server.
 
-     Thanks to Jüri Aedla for reporting this issue. (CVE-2014-0195)
-     [Jüri Aedla, Steve Henson]
+     Thanks to Jüri Aedla for reporting this issue. (CVE-2014-0195)
+     [Jüri Aedla, Steve Henson]
 
   *) Fix bug in TLS code where clients enable anonymous ECDH ciphersuites
      are subject to a denial of service attack.
 
-     Thanks to Felix Gröbert and Ivan Fratric at Google for discovering
+     Thanks to Felix Gröbert and Ivan Fratric at Google for discovering
      this issue. (CVE-2014-3470)
-     [Felix Gröbert, Ivan Fratric, Steve Henson]
+     [Felix Gröbert, Ivan Fratric, Steve Henson]
 
   *) Harmonize version and its documentation. -f flag is used to display
      compilation flags.
@@ -553,9 +628,9 @@
      Thanks go to Nadhem Alfardan and Kenny Paterson of the Information
      Security Group at Royal Holloway, University of London
      (www.isg.rhul.ac.uk) for discovering this flaw and Adam Langley and
-     Emilia Käsper for the initial patch.
+     Emilia Käsper for the initial patch.
      (CVE-2013-0169)
-     [Emilia Käsper, Adam Langley, Ben Laurie, Andy Polyakov, Steve Henson]
+     [Emilia Käsper, Adam Langley, Ben Laurie, Andy Polyakov, Steve Henson]
 
   *) Fix flaw in AESNI handling of TLS 1.2 and 1.1 records for CBC mode
      ciphersuites which can be exploited in a denial of service attack.
@@ -730,7 +805,7 @@
      EC_GROUP_new_by_curve_name() will automatically use these (while
      EC_GROUP_new_curve_GFp() currently prefers the more flexible
      implementations).
-     [Emilia Käsper, Adam Langley, Bodo Moeller (Google)]
+     [Emilia Käsper, Adam Langley, Bodo Moeller (Google)]
 
   *) Use type ossl_ssize_t instad of ssize_t which isn't available on
      all platforms. Move ssize_t definition from e_os.h to the public
@@ -1006,7 +1081,7 @@
      [Adam Langley (Google)]
 
   *) Fix spurious failures in ecdsatest.c.
-     [Emilia Käsper (Google)]
+     [Emilia Käsper (Google)]
 
   *) Fix the BIO_f_buffer() implementation (which was mixing different
      interpretations of the '..._len' fields).
@@ -1020,7 +1095,7 @@
      lock to call BN_BLINDING_invert_ex, and avoids one use of
      BN_BLINDING_update for each BN_BLINDING structure (previously,
      the last update always remained unused).
-     [Emilia Käsper (Google)]
+     [Emilia Käsper (Google)]
 
   *) In ssl3_clear, preserve s3->init_extra along with s3->rbuf.
      [Bob Buckholz (Google)]
@@ -1829,7 +1904,7 @@
 
   *) Add RFC 3161 compliant time stamp request creation, response generation
      and response verification functionality.
-     [Zoltán Glózik <zglozik@opentsa.org>, The OpenTSA Project]
+     [Zoltán Glózik <zglozik@opentsa.org>, The OpenTSA Project]
 
   *) Add initial support for TLS extensions, specifically for the server_name
      extension so far.  The SSL_SESSION, SSL_CTX, and SSL data structures now
@@ -2997,7 +3072,7 @@
 
   *) BN_CTX_get() should return zero-valued bignums, providing the same
      initialised value as BN_new().
-     [Geoff Thorpe, suggested by Ulf Möller]
+     [Geoff Thorpe, suggested by Ulf Möller]
 
   *) Support for inhibitAnyPolicy certificate extension.
      [Steve Henson]
@@ -3016,7 +3091,7 @@
      some point, these tighter rules will become openssl's default to improve
      maintainability, though the assert()s and other overheads will remain only
      in debugging configurations. See bn.h for more details.
-     [Geoff Thorpe, Nils Larsch, Ulf Möller]
+     [Geoff Thorpe, Nils Larsch, Ulf Möller]
 
   *) BN_CTX_init() has been deprecated, as BN_CTX is an opaque structure
      that can only be obtained through BN_CTX_new() (which implicitly
@@ -3083,7 +3158,7 @@
      [Douglas Stebila (Sun Microsystems Laboratories)]
 
   *) Add the possibility to load symbols globally with DSO.
-     [Götz Babin-Ebell <babin-ebell@trustcenter.de> via Richard Levitte]
+     [Götz Babin-Ebell <babin-ebell@trustcenter.de> via Richard Levitte]
 
   *) Add the functions ERR_set_mark() and ERR_pop_to_mark() for better
      control of the error stack.
@@ -3798,7 +3873,7 @@
      [Steve Henson]
 
   *) Undo Cygwin change.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Added support for proxy certificates according to RFC 3820.
      Because they may be a security thread to unaware applications,
@@ -3831,11 +3906,11 @@
      [Stephen Henson, reported by UK NISCC]
 
   *) Use Windows randomness collection on Cygwin.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Fix hang in EGD/PRNGD query when communication socket is closed
      prematurely by EGD/PRNGD.
-     [Darren Tucker <dtucker@zip.com.au> via Lutz Jänicke, resolves #1014]
+     [Darren Tucker <dtucker@zip.com.au> via Lutz Jänicke, resolves #1014]
 
   *) Prompt for pass phrases when appropriate for PKCS12 input format.
      [Steve Henson]
@@ -4297,7 +4372,7 @@
      pointers passed to them whenever necessary. Otherwise it is possible
      the caller may have overwritten (or deallocated) the original string
      data when a later ENGINE operation tries to use the stored values.
-     [Götz Babin-Ebell <babinebell@trustcenter.de>]
+     [Götz Babin-Ebell <babinebell@trustcenter.de>]
 
   *) Improve diagnostics in file reading and command-line digests.
      [Ben Laurie aided and abetted by Solar Designer <solar@openwall.com>]
@@ -6402,7 +6477,7 @@
      [Bodo Moeller]
 
   *) BN_sqr() bug fix.
-     [Ulf Möller, reported by Jim Ellis <jim.ellis@cavium.com>]
+     [Ulf Möller, reported by Jim Ellis <jim.ellis@cavium.com>]
 
   *) Rabin-Miller test analyses assume uniformly distributed witnesses,
      so use BN_pseudo_rand_range() instead of using BN_pseudo_rand()
@@ -6562,7 +6637,7 @@
      [Bodo Moeller]
 
   *) Fix OAEP check.
-     [Ulf Möller, Bodo Möller]
+     [Ulf Möller, Bodo Möller]
 
   *) The countermeasure against Bleichbacher's attack on PKCS #1 v1.5
      RSA encryption was accidentally removed in s3_srvr.c in OpenSSL 0.9.5
@@ -6824,10 +6899,10 @@
      [Bodo Moeller]
 
   *) Use better test patterns in bntest.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) rand_win.c fix for Borland C.
-     [Ulf Möller]
+     [Ulf Möller]
  
   *) BN_rshift bugfix for n == 0.
      [Bodo Moeller]
@@ -6972,14 +7047,14 @@
 
   *) New BIO_shutdown_wr macro, which invokes the BIO_C_SHUTDOWN_WR
      BIO_ctrl (for BIO pairs).
-     [Bodo Möller]
+     [Bodo Möller]
 
   *) Add DSO method for VMS.
      [Richard Levitte]
 
   *) Bug fix: Montgomery multiplication could produce results with the
      wrong sign.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Add RPM specification openssl.spec and modify it to build three
      packages.  The default package contains applications, application
@@ -6997,7 +7072,7 @@
 
   *) Don't set the two most significant bits to one when generating a
      random number < q in the DSA library.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) New SSL API mode 'SSL_MODE_AUTO_RETRY'.  This disables the default
      behaviour that SSL_read may result in SSL_ERROR_WANT_READ (even if
@@ -7263,7 +7338,7 @@
   *) Randomness polling function for Win9x, as described in:
      Peter Gutmann, Software Generation of Practically Strong
      Random Numbers.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Fix so PRNG is seeded in req if using an already existing
      DSA key.
@@ -7483,7 +7558,7 @@
      [Steve Henson]
 
   *) Eliminate non-ANSI declarations in crypto.h and stack.h.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Fix for SSL server purpose checking. Server checking was
      rejecting certificates which had extended key usage present
@@ -7515,7 +7590,7 @@
      [Bodo Moeller]
 
   *) Bugfix for linux-elf makefile.one.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) RSA_get_default_method() will now cause a default
      RSA_METHOD to be chosen if one doesn't exist already.
@@ -7604,7 +7679,7 @@
      [Steve Henson]
 
   *) des_quad_cksum() byte order bug fix.
-     [Ulf Möller, using the problem description in krb4-0.9.7, where
+     [Ulf Möller, using the problem description in krb4-0.9.7, where
       the solution is attributed to Derrick J Brashear <shadow@DEMENTIA.ORG>]
 
   *) Fix so V_ASN1_APP_CHOOSE works again: however its use is strongly
@@ -7705,7 +7780,7 @@
      [Rolf Haberrecker <rolf@suse.de>]
 
   *) Assembler module support for Mingw32.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Shared library support for HPUX (in shlib/).
      [Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE> and Anonymous]
@@ -7724,7 +7799,7 @@
 
   *) BN_mul bugfix: In bn_mul_part_recursion() only the a>a[n] && b>b[n]
      case was implemented. This caused BN_div_recp() to fail occasionally.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Add an optional second argument to the set_label() in the perl
      assembly language builder. If this argument exists and is set
@@ -7754,14 +7829,14 @@
      [Steve Henson]
 
   *) Fix potential buffer overrun problem in BIO_printf().
-     [Ulf Möller, using public domain code by Patrick Powell; problem
+     [Ulf Möller, using public domain code by Patrick Powell; problem
       pointed out by David Sacerdote <das33@cornell.edu>]
 
   *) Support EGD <http://www.lothar.com/tech/crypto/>.  New functions
      RAND_egd() and RAND_status().  In the command line application,
      the EGD socket can be specified like a seed file using RANDFILE
      or -rand.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Allow the string CERTIFICATE to be tolerated in PKCS#7 structures.
      Some CAs (e.g. Verisign) distribute certificates in this form.
@@ -7794,7 +7869,7 @@
         #define OPENSSL_ALGORITHM_DEFINES
         #include <openssl/opensslconf.h>
      defines all pertinent NO_<algo> symbols, such as NO_IDEA, NO_RSA, etc.
-     [Richard Levitte, Ulf and Bodo Möller]
+     [Richard Levitte, Ulf and Bodo Möller]
 
   *) Bugfix: Tolerate fragmentation and interleaving in the SSL 3/TLS
      record layer.
@@ -7845,17 +7920,17 @@
 
   *) Bug fix for BN_div_recp() for numerators with an even number of
      bits.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) More tests in bntest.c, and changed test_bn output.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) ./config recognizes MacOS X now.
      [Andy Polyakov]
 
   *) Bug fix for BN_div() when the first words of num and divsor are
      equal (it gave wrong results if (rem=(n1-q*d0)&BN_MASK2) < d0).
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Add support for various broken PKCS#8 formats, and command line
      options to produce them.
@@ -7863,11 +7938,11 @@
 
   *) New functions BN_CTX_start(), BN_CTX_get() and BT_CTX_end() to
      get temporary BIGNUMs from a BN_CTX.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Correct return values in BN_mod_exp_mont() and BN_mod_exp2_mont()
      for p == 0.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Change the SSLeay_add_all_*() functions to OpenSSL_add_all_*() and
      include a #define from the old name to the new. The original intent
@@ -7891,7 +7966,7 @@
 
   *) Source code cleanups: use const where appropriate, eliminate casts,
      use void * instead of char * in lhash.
-     [Ulf Möller] 
+     [Ulf Möller] 
 
   *) Bugfix: ssl3_send_server_key_exchange was not restartable
      (the state was not changed to SSL3_ST_SW_KEY_EXCH_B, and because of
@@ -7936,13 +8011,13 @@
      [Steve Henson]
 
   *) New function BN_pseudo_rand().
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Clean up BN_mod_mul_montgomery(): replace the broken (and unreadable)
      bignum version of BN_from_montgomery() with the working code from
      SSLeay 0.9.0 (the word based version is faster anyway), and clean up
      the comments.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Avoid a race condition in s2_clnt.c (function get_server_hello) that
      made it impossible to use the same SSL_SESSION data structure in
@@ -7952,25 +8027,25 @@
   *) The return value of RAND_load_file() no longer counts bytes obtained
      by stat().  RAND_load_file(..., -1) is new and uses the complete file
      to seed the PRNG (previously an explicit byte count was required).
-     [Ulf Möller, Bodo Möller]
+     [Ulf Möller, Bodo Möller]
 
   *) Clean up CRYPTO_EX_DATA functions, some of these didn't have prototypes
      used (char *) instead of (void *) and had casts all over the place.
      [Steve Henson]
 
   *) Make BN_generate_prime() return NULL on error if ret!=NULL.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Retain source code compatibility for BN_prime_checks macro:
      BN_is_prime(..., BN_prime_checks, ...) now uses
      BN_prime_checks_for_size to determine the appropriate number of
      Rabin-Miller iterations.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Diffie-Hellman uses "safe" primes: DH_check() return code renamed to
      DH_CHECK_P_NOT_SAFE_PRIME.
      (Check if this is true? OpenPGP calls them "strong".)
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Merge the functionality of "dh" and "gendh" programs into a new program
      "dhparam". The old programs are retained for now but will handle DH keys
@@ -8026,7 +8101,7 @@
   *) Add missing #ifndefs that caused missing symbols when building libssl
      as a shared library without RSA.  Use #ifndef NO_SSL2 instead of
      NO_RSA in ssl/s2*.c. 
-     [Kris Kennaway <kris@hub.freebsd.org>, modified by Ulf Möller]
+     [Kris Kennaway <kris@hub.freebsd.org>, modified by Ulf Möller]
 
   *) Precautions against using the PRNG uninitialized: RAND_bytes() now
      has a return value which indicates the quality of the random data
@@ -8035,7 +8110,7 @@
      guaranteed to be unique but not unpredictable. RAND_add is like
      RAND_seed, but takes an extra argument for an entropy estimate
      (RAND_seed always assumes full entropy).
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Do more iterations of Rabin-Miller probable prime test (specifically,
      3 for 1024-bit primes, 6 for 512-bit primes, 12 for 256-bit primes
@@ -8065,7 +8140,7 @@
      [Steve Henson]
 
   *) Honor the no-xxx Configure options when creating .DEF files.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Add PKCS#10 attributes to field table: challengePassword, 
      unstructuredName and unstructuredAddress. These are taken from
@@ -8899,7 +8974,7 @@
 
   *) More DES library cleanups: remove references to srand/rand and
      delete an unused file.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Add support for the the free Netwide assembler (NASM) under Win32,
      since not many people have MASM (ml) and it can be hard to obtain.
@@ -8988,7 +9063,7 @@
      worked.
 
   *) Fix problems with no-hmac etc.
-     [Ulf Möller, pointed out by Brian Wellington <bwelling@tislabs.com>]
+     [Ulf Möller, pointed out by Brian Wellington <bwelling@tislabs.com>]
 
   *) New functions RSA_get_default_method(), RSA_set_method() and
      RSA_get_method(). These allows replacement of RSA_METHODs without having
@@ -9105,7 +9180,7 @@
      [Ben Laurie]
 
   *) DES library cleanups.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Add support for PKCS#5 v2.0 PBE algorithms. This will permit PKCS#8 to be
      used with any cipher unlike PKCS#5 v1.5 which can at most handle 64 bit
@@ -9148,7 +9223,7 @@
      [Christian Forster <fo@hawo.stw.uni-erlangen.de>]
 
   *) config now generates no-xxx options for missing ciphers.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Support the EBCDIC character set (work in progress).
      File ebcdic.c not yet included because it has a different license.
@@ -9261,7 +9336,7 @@
      [Bodo Moeller]
 
   *) Move openssl.cnf out of lib/.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Fix various things to let OpenSSL even pass ``egcc -pipe -O2 -Wall
      -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes
@@ -9318,10 +9393,10 @@
      [Ben Laurie]
 
   *) Support Borland C++ builder.
-     [Janez Jere <jj@void.si>, modified by Ulf Möller]
+     [Janez Jere <jj@void.si>, modified by Ulf Möller]
 
   *) Support Mingw32.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) SHA-1 cleanups and performance enhancements.
      [Andy Polyakov <appro@fy.chalmers.se>]
@@ -9330,7 +9405,7 @@
      [Andy Polyakov <appro@fy.chalmers.se>]
 
   *) Accept any -xxx and +xxx compiler options in Configure.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Update HPUX configuration.
      [Anonymous]
@@ -9363,7 +9438,7 @@
      [Bodo Moeller]
 
   *) OAEP decoding bug fix.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Support INSTALL_PREFIX for package builders, as proposed by
      David Harris.
@@ -9386,21 +9461,21 @@
      [Niels Poppe <niels@netbox.org>]
 
   *) New Configure option no-<cipher> (rsa, idea, rc5, ...).
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Add the PKCS#12 API documentation to openssl.txt. Preliminary support for
      extension adding in x509 utility.
      [Steve Henson]
 
   *) Remove NOPROTO sections and error code comments.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Partial rewrite of the DEF file generator to now parse the ANSI
      prototypes.
      [Steve Henson]
 
   *) New Configure options --prefix=DIR and --openssldir=DIR.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Complete rewrite of the error code script(s). It is all now handled
      by one script at the top level which handles error code gathering,
@@ -9429,7 +9504,7 @@
      [Steve Henson]
 
   *) Move the autogenerated header file parts to crypto/opensslconf.h.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Fix new 56-bit DES export ciphersuites: they were using 7 bytes instead of
      8 of keying material. Merlin has also confirmed interop with this fix
@@ -9447,13 +9522,13 @@
      [Andy Polyakov <appro@fy.chalmers.se>]
 
   *) Change functions to ANSI C.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Fix typos in error codes.
-     [Martin Kraemer <Martin.Kraemer@MchP.Siemens.De>, Ulf Möller]
+     [Martin Kraemer <Martin.Kraemer@MchP.Siemens.De>, Ulf Möller]
 
   *) Remove defunct assembler files from Configure.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) SPARC v8 assembler BIGNUM implementation.
      [Andy Polyakov <appro@fy.chalmers.se>]
@@ -9490,7 +9565,7 @@
      [Steve Henson]
 
   *) New Configure option "rsaref".
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Don't auto-generate pem.h.
      [Bodo Moeller]
@@ -9538,7 +9613,7 @@
 
   *) New functions DSA_do_sign and DSA_do_verify to provide access to
      the raw DSA values prior to ASN.1 encoding.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) Tweaks to Configure
      [Niels Poppe <niels@netbox.org>]
@@ -9548,11 +9623,11 @@
      [Steve Henson]
 
   *) New variables $(RANLIB) and $(PERL) in the Makefiles.
-     [Ulf Möller]
+     [Ulf Möller]
 
   *) New config option to avoid instructions that are illegal on the 80386.
      The default code is faster, but requires at least a 486.
-     [Ulf Möller]
+     [Ulf Möller]
   
   *) Got rid of old SSL2_CLIENT_VERSION (inconsistently used) and
      SSL2_SERVER_VERSION (not used at all) macros, which are now the
@@ -10091,7 +10166,7 @@
       Hagino <itojun@kame.net>]
 
   *) File was opened incorrectly in randfile.c.
-     [Ulf Möller <ulf@fitug.de>]
+     [Ulf Möller <ulf@fitug.de>]
 
   *) Beginning of support for GeneralizedTime. d2i, i2d, check and print
      functions. Also ASN1_TIME suite which is a CHOICE of UTCTime or
@@ -10101,7 +10176,7 @@
      [Steve Henson]
 
   *) Correct Linux 1 recognition in config.
-     [Ulf Möller <ulf@fitug.de>]
+     [Ulf Möller <ulf@fitug.de>]
 
   *) Remove pointless MD5 hash when using DSA keys in ca.
      [Anonymous <nobody@replay.com>]
@@ -10248,7 +10323,7 @@
 
   *) Fix the RSA header declarations that hid a bug I fixed in 0.9.0b but
      was already fixed by Eric for 0.9.1 it seems.
-     [Ben Laurie - pointed out by Ulf Möller <ulf@fitug.de>]
+     [Ben Laurie - pointed out by Ulf Möller <ulf@fitug.de>]
 
   *) Autodetect FreeBSD3.
      [Ben Laurie]
diff --git a/src/third_party/openssl/openssl/CONTRIBUTING b/src/third_party/openssl/openssl/CONTRIBUTING
new file mode 100644
index 0000000..9d63d8a
--- /dev/null
+++ b/src/third_party/openssl/openssl/CONTRIBUTING
@@ -0,0 +1,38 @@
+HOW TO CONTRIBUTE TO OpenSSL
+----------------------------
+
+Development is coordinated on the openssl-dev mailing list (see
+http://www.openssl.org for information on subscribing). If you
+would like to submit a patch, send it to rt@openssl.org with
+the string "[PATCH]" in the subject. Please be sure to include a
+textual explanation of what your patch does.
+
+You can also make GitHub pull requests. If you do this, please also send
+mail to rt@openssl.org with a brief description and a link to the PR so
+that we can more easily keep track of it.
+
+If you are unsure as to whether a feature will be useful for the general
+OpenSSL community please discuss it on the openssl-dev mailing list first.
+Someone may be already working on the same thing or there may be a good
+reason as to why that feature isn't implemented.
+
+Patches should be as up to date as possible, preferably relative to the
+current Git or the last snapshot. They should follow our coding style
+(see https://www.openssl.org/policies/codingstyle.html) and compile without
+warnings using the --strict-warnings flag.  OpenSSL compiles on many varied
+platforms: try to ensure you only use portable features.
+
+Our preferred format for patch files is "git format-patch" output. For example
+to provide a patch file containing the last commit in your local git repository
+use the following command:
+
+# git format-patch --stdout HEAD^ >mydiffs.patch
+
+Another method of creating an acceptable patch file without using git is as
+follows:
+
+# cd openssl-work
+# [your changes]
+# ./Configure dist; make clean
+# cd ..
+# diff -ur openssl-orig openssl-work > mydiffs.patch
diff --git a/src/third_party/openssl/openssl/Configure b/src/third_party/openssl/openssl/Configure
index 60ec378..0a5ffac 100755
--- a/src/third_party/openssl/openssl/Configure
+++ b/src/third_party/openssl/openssl/Configure
@@ -105,6 +105,11 @@
 
 my $gcc_devteam_warn = "-Wall -pedantic -DPEDANTIC -Wno-long-long -Wsign-compare -Wmissing-prototypes -Wshadow -Wformat -Werror -DCRYPTO_MDEBUG_ALL -DCRYPTO_MDEBUG_ABORT -DREF_CHECK -DOPENSSL_NO_DEPRECATED";
 
+# Warn that "make depend" should be run?
+my $warn_make_depend = 0;
+
+my $clang_devteam_warn = "-Wno-unused-parameter -Wno-missing-field-initializers -Wno-language-extension-token -Wno-extended-offsetof -Qunused-arguments";
+
 my $strict_warnings = 0;
 
 my $x86_gcc_des="DES_PTR DES_RISC1 DES_UNROLL";
@@ -197,6 +202,7 @@
 "debug-linux-generic32","gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -g -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
 "debug-linux-generic64","gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -g -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
 "debug-linux-x86_64","gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -m64 -DL_ENDIAN -g -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
+"debug-linux-x86_64-clang","clang: -DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -m64 -DL_ENDIAN -g -Wall -Qunused-arguments::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
 "dist",		"cc:-O::(unknown)::::::",
 
 # Basic configs that should work on any (32 and less bit) box
@@ -361,6 +367,7 @@
 "linux-ia64-ecc","ecc:-DL_ENDIAN -O2 -Wall -no_cpprt::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT:${ia64_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
 "linux-ia64-icc","icc:-DL_ENDIAN -O2 -Wall -no_cpprt::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_INT:${ia64_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
 "linux-x86_64",	"gcc:-m64 -DL_ENDIAN -O3 -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
+"linux-x86_64-clang","clang: -m64 -DL_ENDIAN -O3 -Wall -Qunused-arguments::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
 "linux64-s390x",	"gcc:-m64 -DB_ENDIAN -O3 -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL:${s390x_asm}:64:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
 #### So called "highgprs" target for z/Architecture CPUs
 # "Highgprs" is kernel feature first implemented in Linux 2.6.32, see
@@ -1442,7 +1449,7 @@
 # linker only when --prefix is not /usr.
 if ($target =~ /^BSD\-/)
 	{
-	$shared_ldflag.=" -Wl,-rpath,\$(LIBRPATH)" if ($prefix !~ m|^/usr[/]*$|);
+	$shared_ldflag.=" -Wl,-rpath,\$\$(LIBRPATH)" if ($prefix !~ m|^/usr[/]*$|);
 	}
 
 if ($sys_id ne "")
@@ -1574,11 +1581,20 @@
 
 if ($strict_warnings)
 	{
+	my $ecc = $cc;
+	$ecc = "clang" if `$cc --version 2>&1` =~ /clang/;
 	my $wopt;
-	die "ERROR --strict-warnings requires gcc" unless ($cc =~ /gcc$/);
+	die "ERROR --strict-warnings requires gcc or clang" unless ($ecc =~ /gcc$/ or $ecc =~ /clang$/);
 	foreach $wopt (split /\s+/, $gcc_devteam_warn)
 		{
-		$cflags .= " $wopt" unless ($cflags =~ /$wopt/)
+		$cflags .= " $wopt" unless ($cflags =~ /(^|\s)$wopt(\s|$)/)
+		}
+	if ($ecc eq "clang")
+		{
+		foreach $wopt (split /\s+/, $clang_devteam_warn)
+			{
+			$cflags .= " $wopt" unless ($cflags =~ /(^|\s)$wopt(\s|$)/)
+			}
 		}
 	}
 
@@ -1940,14 +1956,8 @@
 	    &dofile("apps/CA.pl",'/usr/local/bin/perl','^#!/', '#!%s');
 	}
 	if ($depflags ne $default_depflags && !$make_depend) {
-		print <<EOF;
-
-Since you've disabled or enabled at least one algorithm, you need to do
-the following before building:
-
-	make depend
-EOF
-	}
+            $warn_make_depend++;
+        }
 }
 
 # create the ms/version32.rc file if needed
@@ -2026,12 +2036,18 @@
 
 print <<\EOF if ($no_shared_warn);
 
-You gave the option 'shared'.  Normally, that would give you shared libraries.
-Unfortunately, the OpenSSL configuration doesn't include shared library support
-for this platform yet, so it will pretend you gave the option 'no-shared'.  If
-you can inform the developpers (openssl-dev\@openssl.org) how to support shared
-libraries on this platform, they will at least look at it and try their best
-(but please first make sure you have tried with a current version of OpenSSL).
+You gave the option 'shared', which is not supported on this platform, so
+we will pretend you gave the option 'no-shared'.  If you know how to implement
+shared libraries, please let us know (but please first make sure you have
+tried with a current version of OpenSSL).
+EOF
+
+print <<EOF if ($warn_make_depend);
+
+*** Because of configuration changes, you MUST do the following before
+*** building:
+
+	make depend
 EOF
 
 exit(0);
diff --git a/src/third_party/openssl/openssl/FAQ b/src/third_party/openssl/openssl/FAQ
index f8ea604..22c5cf7 100644
--- a/src/third_party/openssl/openssl/FAQ
+++ b/src/third_party/openssl/openssl/FAQ
@@ -1,1039 +1,2 @@
-OpenSSL  -  Frequently Asked Questions
---------------------------------------
-
-[MISC] Miscellaneous questions
-
-* Which is the current version of OpenSSL?
-* Where is the documentation?
-* How can I contact the OpenSSL developers?
-* Where can I get a compiled version of OpenSSL?
-* Why aren't tools like 'autoconf' and 'libtool' used?
-* What is an 'engine' version?
-* How do I check the authenticity of the OpenSSL distribution?
-* How does the versioning scheme work?
-
-[LEGAL] Legal questions
-
-* Do I need patent licenses to use OpenSSL?
-* Can I use OpenSSL with GPL software? 
-
-[USER] Questions on using the OpenSSL applications
-
-* Why do I get a "PRNG not seeded" error message?
-* Why do I get an "unable to write 'random state'" error message?
-* How do I create certificates or certificate requests?
-* Why can't I create certificate requests?
-* Why does <SSL program> fail with a certificate verify error?
-* Why can I only use weak ciphers when I connect to a server using OpenSSL?
-* How can I create DSA certificates?
-* Why can't I make an SSL connection using a DSA certificate?
-* How can I remove the passphrase on a private key?
-* Why can't I use OpenSSL certificates with SSL client authentication?
-* Why does my browser give a warning about a mismatched hostname?
-* How do I install a CA certificate into a browser?
-* Why is OpenSSL x509 DN output not conformant to RFC2253?
-* What is a "128 bit certificate"? Can I create one with OpenSSL?
-* Why does OpenSSL set the authority key identifier extension incorrectly?
-* How can I set up a bundle of commercial root CA certificates?
-
-[BUILD] Questions about building and testing OpenSSL
-
-* Why does the linker complain about undefined symbols?
-* Why does the OpenSSL test fail with "bc: command not found"?
-* Why does the OpenSSL test fail with "bc: 1 no implemented"?
-* Why does the OpenSSL test fail with "bc: stack empty"?
-* Why does the OpenSSL compilation fail on Alpha Tru64 Unix?
-* Why does the OpenSSL compilation fail with "ar: command not found"?
-* Why does the OpenSSL compilation fail on Win32 with VC++?
-* What is special about OpenSSL on Redhat?
-* Why does the OpenSSL compilation fail on MacOS X?
-* Why does the OpenSSL test suite fail on MacOS X?
-* Why does the OpenSSL test suite fail in BN_sqr test [on a 64-bit platform]?
-* Why does OpenBSD-i386 build fail on des-586.s with "Unimplemented segment type"?
-* Why does the OpenSSL test suite fail in sha512t on x86 CPU?
-* Why does compiler fail to compile sha512.c?
-* Test suite still fails, what to do?
-* I think I've found a bug, what should I do?
-* I'm SURE I've found a bug, how do I report it?
-* I've found a security issue, how do I report it?
-
-[PROG] Questions about programming with OpenSSL
-
-* Is OpenSSL thread-safe?
-* I've compiled a program under Windows and it crashes: why?
-* How do I read or write a DER encoded buffer using the ASN1 functions?
-* OpenSSL uses DER but I need BER format: does OpenSSL support BER?
-* I've tried using <M_some_evil_pkcs12_macro> and I get errors why?
-* I've called <some function> and it fails, why?
-* I just get a load of numbers for the error output, what do they mean?
-* Why do I get errors about unknown algorithms?
-* Why can't the OpenSSH configure script detect OpenSSL?
-* Can I use OpenSSL's SSL library with non-blocking I/O?
-* Why doesn't my server application receive a client certificate?
-* Why does compilation fail due to an undefined symbol NID_uniqueIdentifier?
-* I think I've detected a memory leak, is this a bug?
-* Why does Valgrind complain about the use of uninitialized data?
-* Why doesn't a memory BIO work when a file does?
-* Where are the declarations and implementations of d2i_X509() etc?
-
-===============================================================================
-
-[MISC] ========================================================================
-
-* Which is the current version of OpenSSL?
-
-The current version is available from <URL: http://www.openssl.org>.
-OpenSSL 1.0.1e was released on Feb 11th, 2013.
-
-In addition to the current stable release, you can also access daily
-snapshots of the OpenSSL development version at <URL:
-ftp://ftp.openssl.org/snapshot/>, or get it by anonymous Git access.
-
-
-* Where is the documentation?
-
-OpenSSL is a library that provides cryptographic functionality to
-applications such as secure web servers.  Be sure to read the
-documentation of the application you want to use.  The INSTALL file
-explains how to install this library.
-
-OpenSSL includes a command line utility that can be used to perform a
-variety of cryptographic functions.  It is described in the openssl(1)
-manpage.  Documentation for developers is currently being written. Many
-manual pages are available; overviews over libcrypto and
-libssl are given in the crypto(3) and ssl(3) manpages.
-
-The OpenSSL manpages are installed in /usr/local/ssl/man/ (or a
-different directory if you specified one as described in INSTALL).
-In addition, you can read the most current versions at
-<URL: http://www.openssl.org/docs/>. Note that the online documents refer
-to the very latest development versions of OpenSSL and may include features
-not present in released versions. If in doubt refer to the documentation
-that came with the version of OpenSSL you are using. The pod format
-documentation is included in each OpenSSL distribution under the docs
-directory.
-
-There is some documentation about certificate extensions and PKCS#12
-in doc/openssl.txt
-
-The original SSLeay documentation is included in OpenSSL as
-doc/ssleay.txt.  It may be useful when none of the other resources
-help, but please note that it reflects the obsolete version SSLeay
-0.6.6.
-
-
-* How can I contact the OpenSSL developers?
-
-The README file describes how to submit bug reports and patches to
-OpenSSL.  Information on the OpenSSL mailing lists is available from
-<URL: http://www.openssl.org>.
-
-
-* Where can I get a compiled version of OpenSSL?
-
-You can finder pointers to binary distributions in
-<URL: http://www.openssl.org/related/binaries.html> .
-
-Some applications that use OpenSSL are distributed in binary form.
-When using such an application, you don't need to install OpenSSL
-yourself; the application will include the required parts (e.g. DLLs).
-
-If you want to build OpenSSL on a Windows system and you don't have
-a C compiler, read the "Mingw32" section of INSTALL.W32 for information
-on how to obtain and install the free GNU C compiler.
-
-A number of Linux and *BSD distributions include OpenSSL.
-
-
-* Why aren't tools like 'autoconf' and 'libtool' used?
-
-autoconf will probably be used in future OpenSSL versions. If it was
-less Unix-centric, it might have been used much earlier.
-
-* What is an 'engine' version?
-
-With version 0.9.6 OpenSSL was extended to interface to external crypto
-hardware. This was realized in a special release '0.9.6-engine'. With
-version 0.9.7 the changes were merged into the main development line,
-so that the special release is no longer necessary.
-
-* How do I check the authenticity of the OpenSSL distribution?
-
-We provide MD5 digests and ASC signatures of each tarball.
-Use MD5 to check that a tarball from a mirror site is identical:
-
-   md5sum TARBALL | awk '{print $1;}' | cmp - TARBALL.md5
-
-You can check authenticity using pgp or gpg. You need the OpenSSL team
-member public key used to sign it (download it from a key server, see a
-list of keys at <URL: http://www.openssl.org/about/>). Then
-just do:
-
-   pgp TARBALL.asc
-
-* How does the versioning scheme work?
-
-After the release of OpenSSL 1.0.0 the versioning scheme changed. Letter 
-releases (e.g. 1.0.1a) can only contain bug and security fixes and no
-new features. Minor releases change the last number (e.g. 1.0.2) and 
-can contain new features that retain binary compatibility. Changes to
-the middle number are considered major releases and neither source nor
-binary compatibility is guaranteed.
-
-Therefore the answer to the common question "when will feature X be
-backported to OpenSSL 1.0.0/0.9.8?" is "never" but it could appear
-in the next minor release.
-
-[LEGAL] =======================================================================
-
-* Do I need patent licenses to use OpenSSL?
-
-The patents section of the README file lists patents that may apply to
-you if you want to use OpenSSL.  For information on intellectual
-property rights, please consult a lawyer.  The OpenSSL team does not
-offer legal advice.
-
-You can configure OpenSSL so as not to use IDEA, MDC2 and RC5 by using
- ./config no-idea no-mdc2 no-rc5
-
-
-* Can I use OpenSSL with GPL software?
-
-On many systems including the major Linux and BSD distributions, yes (the
-GPL does not place restrictions on using libraries that are part of the
-normal operating system distribution).
-
-On other systems, the situation is less clear. Some GPL software copyright
-holders claim that you infringe on their rights if you use OpenSSL with
-their software on operating systems that don't normally include OpenSSL.
-
-If you develop open source software that uses OpenSSL, you may find it
-useful to choose an other license than the GPL, or state explicitly that
-"This program is released under the GPL with the additional exemption that
-compiling, linking, and/or using OpenSSL is allowed."  If you are using
-GPL software developed by others, you may want to ask the copyright holder
-for permission to use their software with OpenSSL.
-
-
-[USER] ========================================================================
-
-* Why do I get a "PRNG not seeded" error message?
-
-Cryptographic software needs a source of unpredictable data to work
-correctly.  Many open source operating systems provide a "randomness
-device" (/dev/urandom or /dev/random) that serves this purpose.
-All OpenSSL versions try to use /dev/urandom by default; starting with
-version 0.9.7, OpenSSL also tries /dev/random if /dev/urandom is not
-available.
-
-On other systems, applications have to call the RAND_add() or
-RAND_seed() function with appropriate data before generating keys or
-performing public key encryption. (These functions initialize the
-pseudo-random number generator, PRNG.)  Some broken applications do
-not do this.  As of version 0.9.5, the OpenSSL functions that need
-randomness report an error if the random number generator has not been
-seeded with at least 128 bits of randomness.  If this error occurs and
-is not discussed in the documentation of the application you are
-using, please contact the author of that application; it is likely
-that it never worked correctly.  OpenSSL 0.9.5 and later make the
-error visible by refusing to perform potentially insecure encryption.
-
-If you are using Solaris 8, you can add /dev/urandom and /dev/random
-devices by installing patch 112438 (Sparc) or 112439 (x86), which are
-available via the Patchfinder at <URL: http://sunsolve.sun.com>
-(Solaris 9 includes these devices by default). For /dev/random support
-for earlier Solaris versions, see Sun's statement at
-<URL: http://sunsolve.sun.com/pub-cgi/retrieve.pl?doc=fsrdb/27606&zone_32=SUNWski>
-(the SUNWski package is available in patch 105710).
-
-On systems without /dev/urandom and /dev/random, it is a good idea to
-use the Entropy Gathering Demon (EGD); see the RAND_egd() manpage for
-details.  Starting with version 0.9.7, OpenSSL will automatically look
-for an EGD socket at /var/run/egd-pool, /dev/egd-pool, /etc/egd-pool and
-/etc/entropy.
-
-Most components of the openssl command line utility automatically try
-to seed the random number generator from a file.  The name of the
-default seeding file is determined as follows: If environment variable
-RANDFILE is set, then it names the seeding file.  Otherwise if
-environment variable HOME is set, then the seeding file is $HOME/.rnd.
-If neither RANDFILE nor HOME is set, versions up to OpenSSL 0.9.6 will
-use file .rnd in the current directory while OpenSSL 0.9.6a uses no
-default seeding file at all.  OpenSSL 0.9.6b and later will behave
-similarly to 0.9.6a, but will use a default of "C:\" for HOME on
-Windows systems if the environment variable has not been set.
-
-If the default seeding file does not exist or is too short, the "PRNG
-not seeded" error message may occur.
-
-The openssl command line utility will write back a new state to the
-default seeding file (and create this file if necessary) unless
-there was no sufficient seeding.
-
-Pointing $RANDFILE to an Entropy Gathering Daemon socket does not work.
-Use the "-rand" option of the OpenSSL command line tools instead.
-The $RANDFILE environment variable and $HOME/.rnd are only used by the
-OpenSSL command line tools. Applications using the OpenSSL library
-provide their own configuration options to specify the entropy source,
-please check out the documentation coming the with application.
-
-
-* Why do I get an "unable to write 'random state'" error message?
-
-
-Sometimes the openssl command line utility does not abort with
-a "PRNG not seeded" error message, but complains that it is
-"unable to write 'random state'".  This message refers to the
-default seeding file (see previous answer).  A possible reason
-is that no default filename is known because neither RANDFILE
-nor HOME is set.  (Versions up to 0.9.6 used file ".rnd" in the
-current directory in this case, but this has changed with 0.9.6a.)
-
-
-* How do I create certificates or certificate requests?
-
-Check out the CA.pl(1) manual page. This provides a simple wrapper round
-the 'req', 'verify', 'ca' and 'pkcs12' utilities. For finer control check
-out the manual pages for the individual utilities and the certificate
-extensions documentation (in ca(1), req(1), x509v3_config(5) )
-
-
-* Why can't I create certificate requests?
-
-You typically get the error:
-
-	unable to find 'distinguished_name' in config
-	problems making Certificate Request
-
-This is because it can't find the configuration file. Check out the
-DIAGNOSTICS section of req(1) for more information.
-
-
-* Why does <SSL program> fail with a certificate verify error?
-
-This problem is usually indicated by log messages saying something like
-"unable to get local issuer certificate" or "self signed certificate".
-When a certificate is verified its root CA must be "trusted" by OpenSSL
-this typically means that the CA certificate must be placed in a directory
-or file and the relevant program configured to read it. The OpenSSL program
-'verify' behaves in a similar way and issues similar error messages: check
-the verify(1) program manual page for more information.
-
-
-* Why can I only use weak ciphers when I connect to a server using OpenSSL?
-
-This is almost certainly because you are using an old "export grade" browser
-which only supports weak encryption. Upgrade your browser to support 128 bit
-ciphers.
-
-
-* How can I create DSA certificates?
-
-Check the CA.pl(1) manual page for a DSA certificate example.
-
-
-* Why can't I make an SSL connection to a server using a DSA certificate?
-
-Typically you'll see a message saying there are no shared ciphers when
-the same setup works fine with an RSA certificate. There are two possible
-causes. The client may not support connections to DSA servers most web
-browsers (including Netscape and MSIE) only support connections to servers
-supporting RSA cipher suites. The other cause is that a set of DH parameters
-has not been supplied to the server. DH parameters can be created with the
-dhparam(1) command and loaded using the SSL_CTX_set_tmp_dh() for example:
-check the source to s_server in apps/s_server.c for an example.
-
-
-* How can I remove the passphrase on a private key?
-
-Firstly you should be really *really* sure you want to do this. Leaving
-a private key unencrypted is a major security risk. If you decide that
-you do have to do this check the EXAMPLES sections of the rsa(1) and
-dsa(1) manual pages.
-
-
-* Why can't I use OpenSSL certificates with SSL client authentication?
-
-What will typically happen is that when a server requests authentication
-it will either not include your certificate or tell you that you have
-no client certificates (Netscape) or present you with an empty list box
-(MSIE). The reason for this is that when a server requests a client
-certificate it includes a list of CAs names which it will accept. Browsers
-will only let you select certificates from the list on the grounds that
-there is little point presenting a certificate which the server will
-reject.
-
-The solution is to add the relevant CA certificate to your servers "trusted
-CA list". How you do this depends on the server software in uses. You can
-print out the servers list of acceptable CAs using the OpenSSL s_client tool:
-
-openssl s_client -connect www.some.host:443 -prexit
-
-If your server only requests certificates on certain URLs then you may need
-to manually issue an HTTP GET command to get the list when s_client connects:
-
-GET /some/page/needing/a/certificate.html
-
-If your CA does not appear in the list then this confirms the problem.
-
-
-* Why does my browser give a warning about a mismatched hostname?
-
-Browsers expect the server's hostname to match the value in the commonName
-(CN) field of the certificate. If it does not then you get a warning.
-
-
-* How do I install a CA certificate into a browser?
-
-The usual way is to send the DER encoded certificate to the browser as
-MIME type application/x-x509-ca-cert, for example by clicking on an appropriate
-link. On MSIE certain extensions such as .der or .cacert may also work, or you
-can import the certificate using the certificate import wizard.
-
-You can convert a certificate to DER form using the command:
-
-openssl x509 -in ca.pem -outform DER -out ca.der
-
-Occasionally someone suggests using a command such as:
-
-openssl pkcs12 -export -out cacert.p12 -in cacert.pem -inkey cakey.pem
-
-DO NOT DO THIS! This command will give away your CAs private key and
-reduces its security to zero: allowing anyone to forge certificates in
-whatever name they choose.
-
-* Why is OpenSSL x509 DN output not conformant to RFC2253?
-
-The ways to print out the oneline format of the DN (Distinguished Name) have
-been extended in version 0.9.7 of OpenSSL. Using the new X509_NAME_print_ex()
-interface, the "-nameopt" option could be introduded. See the manual
-page of the "openssl x509" commandline tool for details. The old behaviour
-has however been left as default for the sake of compatibility.
-
-* What is a "128 bit certificate"? Can I create one with OpenSSL?
-
-The term "128 bit certificate" is a highly misleading marketing term. It does
-*not* refer to the size of the public key in the certificate! A certificate
-containing a 128 bit RSA key would have negligible security.
-
-There were various other names such as "magic certificates", "SGC
-certificates", "step up certificates" etc.
-
-You can't generally create such a certificate using OpenSSL but there is no
-need to any more. Nowadays web browsers using unrestricted strong encryption
-are generally available.
-
-When there were tight restrictions on the export of strong encryption
-software from the US only weak encryption algorithms could be freely exported
-(initially 40 bit and then 56 bit). It was widely recognised that this was
-inadequate. A relaxation of the rules allowed the use of strong encryption but
-only to an authorised server.
-
-Two slighly different techniques were developed to support this, one used by
-Netscape was called "step up", the other used by MSIE was called "Server Gated
-Cryptography" (SGC). When a browser initially connected to a server it would
-check to see if the certificate contained certain extensions and was issued by
-an authorised authority. If these test succeeded it would reconnect using
-strong encryption.
-
-Only certain (initially one) certificate authorities could issue the
-certificates and they generally cost more than ordinary certificates.
-
-Although OpenSSL can create certificates containing the appropriate extensions
-the certificate would not come from a permitted authority and so would not
-be recognized.
-
-The export laws were later changed to allow almost unrestricted use of strong
-encryption so these certificates are now obsolete.
-
-
-* Why does OpenSSL set the authority key identifier (AKID) extension incorrectly?
-
-It doesn't: this extension is often the cause of confusion.
-
-Consider a certificate chain A->B->C so that A signs B and B signs C. Suppose
-certificate C contains AKID.
-
-The purpose of this extension is to identify the authority certificate B. This
-can be done either by including the subject key identifier of B or its issuer
-name and serial number.
-
-In this latter case because it is identifying certifcate B it must contain the
-issuer name and serial number of B.
-
-It is often wrongly assumed that it should contain the subject name of B. If it
-did this would be redundant information because it would duplicate the issuer
-name of C.
-
-
-* How can I set up a bundle of commercial root CA certificates?
-
-The OpenSSL software is shipped without any root CA certificate as the
-OpenSSL project does not have any policy on including or excluding
-any specific CA and does not intend to set up such a policy. Deciding
-about which CAs to support is up to application developers or
-administrators.
-
-Other projects do have other policies so you can for example extract the CA
-bundle used by Mozilla and/or modssl as described in this article:
-
-  <URL: http://www.mail-archive.com/modssl-users@modssl.org/msg16980.html>
-
-
-[BUILD] =======================================================================
-
-* Why does the linker complain about undefined symbols?
-
-Maybe the compilation was interrupted, and make doesn't notice that
-something is missing.  Run "make clean; make".
-
-If you used ./Configure instead of ./config, make sure that you
-selected the right target.  File formats may differ slightly between
-OS versions (for example sparcv8/sparcv9, or a.out/elf).
-
-In case you get errors about the following symbols, use the config
-option "no-asm", as described in INSTALL:
-
- BF_cbc_encrypt, BF_decrypt, BF_encrypt, CAST_cbc_encrypt,
- CAST_decrypt, CAST_encrypt, RC4, RC5_32_cbc_encrypt, RC5_32_decrypt,
- RC5_32_encrypt, bn_add_words, bn_div_words, bn_mul_add_words,
- bn_mul_comba4, bn_mul_comba8, bn_mul_words, bn_sqr_comba4,
- bn_sqr_comba8, bn_sqr_words, bn_sub_words, des_decrypt3,
- des_ede3_cbc_encrypt, des_encrypt, des_encrypt2, des_encrypt3,
- des_ncbc_encrypt, md5_block_asm_host_order, sha1_block_asm_data_order
-
-If none of these helps, you may want to try using the current snapshot.
-If the problem persists, please submit a bug report.
-
-
-* Why does the OpenSSL test fail with "bc: command not found"?
-
-You didn't install "bc", the Unix calculator.  If you want to run the
-tests, get GNU bc from ftp://ftp.gnu.org or from your OS distributor.
-
-
-* Why does the OpenSSL test fail with "bc: 1 no implemented"?
-
-On some SCO installations or versions, bc has a bug that gets triggered
-when you run the test suite (using "make test").  The message returned is
-"bc: 1 not implemented".
-
-The best way to deal with this is to find another implementation of bc
-and compile/install it.  GNU bc (see <URL: http://www.gnu.org/software/software.html>
-for download instructions) can be safely used, for example.
-
-
-* Why does the OpenSSL test fail with "bc: stack empty"?
-
-On some DG/ux versions, bc seems to have a too small stack for calculations
-that the OpenSSL bntest throws at it.  This gets triggered when you run the
-test suite (using "make test").  The message returned is "bc: stack empty".
-
-The best way to deal with this is to find another implementation of bc
-and compile/install it.  GNU bc (see <URL: http://www.gnu.org/software/software.html>
-for download instructions) can be safely used, for example.
-
-
-* Why does the OpenSSL compilation fail on Alpha Tru64 Unix?
-
-On some Alpha installations running Tru64 Unix and Compaq C, the compilation
-of crypto/sha/sha_dgst.c fails with the message 'Fatal:  Insufficient virtual
-memory to continue compilation.'  As far as the tests have shown, this may be
-a compiler bug.  What happens is that it eats up a lot of resident memory
-to build something, probably a table.  The problem is clearly in the
-optimization code, because if one eliminates optimization completely (-O0),
-the compilation goes through (and the compiler consumes about 2MB of resident
-memory instead of 240MB or whatever one's limit is currently).
-
-There are three options to solve this problem:
-
-1. set your current data segment size soft limit higher.  Experience shows
-that about 241000 kbytes seems to be enough on an AlphaServer DS10.  You do
-this with the command 'ulimit -Sd nnnnnn', where 'nnnnnn' is the number of
-kbytes to set the limit to.
-
-2. If you have a hard limit that is lower than what you need and you can't
-get it changed, you can compile all of OpenSSL with -O0 as optimization
-level.  This is however not a very nice thing to do for those who expect to
-get the best result from OpenSSL.  A bit more complicated solution is the
-following:
-
------ snip:start -----
-  make DIRS=crypto SDIRS=sha "`grep '^CFLAG=' Makefile.ssl | \
-       sed -e 's/ -O[0-9] / -O0 /'`"
-  rm `ls crypto/*.o crypto/sha/*.o | grep -v 'sha_dgst\.o'`
-  make
------ snip:end -----
-
-This will only compile sha_dgst.c with -O0, the rest with the optimization
-level chosen by the configuration process.  When the above is done, do the
-test and installation and you're set.
-
-3. Reconfigure the toolkit with no-sha0 option to leave out SHA0. It 
-should not be used and is not used in SSL/TLS nor any other recognized
-protocol in either case.
-
-
-* Why does the OpenSSL compilation fail with "ar: command not found"?
-
-Getting this message is quite usual on Solaris 2, because Sun has hidden
-away 'ar' and other development commands in directories that aren't in
-$PATH by default.  One of those directories is '/usr/ccs/bin'.  The
-quickest way to fix this is to do the following (it assumes you use sh
-or any sh-compatible shell):
-
------ snip:start -----
-  PATH=${PATH}:/usr/ccs/bin; export PATH
------ snip:end -----
-
-and then redo the compilation.  What you should really do is make sure
-'/usr/ccs/bin' is permanently in your $PATH, for example through your
-'.profile' (again, assuming you use a sh-compatible shell).
-
-
-* Why does the OpenSSL compilation fail on Win32 with VC++?
-
-Sometimes, you may get reports from VC++ command line (cl) that it
-can't find standard include files like stdio.h and other weirdnesses.
-One possible cause is that the environment isn't correctly set up.
-To solve that problem for VC++ versions up to 6, one should run
-VCVARS32.BAT which is found in the 'bin' subdirectory of the VC++
-installation directory (somewhere under 'Program Files').  For VC++
-version 7 (and up?), which is also called VS.NET, the file is called
-VSVARS32.BAT instead.
-This needs to be done prior to running NMAKE, and the changes are only
-valid for the current DOS session.
-
-
-* What is special about OpenSSL on Redhat?
-
-Red Hat Linux (release 7.0 and later) include a preinstalled limited
-version of OpenSSL. For patent reasons, support for IDEA, RC5 and MDC2
-is disabled in this version. The same may apply to other Linux distributions.
-Users may therefore wish to install more or all of the features left out.
-
-To do this you MUST ensure that you do not overwrite the openssl that is in
-/usr/bin on your Red Hat machine. Several packages depend on this file,
-including sendmail and ssh. /usr/local/bin is a good alternative choice. The
-libraries that come with Red Hat 7.0 onwards have different names and so are
-not affected. (eg For Red Hat 7.2 they are /lib/libssl.so.0.9.6b and
-/lib/libcrypto.so.0.9.6b with symlinks /lib/libssl.so.2 and
-/lib/libcrypto.so.2 respectively).
-
-Please note that we have been advised by Red Hat attempting to recompile the
-openssl rpm with all the cryptography enabled will not work. All other
-packages depend on the original Red Hat supplied openssl package. It is also
-worth noting that due to the way Red Hat supplies its packages, updates to
-openssl on each distribution never change the package version, only the
-build number. For example, on Red Hat 7.1, the latest openssl package has
-version number 0.9.6 and build number 9 even though it contains all the
-relevant updates in packages up to and including 0.9.6b.
-
-A possible way around this is to persuade Red Hat to produce a non-US
-version of Red Hat Linux.
-
-FYI: Patent numbers and expiry dates of US patents:
-MDC-2: 4,908,861 13/03/2007
-IDEA:  5,214,703 25/05/2010
-RC5:   5,724,428 03/03/2015
-
-
-* Why does the OpenSSL compilation fail on MacOS X?
-
-If the failure happens when trying to build the "openssl" binary, with
-a large number of undefined symbols, it's very probable that you have
-OpenSSL 0.9.6b delivered with the operating system (you can find out by
-running '/usr/bin/openssl version') and that you were trying to build
-OpenSSL 0.9.7 or newer.  The problem is that the loader ('ld') in
-MacOS X has a misfeature that's quite difficult to go around.
-Look in the file PROBLEMS for a more detailed explanation and for possible
-solutions.
-
-
-* Why does the OpenSSL test suite fail on MacOS X?
-
-If the failure happens when running 'make test' and the RC4 test fails,
-it's very probable that you have OpenSSL 0.9.6b delivered with the
-operating system (you can find out by running '/usr/bin/openssl version')
-and that you were trying to build OpenSSL 0.9.6d.  The problem is that
-the loader ('ld') in MacOS X has a misfeature that's quite difficult to
-go around and has linked the programs "openssl" and the test programs
-with /usr/lib/libcrypto.dylib and /usr/lib/libssl.dylib instead of the
-libraries you just built.
-Look in the file PROBLEMS for a more detailed explanation and for possible
-solutions.
-
-* Why does the OpenSSL test suite fail in BN_sqr test [on a 64-bit platform]?
-
-Failure in BN_sqr test is most likely caused by a failure to configure the
-toolkit for current platform or lack of support for the platform in question.
-Run './config -t' and './apps/openssl version -p'. Do these platform
-identifiers match? If they don't, then you most likely failed to run
-./config and you're hereby advised to do so before filing a bug report.
-If ./config itself fails to run, then it's most likely problem with your
-local environment and you should turn to your system administrator (or
-similar). If identifiers match (and/or no alternative identifier is
-suggested by ./config script), then the platform is unsupported. There might
-or might not be a workaround. Most notably on SPARC64 platforms with GNU
-C compiler you should be able to produce a working build by running
-'./config -m32'. I understand that -m32 might not be what you want/need,
-but the build should be operational. For further details turn to
-<openssl-dev@openssl.org>.
-
-* Why does OpenBSD-i386 build fail on des-586.s with "Unimplemented segment type"?
-
-As of 0.9.7 assembler routines were overhauled for position independence
-of the machine code, which is essential for shared library support. For
-some reason OpenBSD is equipped with an out-of-date GNU assembler which
-finds the new code offensive. To work around the problem, configure with
-no-asm (and sacrifice a great deal of performance) or patch your assembler
-according to <URL: http://www.openssl.org/~appro/gas-1.92.3.OpenBSD.patch>.
-For your convenience a pre-compiled replacement binary is provided at
-<URL: http://www.openssl.org/~appro/gas-1.92.3.static.aout.bin>.
-Reportedly elder *BSD a.out platforms also suffer from this problem and
-remedy should be same. Provided binary is statically linked and should be
-working across wider range of *BSD branches, not just OpenBSD.
-
-* Why does the OpenSSL test suite fail in sha512t on x86 CPU?
-
-If the test program in question fails withs SIGILL, Illegal Instruction
-exception, then you more than likely to run SSE2-capable CPU, such as
-Intel P4, under control of kernel which does not support SSE2
-instruction extentions. See accompanying INSTALL file and
-OPENSSL_ia32cap(3) documentation page for further information.
-
-* Why does compiler fail to compile sha512.c?
-
-OpenSSL SHA-512 implementation depends on compiler support for 64-bit
-integer type. Few elder compilers [ULTRIX cc, SCO compiler to mention a
-couple] lack support for this and therefore are incapable of compiling
-the module in question. The recommendation is to disable SHA-512 by
-adding no-sha512 to ./config [or ./Configure] command line. Another
-possible alternative might be to switch to GCC.
-
-* Test suite still fails, what to do?
-
-Another common reason for failure to complete some particular test is
-simply bad code generated by a buggy component in toolchain or deficiency
-in run-time environment. There are few cases documented in PROBLEMS file,
-consult it for possible workaround before you beat the drum. Even if you
-don't find solution or even mention there, do reserve for possibility of
-a compiler bug. Compiler bugs might appear in rather bizarre ways, they
-never make sense, and tend to emerge when you least expect them. In order
-to identify one, drop optimization level, e.g. by editing CFLAG line in
-top-level Makefile, recompile and re-run the test.
-
-* I think I've found a bug, what should I do?
-
-If you are a new user then it is quite likely you haven't found a bug and
-something is happening you aren't familiar with. Check this FAQ, the associated
-documentation and the mailing lists for similar queries. If you are still
-unsure whether it is a bug or not submit a query to the openssl-users mailing
-list.
-
-
-* I'm SURE I've found a bug, how do I report it?
-
-Bug reports with no security implications should be sent to the request
-tracker. This can be done by mailing the report to <rt@openssl.org> (or its
-alias <openssl-bugs@openssl.org>), please note that messages sent to the
-request tracker also appear in the public openssl-dev mailing list.
-
-The report should be in plain text. Any patches should be sent as
-plain text attachments because some mailers corrupt patches sent inline.
-If your issue affects multiple versions of OpenSSL check any patches apply
-cleanly and, if possible include patches to each affected version.
-
-The report should be given a meaningful subject line briefly summarising the
-issue. Just "bug in OpenSSL" or "bug in OpenSSL 0.9.8n" is not very helpful.
-
-By sending reports to the request tracker the bug can then be given a priority
-and assigned to the appropriate maintainer. The history of discussions can be
-accessed and if the issue has been addressed or a reason why not. If patches
-are only sent to openssl-dev they can be mislaid if a team member has to
-wade through months of old messages to review the discussion.
-
-See also <URL: http://www.openssl.org/support/rt.html>
-
-
-* I've found a security issue, how do I report it?
-
-If you think your bug has security implications then please send it to
-openssl-security@openssl.org if you don't get a prompt reply at least 
-acknowledging receipt then resend or mail it directly to one of the
-more active team members (e.g. Steve).
-
-Note that bugs only present in the openssl utility are not in general
-considered to be security issues. 
-
-[PROG] ========================================================================
-
-* Is OpenSSL thread-safe?
-
-Yes (with limitations: an SSL connection may not concurrently be used
-by multiple threads).  On Windows and many Unix systems, OpenSSL
-automatically uses the multi-threaded versions of the standard
-libraries.  If your platform is not one of these, consult the INSTALL
-file.
-
-Multi-threaded applications must provide two callback functions to
-OpenSSL by calling CRYPTO_set_locking_callback() and
-CRYPTO_set_id_callback(), for all versions of OpenSSL up to and
-including 0.9.8[abc...]. As of version 1.0.0, CRYPTO_set_id_callback()
-and associated APIs are deprecated by CRYPTO_THREADID_set_callback()
-and friends. This is described in the threads(3) manpage.
-
-* I've compiled a program under Windows and it crashes: why?
-
-This is usually because you've missed the comment in INSTALL.W32.
-Your application must link against the same version of the Win32
-C-Runtime against which your openssl libraries were linked.  The
-default version for OpenSSL is /MD - "Multithreaded DLL".
-
-If you are using Microsoft Visual C++'s IDE (Visual Studio), in
-many cases, your new project most likely defaulted to "Debug
-Singlethreaded" - /ML.  This is NOT interchangeable with /MD and your
-program will crash, typically on the first BIO related read or write
-operation.
-
-For each of the six possible link stage configurations within Win32,
-your application must link  against the same by which OpenSSL was
-built.  If you are using MS Visual C++ (Studio) this can be changed
-by:
-
- 1. Select Settings... from the Project Menu.
- 2. Select the C/C++ Tab.
- 3. Select "Code Generation from the "Category" drop down list box
- 4. Select the Appropriate library (see table below) from the "Use
-    run-time library" drop down list box.  Perform this step for both
-    your debug and release versions of your application (look at the
-    top left of the settings panel to change between the two)
-
-    Single Threaded           /ML        -  MS VC++ often defaults to
-                                            this for the release
-                                            version of a new project.
-    Debug Single Threaded     /MLd       -  MS VC++ often defaults to
-                                            this for the debug version
-                                            of a new project.
-    Multithreaded             /MT
-    Debug Multithreaded       /MTd
-    Multithreaded DLL         /MD        -  OpenSSL defaults to this.
-    Debug Multithreaded DLL   /MDd
-
-Note that debug and release libraries are NOT interchangeable.  If you
-built OpenSSL with /MD your application must use /MD and cannot use /MDd.
-
-As per 0.9.8 the above limitation is eliminated for .DLLs. OpenSSL
-.DLLs compiled with some specific run-time option [we insist on the
-default /MD] can be deployed with application compiled with different
-option or even different compiler. But there is a catch! Instead of
-re-compiling OpenSSL toolkit, as you would have to with prior versions,
-you have to compile small C snippet with compiler and/or options of
-your choice. The snippet gets installed as
-<install-root>/include/openssl/applink.c and should be either added to
-your application project or simply #include-d in one [and only one]
-of your application source files. Failure to link this shim module
-into your application manifests itself as fatal "no OPENSSL_Applink"
-run-time error. An explicit reminder is due that in this situation
-[mixing compiler options] it is as important to add CRYPTO_malloc_init
-prior first call to OpenSSL.
-
-* How do I read or write a DER encoded buffer using the ASN1 functions?
-
-You have two options. You can either use a memory BIO in conjunction
-with the i2d_*_bio() or d2i_*_bio() functions or you can use the
-i2d_*(), d2i_*() functions directly. Since these are often the
-cause of grief here are some code fragments using PKCS7 as an example:
-
- unsigned char *buf, *p;
- int len;
-
- len = i2d_PKCS7(p7, NULL);
- buf = OPENSSL_malloc(len); /* or Malloc, error checking omitted */
- p = buf;
- i2d_PKCS7(p7, &p);
-
-At this point buf contains the len bytes of the DER encoding of
-p7.
-
-The opposite assumes we already have len bytes in buf:
-
- unsigned char *p;
- p = buf;
- p7 = d2i_PKCS7(NULL, &p, len);
-
-At this point p7 contains a valid PKCS7 structure of NULL if an error
-occurred. If an error occurred ERR_print_errors(bio) should give more
-information.
-
-The reason for the temporary variable 'p' is that the ASN1 functions
-increment the passed pointer so it is ready to read or write the next
-structure. This is often a cause of problems: without the temporary
-variable the buffer pointer is changed to point just after the data
-that has been read or written. This may well be uninitialized data
-and attempts to free the buffer will have unpredictable results
-because it no longer points to the same address.
-
-
-* OpenSSL uses DER but I need BER format: does OpenSSL support BER?
-
-The short answer is yes, because DER is a special case of BER and OpenSSL
-ASN1 decoders can process BER.
-
-The longer answer is that ASN1 structures can be encoded in a number of
-different ways. One set of ways is the Basic Encoding Rules (BER) with various
-permissible encodings. A restriction of BER is the Distinguished Encoding
-Rules (DER): these uniquely specify how a given structure is encoded.
-
-Therefore, because DER is a special case of BER, DER is an acceptable encoding
-for BER.
-
-
-* I've tried using <M_some_evil_pkcs12_macro> and I get errors why?
-
-This usually happens when you try compiling something using the PKCS#12
-macros with a C++ compiler. There is hardly ever any need to use the
-PKCS#12 macros in a program, it is much easier to parse and create
-PKCS#12 files using the PKCS12_parse() and PKCS12_create() functions
-documented in doc/openssl.txt and with examples in demos/pkcs12. The
-'pkcs12' application has to use the macros because it prints out 
-debugging information.
-
-
-* I've called <some function> and it fails, why?
-
-Before submitting a report or asking in one of the mailing lists, you
-should try to determine the cause. In particular, you should call
-ERR_print_errors() or ERR_print_errors_fp() after the failed call
-and see if the message helps. Note that the problem may occur earlier
-than you think -- you should check for errors after every call where
-it is possible, otherwise the actual problem may be hidden because
-some OpenSSL functions clear the error state.
-
-
-* I just get a load of numbers for the error output, what do they mean?
-
-The actual format is described in the ERR_print_errors() manual page.
-You should call the function ERR_load_crypto_strings() before hand and
-the message will be output in text form. If you can't do this (for example
-it is a pre-compiled binary) you can use the errstr utility on the error
-code itself (the hex digits after the second colon).
-
-
-* Why do I get errors about unknown algorithms?
-
-The cause is forgetting to load OpenSSL's table of algorithms with
-OpenSSL_add_all_algorithms(). See the manual page for more information. This
-can cause several problems such as being unable to read in an encrypted
-PEM file, unable to decrypt a PKCS#12 file or signature failure when
-verifying certificates.
-
-* Why can't the OpenSSH configure script detect OpenSSL?
-
-Several reasons for problems with the automatic detection exist.
-OpenSSH requires at least version 0.9.5a of the OpenSSL libraries.
-Sometimes the distribution has installed an older version in the system
-locations that is detected instead of a new one installed. The OpenSSL
-library might have been compiled for another CPU or another mode (32/64 bits).
-Permissions might be wrong.
-
-The general answer is to check the config.log file generated when running
-the OpenSSH configure script. It should contain the detailed information
-on why the OpenSSL library was not detected or considered incompatible.
-
-
-* Can I use OpenSSL's SSL library with non-blocking I/O?
-
-Yes; make sure to read the SSL_get_error(3) manual page!
-
-A pitfall to avoid: Don't assume that SSL_read() will just read from
-the underlying transport or that SSL_write() will just write to it --
-it is also possible that SSL_write() cannot do any useful work until
-there is data to read, or that SSL_read() cannot do anything until it
-is possible to send data.  One reason for this is that the peer may
-request a new TLS/SSL handshake at any time during the protocol,
-requiring a bi-directional message exchange; both SSL_read() and
-SSL_write() will try to continue any pending handshake.
-
-
-* Why doesn't my server application receive a client certificate?
-
-Due to the TLS protocol definition, a client will only send a certificate,
-if explicitly asked by the server. Use the SSL_VERIFY_PEER flag of the
-SSL_CTX_set_verify() function to enable the use of client certificates.
-
-
-* Why does compilation fail due to an undefined symbol NID_uniqueIdentifier?
-
-For OpenSSL 0.9.7 the OID table was extended and corrected. In earlier
-versions, uniqueIdentifier was incorrectly used for X.509 certificates.
-The correct name according to RFC2256 (LDAP) is x500UniqueIdentifier.
-Change your code to use the new name when compiling against OpenSSL 0.9.7.
-
-
-* I think I've detected a memory leak, is this a bug?
-
-In most cases the cause of an apparent memory leak is an OpenSSL internal table
-that is allocated when an application starts up. Since such tables do not grow
-in size over time they are harmless.
-
-These internal tables can be freed up when an application closes using various
-functions.  Currently these include following:
-
-Thread-local cleanup functions:
-
-  ERR_remove_state()
-
-Application-global cleanup functions that are aware of usage (and therefore
-thread-safe):
-
-  ENGINE_cleanup() and CONF_modules_unload()
-
-"Brutal" (thread-unsafe) Application-global cleanup functions:
-
-  ERR_free_strings(), EVP_cleanup() and CRYPTO_cleanup_all_ex_data().
-
-
-* Why does Valgrind complain about the use of uninitialized data?
-
-When OpenSSL's PRNG routines are called to generate random numbers the supplied
-buffer contents are mixed into the entropy pool: so it technically does not
-matter whether the buffer is initialized at this point or not.  Valgrind (and
-other test tools) will complain about this. When using Valgrind, make sure the
-OpenSSL library has been compiled with the PURIFY macro defined (-DPURIFY)
-to get rid of these warnings.
-
-
-* Why doesn't a memory BIO work when a file does?
-
-This can occur in several cases for example reading an S/MIME email message.
-The reason is that a memory BIO can do one of two things when all the data
-has been read from it.
-
-The default behaviour is to indicate that no more data is available and that
-the call should be retried, this is to allow the application to fill up the BIO
-again if necessary.
-
-Alternatively it can indicate that no more data is available and that EOF has
-been reached.
-
-If a memory BIO is to behave in the same way as a file this second behaviour
-is needed. This must be done by calling:
-
-   BIO_set_mem_eof_return(bio, 0);
-
-See the manual pages for more details.
-
-
-* Where are the declarations and implementations of d2i_X509() etc?
-
-These are defined and implemented by macros of the form:
-
-
- DECLARE_ASN1_FUNCTIONS(X509) and IMPLEMENT_ASN1_FUNCTIONS(X509)
-
-The implementation passes an ASN1 "template" defining the structure into an
-ASN1 interpreter using generalised functions such as ASN1_item_d2i().
-
-
-===============================================================================
+The FAQ is now maintained on the web:
+        https://www.openssl.org/docs/faq.html
diff --git a/src/third_party/openssl/openssl/INSTALL b/src/third_party/openssl/openssl/INSTALL
index 1325079..679b30d 100644
--- a/src/third_party/openssl/openssl/INSTALL
+++ b/src/third_party/openssl/openssl/INSTALL
@@ -164,10 +164,10 @@
      standard headers).  If it is a problem with OpenSSL itself, please
      report the problem to <openssl-bugs@openssl.org> (note that your
      message will be recorded in the request tracker publicly readable
-     via http://www.openssl.org/support/rt.html and will be forwarded to a
-     public mailing list). Include the output of "make report" in your message.
-     Please check out the request tracker. Maybe the bug was already
-     reported or has already been fixed.
+     at https://www.openssl.org/community/index.html#bugs and will be
+     forwarded to a public mailing list). Include the output of "make
+     report" in your message.  Please check out the request tracker. Maybe
+     the bug was already reported or has already been fixed.
 
      [If you encounter assembler error messages, try the "no-asm"
      configuration option as an immediate fix.]
diff --git a/src/third_party/openssl/openssl/LICENSE b/src/third_party/openssl/openssl/LICENSE
index e47d101..fb03713 100644
--- a/src/third_party/openssl/openssl/LICENSE
+++ b/src/third_party/openssl/openssl/LICENSE
@@ -12,7 +12,7 @@
   ---------------
 
 /* ====================================================================
- * Copyright (c) 1998-2011 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2016 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
diff --git a/src/third_party/openssl/openssl/Makefile.org b/src/third_party/openssl/openssl/Makefile.org
index 55a3700..bc1c3be 100644
--- a/src/third_party/openssl/openssl/Makefile.org
+++ b/src/third_party/openssl/openssl/Makefile.org
@@ -179,8 +179,7 @@
 GENERAL=        Makefile
 BASENAME=       openssl
 NAME=           $(BASENAME)-$(VERSION)
-TARFILE=        $(NAME).tar
-WTARFILE=       $(NAME)-win.tar
+TARFILE=        ../$(NAME).tar
 EXHEADER=       e_os2.h
 HEADER=         e_os.h
 
@@ -499,35 +498,35 @@
 # would occur. Therefore the list of files is temporarily stored into a file
 # and read directly, requiring GNU-Tar. Call "make TAR=gtar dist" if the normal
 # tar does not support the --files-from option.
-tar:
+TAR_COMMAND=$(TAR) $(TARFLAGS) --files-from $(TARFILE).list \
+	                       --owner 0 --group 0 \
+			       --transform 's|^|$(NAME)/|' \
+			       -cvf -
+
+$(TARFILE).list:
+	find * \! -name STATUS \! -name TABLE \! -name '*.o' \! -name '*.a' \
+	       \! -name '*.so' \! -name '*.so.*'  \! -name 'openssl' \
+	       \( \! -name '*test' -o -name bctest -o -name pod2mantest \) \
+	       \! -name '.#*' \! -name '*~' \! -type l \
+	    | sort > $(TARFILE).list
+
+tar: $(TARFILE).list
 	find . -type d -print | xargs chmod 755
 	find . -type f -print | xargs chmod a+r
 	find . -type f -perm -0100 -print | xargs chmod a+x
-	find * \! -path CVS/\* \! -path \*/CVS/\* \! -name CVS \! -name .cvsignore \! -name STATUS \! -name TABLE | sort > ../$(TARFILE).list; \
-	$(TAR) $(TARFLAGS) --files-from ../$(TARFILE).list -cvf - | \
-	tardy --user_number=0  --user_name=openssl \
-	      --group_number=0 --group_name=openssl \
-	      --prefix=openssl-$(VERSION) - |\
-	gzip --best >../$(TARFILE).gz; \
-	rm -f ../$(TARFILE).list; \
-	ls -l ../$(TARFILE).gz
+	$(TAR_COMMAND) | gzip --best > $(TARFILE).gz
+	rm -f $(TARFILE).list
+	ls -l $(TARFILE).gz
 
-tar-snap:
-	@$(TAR) $(TARFLAGS) -cvf - \
-		`find * \! -path CVS/\* \! -path \*/CVS/\* \! -name CVS \! -name .cvsignore \! -name STATUS \! -name TABLE \! -name '*.o' \! -name '*.a' \! -name '*.so' \! -name '*.so.*'  \! -name 'openssl' \! -name '*test' \! -name '.#*' \! -name '*~' | sort` |\
-	tardy --user_number=0  --user_name=openssl \
-	      --group_number=0 --group_name=openssl \
-	      --prefix=openssl-$(VERSION) - > ../$(TARFILE);\
-	ls -l ../$(TARFILE)
+tar-snap: $(TARFILE).list
+	$(TAR_COMMAND) > $(TARFILE)
+	rm -f $(TARFILE).list
+	ls -l $(TARFILE)
 
 dist:   
 	$(PERL) Configure dist
-	@$(MAKE) dist_pem_h
 	@$(MAKE) SDIRS='$(SDIRS)' clean
-	@$(MAKE) TAR='$(TAR)' TARFLAGS='$(TARFLAGS)' tar
-
-dist_pem_h:
-	(cd crypto/pem; $(MAKE) -e $(BUILDENV) pem.h; $(MAKE) clean)
+	@$(MAKE) TAR='$(TAR)' TARFLAGS='$(TARFLAGS)' $(DISTTARVARS) tar
 
 install: all install_docs install_sw
 
diff --git a/src/third_party/openssl/openssl/NEWS b/src/third_party/openssl/openssl/NEWS
index 5e76d3f..c8193d5 100644
--- a/src/third_party/openssl/openssl/NEWS
+++ b/src/third_party/openssl/openssl/NEWS
@@ -5,9 +5,23 @@
   This file gives a brief overview of the major changes between each OpenSSL
   release. For more details please read the CHANGES file.
 
+  Major changes between OpenSSL 1.0.1q and OpenSSL 1.0.1r [28 Jan 2016]
+
+      o Protection for DH small subgroup attacks
+      o SSLv2 doesn't block disabled ciphers (CVE-2015-3197)
+
+  Major changes between OpenSSL 1.0.1p and OpenSSL 1.0.1q [3 Dec 2015]
+
+      o Certificate verify crash with missing PSS parameter (CVE-2015-3194)
+      o X509_ATTRIBUTE memory leak (CVE-2015-3195)
+      o Rewrite EVP_DecodeUpdate (base64 decoding) to fix several bugs
+      o In DSA_generate_parameters_ex, if the provided seed is too short,
+        return an error
+
   Major changes between OpenSSL 1.0.1o and OpenSSL 1.0.1p [9 Jul 2015]
 
       o Alternate chains certificate forgery (CVE-2015-1793)
+      o Race condition handling PSK identify hint (CVE-2015-3196)
 
   Major changes between OpenSSL 1.0.1n and OpenSSL 1.0.1o [12 Jun 2015]
 
diff --git a/src/third_party/openssl/openssl/README b/src/third_party/openssl/openssl/README
index bf03f30..5e914f8 100644
--- a/src/third_party/openssl/openssl/README
+++ b/src/third_party/openssl/openssl/README
@@ -1,7 +1,7 @@
 
- OpenSSL 1.0.1p 9 Jul 2015
+ OpenSSL 1.0.1r 28 Jan 2016
 
- Copyright (c) 1998-2011 The OpenSSL Project
+ Copyright (c) 1998-2015 The OpenSSL Project
  Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson
  All rights reserved.
 
@@ -10,17 +10,17 @@
 
  The OpenSSL Project is a collaborative effort to develop a robust,
  commercial-grade, fully featured, and Open Source toolkit implementing the
- Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1)
- protocols as well as a full-strength general purpose cryptography library.
- The project is managed by a worldwide community of volunteers that use the
- Internet to communicate, plan, and develop the OpenSSL toolkit and its
- related documentation.
+ Secure Sockets Layer (SSLv3) and Transport Layer Security (TLS) protocols as
+ well as a full-strength general purpose cryptograpic library. The project is
+ managed by a worldwide community of volunteers that use the Internet to
+ communicate, plan, and develop the OpenSSL toolkit and its related
+ documentation.
 
- OpenSSL is based on the excellent SSLeay library developed from Eric A. Young
+ OpenSSL is descended from the SSLeay library developed by Eric A. Young
  and Tim J. Hudson.  The OpenSSL toolkit is licensed under a dual-license (the
- OpenSSL license plus the SSLeay license) situation, which basically means
- that you are free to get and use it for commercial and non-commercial
- purposes as long as you fulfill the conditions of both licenses.
+ OpenSSL license plus the SSLeay license), which means that you are free to
+ get and use it for commercial and non-commercial purposes as long as you
+ fulfill the conditions of both licenses.
 
  OVERVIEW
  --------
@@ -28,116 +28,39 @@
  The OpenSSL toolkit includes:
 
  libssl.a:
-     Implementation of SSLv2, SSLv3, TLSv1 and the required code to support
-     both SSLv2, SSLv3 and TLSv1 in the one server and client.
+     Provides the client and server-side implementations for SSLv3 and TLS.
 
  libcrypto.a:
-     General encryption and X.509 v1/v3 stuff needed by SSL/TLS but not
-     actually logically part of it. It includes routines for the following:
-
-     Ciphers
-        libdes - EAY's libdes DES encryption package which was floating
-                 around the net for a few years, and was then relicensed by
-                 him as part of SSLeay.  It includes 15 'modes/variations'
-                 of DES (1, 2 and 3 key versions of ecb, cbc, cfb and ofb;
-                 pcbc and a more general form of cfb and ofb) including desx
-                 in cbc mode, a fast crypt(3), and routines to read
-                 passwords from the keyboard.
-        RC4 encryption,
-        RC2 encryption      - 4 different modes, ecb, cbc, cfb and ofb.
-        Blowfish encryption - 4 different modes, ecb, cbc, cfb and ofb.
-        IDEA encryption     - 4 different modes, ecb, cbc, cfb and ofb.
-
-     Digests
-        MD5 and MD2 message digest algorithms, fast implementations,
-        SHA (SHA-0) and SHA-1 message digest algorithms,
-        MDC2 message digest. A DES based hash that is popular on smart cards.
-
-     Public Key
-        RSA encryption/decryption/generation.
-            There is no limit on the number of bits.
-        DSA encryption/decryption/generation.
-            There is no limit on the number of bits.
-        Diffie-Hellman key-exchange/key generation.
-            There is no limit on the number of bits.
-
-     X.509v3 certificates
-        X509 encoding/decoding into/from binary ASN1 and a PEM
-             based ASCII-binary encoding which supports encryption with a
-             private key.  Program to generate RSA and DSA certificate
-             requests and to generate RSA and DSA certificates.
-
-     Systems
-        The normal digital envelope routines and base64 encoding.  Higher
-        level access to ciphers and digests by name.  New ciphers can be
-        loaded at run time.  The BIO io system which is a simple non-blocking
-        IO abstraction.  Current methods supported are file descriptors,
-        sockets, socket accept, socket connect, memory buffer, buffering, SSL
-        client/server, file pointer, encryption, digest, non-blocking testing
-        and null.
-
-     Data structures
-        A dynamically growing hashing system
-        A simple stack.
-        A Configuration loader that uses a format similar to MS .ini files.
+     Provides general cryptographic and X.509 support needed by SSL/TLS but
+     not logically part of it.
 
  openssl:
      A command line tool that can be used for:
-        Creation of RSA, DH and DSA key parameters
+        Creation of key parameters
         Creation of X.509 certificates, CSRs and CRLs
-        Calculation of Message Digests
-        Encryption and Decryption with Ciphers
-        SSL/TLS Client and Server Tests
+        Calculation of message digests
+        Encryption and decryption
+        SSL/TLS client and server tests
         Handling of S/MIME signed or encrypted mail
-
-
- PATENTS
- -------
-
- Various companies hold various patents for various algorithms in various
- locations around the world. _YOU_ are responsible for ensuring that your use
- of any algorithms is legal by checking if there are any patents in your
- country.  The file contains some of the patents that we know about or are
- rumored to exist. This is not a definitive list.
-
- RSA Security holds software patents on the RC5 algorithm.  If you
- intend to use this cipher, you must contact RSA Security for
- licensing conditions. Their web page is http://www.rsasecurity.com/.
-
- RC4 is a trademark of RSA Security, so use of this label should perhaps
- only be used with RSA Security's permission.
-
- The IDEA algorithm is patented by Ascom in Austria, France, Germany, Italy,
- Japan, the Netherlands, Spain, Sweden, Switzerland, UK and the USA.  They
- should be contacted if that algorithm is to be used; their web page is
- http://www.ascom.ch/.
-
- NTT and Mitsubishi have patents and pending patents on the Camellia
- algorithm, but allow use at no charge without requiring an explicit
- licensing agreement: http://info.isl.ntt.co.jp/crypt/eng/info/chiteki.html
+        And more...
 
  INSTALLATION
  ------------
 
- To install this package under a Unix derivative, read the INSTALL file.  For
- a Win32 platform, read the INSTALL.W32 file.  For OpenVMS systems, read
- INSTALL.VMS.
-
- Read the documentation in the doc/ directory.  It is quite rough, but it
- lists the functions; you will probably have to look at the code to work out
- how to use them. Look at the example programs.
-
- PROBLEMS
- --------
-
- For some platforms, there are some known problems that may affect the user
- or application author.  We try to collect those in doc/PROBLEMS, with current
- thoughts on how they should be solved in a future of OpenSSL.
+ See the appropriate file:
+        INSTALL         Linux, Unix, etc.
+        INSTALL.DJGPP   DOS platform with DJGPP
+        INSTALL.NW      Netware
+        INSTALL.OS2     OS/2
+        INSTALL.VMS     VMS
+        INSTALL.W32     Windows (32bit)
+        INSTALL.W64     Windows (64bit)
+        INSTALL.WCE     Windows CE
 
  SUPPORT
  -------
 
- See the OpenSSL website www.openssl.org for details of how to obtain
+ See the OpenSSL website www.openssl.org for details on how to obtain
  commercial technical support.
 
  If you have any problems with OpenSSL then please take the following steps
@@ -161,58 +84,36 @@
     - Problem Description (steps that will reproduce the problem, if known)
     - Stack Traceback (if the application dumps core)
 
- Report the bug to the OpenSSL project via the Request Tracker
- (http://www.openssl.org/support/rt.html) by mail to:
+ Email the report to:
 
-    openssl-bugs@openssl.org
+    rt@openssl.org
 
- Note that the request tracker should NOT be used for general assistance
- or support queries. Just because something doesn't work the way you expect
- does not mean it is necessarily a bug in OpenSSL.
+ In order to avoid spam, this is a moderated mailing list, and it might
+ take a day for the ticket to show up.  (We also scan posts to make sure
+ that security disclosures aren't publically posted by mistake.) Mail
+ to this address is recorded in the public RT (request tracker) database
+ (see https://www.openssl.org/community/index.html#bugs for details) and
+ also forwarded the public openssl-dev mailing list.  Confidential mail
+ may be sent to openssl-security@openssl.org (PGP key available from the
+ key servers).
 
- Note that mail to openssl-bugs@openssl.org is recorded in the publicly
- readable request tracker database and is forwarded to a public
- mailing list. Confidential mail may be sent to openssl-security@openssl.org
- (PGP key available from the key servers).
+ Please do NOT use this for general assistance or support queries.
+ Just because something doesn't work the way you expect does not mean it
+ is necessarily a bug in OpenSSL.
+
+ You can also make GitHub pull requests. If you do this, please also send
+ mail to rt@openssl.org with a link to the PR so that we can more easily
+ keep track of it.
 
  HOW TO CONTRIBUTE TO OpenSSL
  ----------------------------
 
- Development is coordinated on the openssl-dev mailing list (see
- http://www.openssl.org for information on subscribing). If you
- would like to submit a patch, send it to openssl-bugs@openssl.org with
- the string "[PATCH]" in the subject. Please be sure to include a
- textual explanation of what your patch does.
+ See CONTRIBUTING
 
- If you are unsure as to whether a feature will be useful for the general
- OpenSSL community please discuss it on the openssl-dev mailing list first.
- Someone may be already working on the same thing or there may be a good
- reason as to why that feature isn't implemented.
+ LEGALITIES
+ ----------
 
- Patches should be as up to date as possible, preferably relative to the
- current Git or the last snapshot. They should follow the coding style of
- OpenSSL and compile without warnings. Some of the core team developer targets
- can be used for testing purposes, (debug-steve64, debug-geoff etc). OpenSSL
- compiles on many varied platforms: try to ensure you only use portable
- features.
-
- Note: For legal reasons, contributions from the US can be accepted only
- if a TSU notification and a copy of the patch are sent to crypt@bis.doc.gov
- (formerly BXA) with a copy to the ENC Encryption Request Coordinator;
- please take some time to look at
-    http://www.bis.doc.gov/Encryption/PubAvailEncSourceCodeNofify.html [sic]
- and
-    http://w3.access.gpo.gov/bis/ear/pdf/740.pdf (EAR Section 740.13(e))
- for the details. If "your encryption source code is too large to serve as
- an email attachment", they are glad to receive it by fax instead; hope you
- have a cheap long-distance plan.
-
- Our preferred format for changes is "diff -u" output. You might
- generate it like this:
-
- # cd openssl-work
- # [your changes]
- # ./Configure dist; make clean
- # cd ..
- # diff -ur openssl-orig openssl-work > mydiffs.patch
-
+ A number of nations, in particular the U.S., restrict the use or export
+ of cryptography. If you are potentially subject to such restrictions
+ you should seek competent professional legal advice before attempting to
+ develop or distribute cryptographic code.
diff --git a/src/third_party/openssl/openssl/apps/Makefile b/src/third_party/openssl/openssl/apps/Makefile
index cafe554..8c3297e 100644
--- a/src/third_party/openssl/openssl/apps/Makefile
+++ b/src/third_party/openssl/openssl/apps/Makefile
@@ -135,7 +135,7 @@
 depend: local_depend
 	@if [ -z "$(THIS)" ]; then $(MAKE) -f $(TOP)/Makefile reflect THIS=$@; fi
 local_depend:
-	@[ -z "$(THIS)" ] || $(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(SRC); \
+	@[ -z "$(THIS)" ] || $(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(SRC)
 
 dclean:
 	$(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new
diff --git a/src/third_party/openssl/openssl/apps/apps.c b/src/third_party/openssl/openssl/apps/apps.c
index 6801238..8ab4833 100644
--- a/src/third_party/openssl/openssl/apps/apps.c
+++ b/src/third_party/openssl/openssl/apps/apps.c
@@ -119,9 +119,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#if !defined(OPENSSL_SYSNAME_WIN32) && !defined(NETWARE_CLIB)
-# include <strings.h>
-#endif
 #include <sys/types.h>
 #include <ctype.h>
 #include <errno.h>
@@ -1247,7 +1244,11 @@
         {"ca_default", XN_FLAG_MULTILINE, 0xffffffffL},
         {NULL, 0, 0}
     };
-    return set_multi_opts(flags, arg, ex_tbl);
+    if (set_multi_opts(flags, arg, ex_tbl) == 0)
+        return 0;
+    if ((*flags & XN_FLAG_SEP_MASK) == 0)
+        *flags |= XN_FLAG_SEP_CPLUS_SPC;
+    return 1;
 }
 
 int set_ext_copy(int *copy_type, const char *arg)
diff --git a/src/third_party/openssl/openssl/apps/asn1pars.c b/src/third_party/openssl/openssl/apps/asn1pars.c
index 11b0787..0a6b990 100644
--- a/src/third_party/openssl/openssl/apps/asn1pars.c
+++ b/src/third_party/openssl/openssl/apps/asn1pars.c
@@ -313,9 +313,9 @@
             }
             typ = ASN1_TYPE_get(at);
             if ((typ == V_ASN1_OBJECT)
+                || (typ == V_ASN1_BOOLEAN)
                 || (typ == V_ASN1_NULL)) {
-                BIO_printf(bio_err, "Can't parse %s type\n",
-                           typ == V_ASN1_NULL ? "NULL" : "OBJECT");
+                BIO_printf(bio_err, "Can't parse %s type\n", ASN1_tag2str(typ));
                 ERR_print_errors(bio_err);
                 goto end;
             }
diff --git a/src/third_party/openssl/openssl/apps/ca.c b/src/third_party/openssl/openssl/apps/ca.c
index 97ad0c1..4d64eb2 100644
--- a/src/third_party/openssl/openssl/apps/ca.c
+++ b/src/third_party/openssl/openssl/apps/ca.c
@@ -99,25 +99,19 @@
 #undef PROG
 #define PROG ca_main
 
-#define BASE_SECTION    "ca"
-#define CONFIG_FILE "openssl.cnf"
+#define BASE_SECTION            "ca"
+#define CONFIG_FILE             "openssl.cnf"
 
 #define ENV_DEFAULT_CA          "default_ca"
 
-#define STRING_MASK     "string_mask"
+#define STRING_MASK             "string_mask"
 #define UTF8_IN                 "utf8"
 
-#define ENV_DIR                 "dir"
-#define ENV_CERTS               "certs"
-#define ENV_CRL_DIR             "crl_dir"
-#define ENV_CA_DB               "CA_DB"
 #define ENV_NEW_CERTS_DIR       "new_certs_dir"
 #define ENV_CERTIFICATE         "certificate"
 #define ENV_SERIAL              "serial"
 #define ENV_CRLNUMBER           "crlnumber"
-#define ENV_CRL                 "crl"
 #define ENV_PRIVATE_KEY         "private_key"
-#define ENV_RANDFILE            "RANDFILE"
 #define ENV_DEFAULT_DAYS        "default_days"
 #define ENV_DEFAULT_STARTDATE   "default_startdate"
 #define ENV_DEFAULT_ENDDATE     "default_enddate"
@@ -2520,6 +2514,8 @@
     char **rrow, *a_tm_s;
 
     a_tm = ASN1_UTCTIME_new();
+    if (a_tm == NULL)
+        return -1;
 
     /* get actual time and make a string */
     a_tm = X509_gmtime_adj(a_tm, 0);
diff --git a/src/third_party/openssl/openssl/apps/ecparam.c b/src/third_party/openssl/openssl/apps/ecparam.c
index 1f340a9..402fb31 100644
--- a/src/third_party/openssl/openssl/apps/ecparam.c
+++ b/src/third_party/openssl/openssl/apps/ecparam.c
@@ -413,14 +413,13 @@
     }
 
     if (check) {
-        if (group == NULL)
-            BIO_printf(bio_err, "no elliptic curve parameters\n");
         BIO_printf(bio_err, "checking elliptic curve parameters: ");
         if (!EC_GROUP_check(group, NULL)) {
             BIO_printf(bio_err, "failed\n");
             ERR_print_errors(bio_err);
-        } else
-            BIO_printf(bio_err, "ok\n");
+            goto end;
+        }
+        BIO_printf(bio_err, "ok\n");
 
     }
 
diff --git a/src/third_party/openssl/openssl/apps/engine.c b/src/third_party/openssl/openssl/apps/engine.c
index 3d70cac..f54631b 100644
--- a/src/third_party/openssl/openssl/apps/engine.c
+++ b/src/third_party/openssl/openssl/apps/engine.c
@@ -1,4 +1,4 @@
-/* apps/engine.c -*- mode: C; c-file-style: "eay" -*- */
+/* apps/engine.c */
 /*
  * Written by Richard Levitte <richard@levitte.org> for the OpenSSL project
  * 2000.
@@ -99,8 +99,6 @@
 
 static int append_buf(char **buf, const char *s, int *size, int step)
 {
-    int l = strlen(s);
-
     if (*buf == NULL) {
         *size = step;
         *buf = OPENSSL_malloc(*size);
@@ -109,9 +107,6 @@
         **buf = '\0';
     }
 
-    if (**buf != '\0')
-        l += 2;                 /* ", " */
-
     if (strlen(*buf) + strlen(s) >= (unsigned int)*size) {
         *size += step;
         *buf = OPENSSL_realloc(*buf, *size);
diff --git a/src/third_party/openssl/openssl/apps/ocsp.c b/src/third_party/openssl/openssl/apps/ocsp.c
index 572f064..bb420c2 100644
--- a/src/third_party/openssl/openssl/apps/ocsp.c
+++ b/src/third_party/openssl/openssl/apps/ocsp.c
@@ -1003,7 +1003,7 @@
     bs = OCSP_BASICRESP_new();
     thisupd = X509_gmtime_adj(NULL, 0);
     if (ndays != -1)
-        nextupd = X509_gmtime_adj(NULL, nmin * 60 + ndays * 3600 * 24);
+        nextupd = X509_time_adj_ex(NULL, ndays, nmin * 60, NULL);
 
     /* Examine each certificate id in the request */
     for (i = 0; i < id_count; i++) {
@@ -1220,8 +1220,8 @@
         return NULL;
     }
 
-    if (BIO_get_fd(cbio, &fd) <= 0) {
-        BIO_puts(err, "Can't get connection fd\n");
+    if (BIO_get_fd(cbio, &fd) < 0) {
+        BIO_puts(bio_err, "Can't get connection fd\n");
         goto err;
     }
 
diff --git a/src/third_party/openssl/openssl/apps/pkcs12.c b/src/third_party/openssl/openssl/apps/pkcs12.c
index 4ff6449..cbb75b7 100644
--- a/src/third_party/openssl/openssl/apps/pkcs12.c
+++ b/src/third_party/openssl/openssl/apps/pkcs12.c
@@ -79,7 +79,8 @@
 # define CLCERTS         0x8
 # define CACERTS         0x10
 
-int get_cert_chain(X509 *cert, X509_STORE *store, STACK_OF(X509) **chain);
+static int get_cert_chain(X509 *cert, X509_STORE *store,
+                          STACK_OF(X509) **chain);
 int dump_certs_keys_p12(BIO *out, PKCS12 *p12, char *pass, int passlen,
                         int options, char *pempass);
 int dump_certs_pkeys_bags(BIO *out, STACK_OF(PKCS12_SAFEBAG) *bags,
@@ -134,13 +135,6 @@
 
     apps_startup();
 
-# ifdef OPENSSL_FIPS
-    if (FIPS_mode())
-        cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
-    else
-# endif
-        cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC;
-
     enc = EVP_des_ede3_cbc();
     if (bio_err == NULL)
         bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
@@ -148,6 +142,13 @@
     if (!load_config(bio_err, NULL))
         goto end;
 
+# ifdef OPENSSL_FIPS
+    if (FIPS_mode())
+        cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
+    else
+# endif
+        cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC;
+
     args = argv + 1;
 
     while (*args) {
@@ -594,7 +595,7 @@
             vret = get_cert_chain(ucert, store, &chain2);
             X509_STORE_free(store);
 
-            if (!vret) {
+            if (vret == X509_V_OK) {
                 /* Exclude verified certificate */
                 for (i = 1; i < sk_X509_num(chain2); i++)
                     sk_X509_push(certs, sk_X509_value(chain2, i));
@@ -602,7 +603,7 @@
                 X509_free(sk_X509_value(chain2, 0));
                 sk_X509_free(chain2);
             } else {
-                if (vret >= 0)
+                if (vret != X509_V_ERR_UNSPECIFIED)
                     BIO_printf(bio_err, "Error %s getting chain.\n",
                                X509_verify_cert_error_string(vret));
                 else
@@ -906,36 +907,25 @@
 
 /* Given a single certificate return a verified chain or NULL if error */
 
-/* Hope this is OK .... */
-
-int get_cert_chain(X509 *cert, X509_STORE *store, STACK_OF(X509) **chain)
+static int get_cert_chain(X509 *cert, X509_STORE *store,
+                          STACK_OF(X509) **chain)
 {
     X509_STORE_CTX store_ctx;
-    STACK_OF(X509) *chn;
+    STACK_OF(X509) *chn = NULL;
     int i = 0;
 
-    /*
-     * FIXME: Should really check the return status of X509_STORE_CTX_init
-     * for an error, but how that fits into the return value of this function
-     * is less obvious.
-     */
-    X509_STORE_CTX_init(&store_ctx, store, cert, NULL);
-    if (X509_verify_cert(&store_ctx) <= 0) {
-        i = X509_STORE_CTX_get_error(&store_ctx);
-        if (i == 0)
-            /*
-             * avoid returning 0 if X509_verify_cert() did not set an
-             * appropriate error value in the context
-             */
-            i = -1;
-        chn = NULL;
-        goto err;
-    } else
+    if (!X509_STORE_CTX_init(&store_ctx, store, cert, NULL)) {
+        *chain = NULL;
+        return X509_V_ERR_UNSPECIFIED;
+    }
+
+    if (X509_verify_cert(&store_ctx) > 0)
         chn = X509_STORE_CTX_get1_chain(&store_ctx);
- err:
+    else if ((i = X509_STORE_CTX_get_error(&store_ctx)) == 0)
+        i = X509_V_ERR_UNSPECIFIED;
+
     X509_STORE_CTX_cleanup(&store_ctx);
     *chain = chn;
-
     return i;
 }
 
diff --git a/src/third_party/openssl/openssl/apps/s_client.c b/src/third_party/openssl/openssl/apps/s_client.c
index 28737b6..16833ac 100644
--- a/src/third_party/openssl/openssl/apps/s_client.c
+++ b/src/third_party/openssl/openssl/apps/s_client.c
@@ -1884,6 +1884,9 @@
         EVP_PKEY_free(key);
     if (pass)
         OPENSSL_free(pass);
+#ifndef OPENSSL_NO_SRP
+    OPENSSL_free(srp_arg.srppassin);
+#endif
     if (vpm)
         X509_VERIFY_PARAM_free(vpm);
     if (cbuf != NULL) {
diff --git a/src/third_party/openssl/openssl/apps/s_server.c b/src/third_party/openssl/openssl/apps/s_server.c
index b58e5e0..a8aee77 100644
--- a/src/third_party/openssl/openssl/apps/s_server.c
+++ b/src/third_party/openssl/openssl/apps/s_server.c
@@ -2654,6 +2654,21 @@
                 goto err;
             } else {
                 BIO_printf(bio_s_out, "read R BLOCK\n");
+#ifndef OPENSSL_NO_SRP
+                if (BIO_should_io_special(io)
+                    && BIO_get_retry_reason(io) == BIO_RR_SSL_X509_LOOKUP) {
+                    BIO_printf(bio_s_out, "LOOKUP renego during read\n");
+                    srp_callback_parm.user =
+                        SRP_VBASE_get_by_user(srp_callback_parm.vb,
+                                              srp_callback_parm.login);
+                    if (srp_callback_parm.user)
+                        BIO_printf(bio_s_out, "LOOKUP done %s\n",
+                                   srp_callback_parm.user->info);
+                    else
+                        BIO_printf(bio_s_out, "LOOKUP not successful\n");
+                    continue;
+                }
+#endif
 #if defined(OPENSSL_SYS_NETWARE)
                 delay(1000);
 #elif !defined(OPENSSL_SYS_MSDOS) && !defined(__DJGPP__)
diff --git a/src/third_party/openssl/openssl/apps/speed.c b/src/third_party/openssl/openssl/apps/speed.c
index 7d9fd8a..ef72723 100644
--- a/src/third_party/openssl/openssl/apps/speed.c
+++ b/src/third_party/openssl/openssl/apps/speed.c
@@ -1,4 +1,4 @@
-/* apps/speed.c -*- mode:C; c-file-style: "eay" -*- */
+/* apps/speed.c */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/apps/x509.c b/src/third_party/openssl/openssl/apps/x509.c
index 929359b..e5fe610 100644
--- a/src/third_party/openssl/openssl/apps/x509.c
+++ b/src/third_party/openssl/openssl/apps/x509.c
@@ -1170,12 +1170,7 @@
     if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL)
         goto err;
 
-    /* Lets just make it 12:00am GMT, Jan 1 1970 */
-    /* memcpy(x->cert_info->validity->notBefore,"700101120000Z",13); */
-    /* 28 days to be certified */
-
-    if (X509_gmtime_adj(X509_get_notAfter(x), (long)60 * 60 * 24 * days) ==
-        NULL)
+    if (X509_time_adj_ex(X509_get_notAfter(x), days, 0, NULL) == NULL)
         goto err;
 
     if (!X509_set_pubkey(x, pkey))
diff --git a/src/third_party/openssl/openssl/appveyor.yml b/src/third_party/openssl/openssl/appveyor.yml
new file mode 100644
index 0000000..8695359
--- /dev/null
+++ b/src/third_party/openssl/openssl/appveyor.yml
@@ -0,0 +1,60 @@
+platform:
+    - x86
+    - x64
+
+environment:
+    matrix:
+        - VSVER: 9
+        - VSVER: 10
+        - VSVER: 11
+        - VSVER: 12
+        - VSVER: 14
+
+configuration:
+    - plain
+    - shared
+
+matrix:
+    allow_failures:
+        - platform: x64
+          VSVER: 9
+        - platform: x64
+          VSVER: 10
+        - platform: x64
+          VSVER: 11
+
+before_build:
+    - ps: >-
+        If ($env:Platform -Match "x86") {
+            $env:VCVARS_PLATFORM="x86"
+            $env:TARGET="VC-WIN32"
+            $env:DO="do_ms"
+        } Else {
+            $env:VCVARS_PLATFORM="amd64"
+            $env:TARGET="VC-WIN64A"
+            $env:DO="do_win64a"
+        }
+    - ps: >-
+        If ($env:Configuration -Like "*shared*") {
+            $env:MAK="ntdll.mak"
+        } Else {
+            $env:MAK="nt.mak"
+        }
+    - ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS"))
+    - call "%VSCOMNTOOLS%\..\..\VC\vcvarsall.bat" %VCVARS_PLATFORM%
+    - perl Configure %TARGET% no-asm
+    - call ms\%DO%
+
+build_script:
+    - nmake /f ms\%MAK%
+
+test_script:
+    - nmake /f ms\%MAK% test
+
+notifications:
+    - provider: Email
+      to:
+          - openssl-commits@openssl.org
+      on_build_success: false
+      on_build_failure: true
+      on_build_status_changed: true
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes.h b/src/third_party/openssl/openssl/crypto/aes/aes.h
index 56f166f..d052289 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes.h
+++ b/src/third_party/openssl/openssl/crypto/aes/aes.h
@@ -1,4 +1,4 @@
-/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes.h */
 /* ====================================================================
  * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_cbc.c b/src/third_party/openssl/openssl/crypto/aes/aes_cbc.c
index e39231f..805d0e2 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_cbc.c
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_cbc.c
@@ -1,4 +1,4 @@
-/* crypto/aes/aes_cbc.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes_cbc.c */
 /* ====================================================================
  * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_cfb.c b/src/third_party/openssl/openssl/crypto/aes/aes_cfb.c
index 1c79ce2..1225000 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_cfb.c
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_cfb.c
@@ -1,4 +1,4 @@
-/* crypto/aes/aes_cfb.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes_cfb.c */
 /* ====================================================================
  * Copyright (c) 2002-2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_core.c b/src/third_party/openssl/openssl/crypto/aes/aes_core.c
index f32498f..6630d45 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_core.c
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_core.c
@@ -1,4 +1,4 @@
-/* crypto/aes/aes_core.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes_core.c */
 /**
  * rijndael-alg-fst.c
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_ctr.c b/src/third_party/openssl/openssl/crypto/aes/aes_ctr.c
index 3ee3822..9e760c4 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_ctr.c
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_ctr.c
@@ -1,4 +1,4 @@
-/* crypto/aes/aes_ctr.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes_ctr.c */
 /* ====================================================================
  * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_ecb.c b/src/third_party/openssl/openssl/crypto/aes/aes_ecb.c
index 341e0bc..aad6b02 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_ecb.c
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_ecb.c
@@ -1,4 +1,4 @@
-/* crypto/aes/aes_ecb.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes_ecb.c */
 /* ====================================================================
  * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_ige.c b/src/third_party/openssl/openssl/crypto/aes/aes_ige.c
index cf31c9b..8f2b770 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_ige.c
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_ige.c
@@ -1,4 +1,4 @@
-/* crypto/aes/aes_ige.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes_ige.c */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_locl.h b/src/third_party/openssl/openssl/crypto/aes/aes_locl.h
index 4bf2e3a..3038b16 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_locl.h
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_locl.h
@@ -1,4 +1,4 @@
-/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes.h */
 /* ====================================================================
  * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_misc.c b/src/third_party/openssl/openssl/crypto/aes/aes_misc.c
index ab948ad..fafad4d 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_misc.c
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_misc.c
@@ -1,4 +1,4 @@
-/* crypto/aes/aes_misc.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes_misc.c */
 /* ====================================================================
  * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_ofb.c b/src/third_party/openssl/openssl/crypto/aes/aes_ofb.c
index e6153f9..64a08ca 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_ofb.c
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_ofb.c
@@ -1,4 +1,4 @@
-/* crypto/aes/aes_ofb.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes_ofb.c */
 /* ====================================================================
  * Copyright (c) 2002-2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/aes_x86core.c b/src/third_party/openssl/openssl/crypto/aes/aes_x86core.c
index 1defbb1..428bd58 100644
--- a/src/third_party/openssl/openssl/crypto/aes/aes_x86core.c
+++ b/src/third_party/openssl/openssl/crypto/aes/aes_x86core.c
@@ -1,4 +1,4 @@
-/* crypto/aes/aes_core.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/aes/aes_core.c */
 /**
  * rijndael-alg-fst.c
  *
diff --git a/src/third_party/openssl/openssl/crypto/aes/asm/aes-586.pl b/src/third_party/openssl/openssl/crypto/aes/asm/aes-586.pl
index 687ed81..51b500d 100755
--- a/src/third_party/openssl/openssl/crypto/aes/asm/aes-586.pl
+++ b/src/third_party/openssl/openssl/crypto/aes/asm/aes-586.pl
@@ -45,7 +45,7 @@
 # the undertaken effort was that it appeared that in tight IA-32
 # register window little-endian flavor could achieve slightly higher
 # Instruction Level Parallelism, and it indeed resulted in up to 15%
-# better performance on most recent µ-archs...
+# better performance on most recent µ-archs...
 #
 # Third version adds AES_cbc_encrypt implementation, which resulted in
 # up to 40% performance imrovement of CBC benchmark results. 40% was
@@ -223,7 +223,7 @@
 $speed_limit=512;	# chunks smaller than $speed_limit are
 			# processed with compact routine in CBC mode
 $small_footprint=1;	# $small_footprint=1 code is ~5% slower [on
-			# recent µ-archs], but ~5 times smaller!
+			# recent µ-archs], but ~5 times smaller!
 			# I favor compact code to minimize cache
 			# contention and in hope to "collect" 5% back
 			# in real-life applications...
@@ -562,7 +562,7 @@
 # Performance is not actually extraordinary in comparison to pure
 # x86 code. In particular encrypt performance is virtually the same.
 # Decrypt performance on the other hand is 15-20% better on newer
-# µ-archs [but we're thankful for *any* improvement here], and ~50%
+# µ-archs [but we're thankful for *any* improvement here], and ~50%
 # better on PIII:-) And additionally on the pros side this code
 # eliminates redundant references to stack and thus relieves/
 # minimizes the pressure on the memory bus.
diff --git a/src/third_party/openssl/openssl/crypto/aes/asm/aesni-x86.pl b/src/third_party/openssl/openssl/crypto/aes/asm/aesni-x86.pl
index 3dc345b..8c1d0b5 100644
--- a/src/third_party/openssl/openssl/crypto/aes/asm/aesni-x86.pl
+++ b/src/third_party/openssl/openssl/crypto/aes/asm/aesni-x86.pl
@@ -74,7 +74,7 @@
 $inout4="xmm6";	$in0="xmm6";
 $inout5="xmm7";	$ivec="xmm7";
 
-# AESNI extenstion
+# AESNI extension
 sub aeskeygenassist
 { my($dst,$src,$imm)=@_;
     if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
diff --git a/src/third_party/openssl/openssl/crypto/asn1/asn1_par.c b/src/third_party/openssl/openssl/crypto/asn1/asn1_par.c
index 22013b9..c4cbf23 100644
--- a/src/third_party/openssl/openssl/crypto/asn1/asn1_par.c
+++ b/src/third_party/openssl/openssl/crypto/asn1/asn1_par.c
@@ -65,6 +65,10 @@
 #include <openssl/objects.h>
 #include <openssl/asn1.h>
 
+#ifndef ASN1_PARSE_MAXDEPTH
+#define ASN1_PARSE_MAXDEPTH 128
+#endif
+
 static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
                            int indent);
 static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
@@ -131,6 +135,12 @@
 #else
     dump_indent = 6;            /* Because we know BIO_dump_indent() */
 #endif
+
+    if (depth > ASN1_PARSE_MAXDEPTH) {
+            BIO_puts(bp, "BAD RECURSION DEPTH\n");
+            return 0;
+    }
+
     p = *pp;
     tot = p + length;
     op = p - 1;
diff --git a/src/third_party/openssl/openssl/crypto/asn1/d2i_pr.c b/src/third_party/openssl/openssl/crypto/asn1/d2i_pr.c
index a66e876..b25e8a9 100644
--- a/src/third_party/openssl/openssl/crypto/asn1/d2i_pr.c
+++ b/src/third_party/openssl/openssl/crypto/asn1/d2i_pr.c
@@ -75,6 +75,7 @@
                          long length)
 {
     EVP_PKEY *ret;
+    const unsigned char *p = *pp;
 
     if ((a == NULL) || (*a == NULL)) {
         if ((ret = EVP_PKEY_new()) == NULL) {
@@ -97,21 +98,23 @@
     }
 
     if (!ret->ameth->old_priv_decode ||
-        !ret->ameth->old_priv_decode(ret, pp, length)) {
+        !ret->ameth->old_priv_decode(ret, &p, length)) {
         if (ret->ameth->priv_decode) {
             PKCS8_PRIV_KEY_INFO *p8 = NULL;
-            p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, pp, length);
+            p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, length);
             if (!p8)
                 goto err;
             EVP_PKEY_free(ret);
             ret = EVP_PKCS82PKEY(p8);
             PKCS8_PRIV_KEY_INFO_free(p8);
-
+            if (ret == NULL)
+                goto err;
         } else {
             ASN1err(ASN1_F_D2I_PRIVATEKEY, ERR_R_ASN1_LIB);
             goto err;
         }
     }
+    *pp = p;
     if (a != NULL)
         (*a) = ret;
     return (ret);
@@ -139,6 +142,7 @@
      * input is surrounded by an ASN1 SEQUENCE.
      */
     inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, length);
+    p = *pp;
     /*
      * Since we only need to discern "traditional format" RSA and DSA keys we
      * can just count the elements.
@@ -149,7 +153,7 @@
         keytype = EVP_PKEY_EC;
     else if (sk_ASN1_TYPE_num(inkey) == 3) { /* This seems to be PKCS8, not
                                               * traditional format */
-        PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, pp, length);
+        PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, length);
         EVP_PKEY *ret;
 
         sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
@@ -160,6 +164,9 @@
         }
         ret = EVP_PKCS82PKEY(p8);
         PKCS8_PRIV_KEY_INFO_free(p8);
+        if (ret == NULL)
+            return NULL;
+        *pp = p;
         if (a) {
             *a = ret;
         }
diff --git a/src/third_party/openssl/openssl/crypto/asn1/tasn_dec.c b/src/third_party/openssl/openssl/crypto/asn1/tasn_dec.c
index 8c1d715..3dce02f 100644
--- a/src/third_party/openssl/openssl/crypto/asn1/tasn_dec.c
+++ b/src/third_party/openssl/openssl/crypto/asn1/tasn_dec.c
@@ -183,6 +183,8 @@
     int otag;
     int ret = 0;
     ASN1_VALUE **pchptr, *ptmpval;
+    int combine = aclass & ASN1_TFLG_COMBINE;
+    aclass &= ~ASN1_TFLG_COMBINE;
     if (!pval)
         return 0;
     if (aux && aux->asn1_cb)
@@ -353,9 +355,9 @@
         }
 
         asn1_set_choice_selector(pval, i, it);
-        *in = p;
         if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL))
             goto auxerr;
+        *in = p;
         return 1;
 
     case ASN1_ITYPE_NDEF_SEQUENCE:
@@ -492,9 +494,9 @@
         /* Save encoding */
         if (!asn1_enc_save(pval, *in, p - *in, it))
             goto auxerr;
-        *in = p;
         if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL))
             goto auxerr;
+        *in = p;
         return 1;
 
     default:
@@ -503,7 +505,8 @@
  auxerr:
     ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_AUX_ERROR);
  err:
-    ASN1_item_ex_free(pval, it);
+    if (combine == 0)
+        ASN1_item_ex_free(pval, it);
     if (errtt)
         ERR_add_error_data(4, "Field=", errtt->field_name,
                            ", Type=", it->sname);
@@ -692,7 +695,7 @@
     } else {
         /* Nothing special */
         ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
-                               -1, 0, opt, ctx);
+                               -1, tt->flags & ASN1_TFLG_COMBINE, opt, ctx);
         if (!ret) {
             ASN1err(ASN1_F_ASN1_TEMPLATE_NOEXP_D2I, ERR_R_NESTED_ASN1_ERROR);
             goto err;
diff --git a/src/third_party/openssl/openssl/crypto/asn1/x_bignum.c b/src/third_party/openssl/openssl/crypto/asn1/x_bignum.c
index d8d95f0..fa91799 100644
--- a/src/third_party/openssl/openssl/crypto/asn1/x_bignum.c
+++ b/src/third_party/openssl/openssl/crypto/asn1/x_bignum.c
@@ -144,8 +144,9 @@
                   int utype, char *free_cont, const ASN1_ITEM *it)
 {
     BIGNUM *bn;
-    if (!*pval)
-        bn_new(pval, it);
+
+    if (*pval == NULL && !bn_new(pval, it))
+        return 0;
     bn = (BIGNUM *)*pval;
     if (!BN_bin2bn(cont, len, bn)) {
         bn_free(pval, it);
diff --git a/src/third_party/openssl/openssl/crypto/asn1/x_pubkey.c b/src/third_party/openssl/openssl/crypto/asn1/x_pubkey.c
index 61e2d44..965e02c 100644
--- a/src/third_party/openssl/openssl/crypto/asn1/x_pubkey.c
+++ b/src/third_party/openssl/openssl/crypto/asn1/x_pubkey.c
@@ -191,13 +191,16 @@
 {
     X509_PUBKEY *xpk;
     EVP_PKEY *pktmp;
-    xpk = d2i_X509_PUBKEY(NULL, pp, length);
+    const unsigned char *q;
+    q = *pp;
+    xpk = d2i_X509_PUBKEY(NULL, &q, length);
     if (!xpk)
         return NULL;
     pktmp = X509_PUBKEY_get(xpk);
     X509_PUBKEY_free(xpk);
     if (!pktmp)
         return NULL;
+    *pp = q;
     if (a) {
         EVP_PKEY_free(*a);
         *a = pktmp;
diff --git a/src/third_party/openssl/openssl/crypto/asn1/x_x509.c b/src/third_party/openssl/openssl/crypto/asn1/x_x509.c
index 3858333..5bc89bd 100644
--- a/src/third_party/openssl/openssl/crypto/asn1/x_x509.c
+++ b/src/third_party/openssl/openssl/crypto/asn1/x_x509.c
@@ -183,16 +183,15 @@
     if (!a || *a == NULL) {
         freeret = 1;
     }
-    ret = d2i_X509(a, pp, length);
+    ret = d2i_X509(a, &q, length);
     /* If certificate unreadable then forget it */
     if (!ret)
         return NULL;
     /* update length */
-    length -= *pp - q;
-    if (!length)
-        return ret;
-    if (!d2i_X509_CERT_AUX(&ret->aux, pp, length))
+    length -= q - *pp;
+    if (length > 0 && !d2i_X509_CERT_AUX(&ret->aux, &q, length))
         goto err;
+    *pp = q;
     return ret;
  err:
     if (freeret) {
diff --git a/src/third_party/openssl/openssl/crypto/bio/b_dump.c b/src/third_party/openssl/openssl/crypto/bio/b_dump.c
index f43e6a5..3846654 100644
--- a/src/third_party/openssl/openssl/crypto/bio/b_dump.c
+++ b/src/third_party/openssl/openssl/crypto/bio/b_dump.c
@@ -107,7 +107,6 @@
     if ((rows * dump_width) < len)
         rows++;
     for (i = 0; i < rows; i++) {
-        buf[0] = '\0';          /* start with empty string */
         BUF_strlcpy(buf, str, sizeof buf);
         BIO_snprintf(tmp, sizeof tmp, "%04x - ", i * dump_width);
         BUF_strlcat(buf, tmp, sizeof buf);
diff --git a/src/third_party/openssl/openssl/crypto/bio/bio.h b/src/third_party/openssl/openssl/crypto/bio/bio.h
index 195b5cc..814cbe8 100644
--- a/src/third_party/openssl/openssl/crypto/bio/bio.h
+++ b/src/third_party/openssl/openssl/crypto/bio/bio.h
@@ -481,11 +481,11 @@
 # define BIO_get_conn_hostname(b)  BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,0)
 # define BIO_get_conn_port(b)      BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,1)
 # define BIO_get_conn_ip(b)               BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,2)
-# define BIO_get_conn_int_port(b) BIO_int_ctrl(b,BIO_C_GET_CONNECT,3,0)
+# define BIO_get_conn_int_port(b) BIO_ctrl(b,BIO_C_GET_CONNECT,3,0,NULL)
 
 # define BIO_set_nbio(b,n)       BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL)
 
-/* BIO_s_accept_socket() */
+/* BIO_s_accept() */
 # define BIO_set_accept_port(b,name) BIO_ctrl(b,BIO_C_SET_ACCEPT,0,(char *)name)
 # define BIO_get_accept_port(b)  BIO_ptr_ctrl(b,BIO_C_GET_ACCEPT,0)
 /* #define BIO_set_nbio(b,n)    BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL) */
@@ -498,6 +498,7 @@
 # define BIO_set_bind_mode(b,mode) BIO_ctrl(b,BIO_C_SET_BIND_MODE,mode,NULL)
 # define BIO_get_bind_mode(b,mode) BIO_ctrl(b,BIO_C_GET_BIND_MODE,0,NULL)
 
+/* BIO_s_accept() and BIO_s_connect() */
 # define BIO_do_connect(b)       BIO_do_handshake(b)
 # define BIO_do_accept(b)        BIO_do_handshake(b)
 # define BIO_do_handshake(b)     BIO_ctrl(b,BIO_C_DO_STATE_MACHINE,0,NULL)
@@ -517,12 +518,15 @@
 # define BIO_get_url(b,url)      BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,2,(char *)(url))
 # define BIO_get_no_connect_return(b)    BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,5,NULL)
 
+/* BIO_s_datagram(), BIO_s_fd(), BIO_s_socket(), BIO_s_accept() and BIO_s_connect() */
 # define BIO_set_fd(b,fd,c)      BIO_int_ctrl(b,BIO_C_SET_FD,c,fd)
 # define BIO_get_fd(b,c)         BIO_ctrl(b,BIO_C_GET_FD,0,(char *)c)
 
+/* BIO_s_file() */
 # define BIO_set_fp(b,fp,c)      BIO_ctrl(b,BIO_C_SET_FILE_PTR,c,(char *)fp)
 # define BIO_get_fp(b,fpp)       BIO_ctrl(b,BIO_C_GET_FILE_PTR,0,(char *)fpp)
 
+/* BIO_s_fd() and BIO_s_file() */
 # define BIO_seek(b,ofs) (int)BIO_ctrl(b,BIO_C_FILE_SEEK,ofs,NULL)
 # define BIO_tell(b)     (int)BIO_ctrl(b,BIO_C_FILE_TELL,0,NULL)
 
diff --git a/src/third_party/openssl/openssl/crypto/bio/bss_bio.c b/src/third_party/openssl/openssl/crypto/bio/bss_bio.c
index ba88afb..c04d7ca 100644
--- a/src/third_party/openssl/openssl/crypto/bio/bss_bio.c
+++ b/src/third_party/openssl/openssl/crypto/bio/bss_bio.c
@@ -1,4 +1,4 @@
-/* crypto/bio/bss_bio.c  -*- Mode: C; c-file-style: "eay" -*- */
+/* crypto/bio/bss_bio.c  */
 /* ====================================================================
  * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/bio/bss_conn.c b/src/third_party/openssl/openssl/crypto/bio/bss_conn.c
index 6a5e8de..ed214ca 100644
--- a/src/third_party/openssl/openssl/crypto/bio/bss_conn.c
+++ b/src/third_party/openssl/openssl/crypto/bio/bss_conn.c
@@ -419,7 +419,7 @@
 {
     BIO *dbio;
     int *ip;
-    const char **pptr;
+    const char **pptr = NULL;
     long ret = 1;
     BIO_CONNECT *data;
 
@@ -442,19 +442,28 @@
     case BIO_C_GET_CONNECT:
         if (ptr != NULL) {
             pptr = (const char **)ptr;
-            if (num == 0) {
-                *pptr = data->param_hostname;
+        }
 
-            } else if (num == 1) {
-                *pptr = data->param_port;
-            } else if (num == 2) {
-                *pptr = (char *)&(data->ip[0]);
-            } else if (num == 3) {
-                *((int *)ptr) = data->port;
+        if (b->init) {
+            if (pptr != NULL) {
+                ret = 1;
+                if (num == 0) {
+                    *pptr = data->param_hostname;
+                } else if (num == 1) {
+                    *pptr = data->param_port;
+                } else if (num == 2) {
+                    *pptr = (char *)&(data->ip[0]);
+                } else {
+                    ret = 0;
+                }
             }
-            if ((!b->init) || (ptr == NULL))
+            if (num == 3) {
+                ret = data->port;
+            }
+        } else {
+            if (pptr != NULL)
                 *pptr = "not initialized";
-            ret = 1;
+            ret = 0;
         }
         break;
     case BIO_C_SET_CONNECT:
diff --git a/src/third_party/openssl/openssl/crypto/bio/bss_dgram.c b/src/third_party/openssl/openssl/crypto/bio/bss_dgram.c
index e3e3dd0..d12b83a 100644
--- a/src/third_party/openssl/openssl/crypto/bio/bss_dgram.c
+++ b/src/third_party/openssl/openssl/crypto/bio/bss_dgram.c
@@ -515,10 +515,8 @@
     switch (cmd) {
     case BIO_CTRL_RESET:
         num = 0;
-    case BIO_C_FILE_SEEK:
         ret = 0;
         break;
-    case BIO_C_FILE_TELL:
     case BIO_CTRL_INFO:
         ret = 0;
         break;
diff --git a/src/third_party/openssl/openssl/crypto/bio/bss_file.c b/src/third_party/openssl/openssl/crypto/bio/bss_file.c
index 56abcb1..a815d8e 100644
--- a/src/third_party/openssl/openssl/crypto/bio/bss_file.c
+++ b/src/third_party/openssl/openssl/crypto/bio/bss_file.c
@@ -118,33 +118,9 @@
     NULL,
 };
 
-BIO *BIO_new_file(const char *filename, const char *mode)
+#  if !defined(OPENSSL_SYS_STARBOARD)
+static FILE *file_fopen(const char *filename, const char *mode)
 {
-    BIO *ret = NULL;
-#  if defined(OPENSSL_SYS_STARBOARD)
-    SbFile sb_file = kSbFileInvalid;
-    SbFileError error = kSbFileOk;
-    sb_file = SbFileOpen(filename, SbFileModeStringToFlags(mode), NULL, &error);
-    if (!SbFileIsValid(sb_file)) {
-        SYSerr(SYS_F_FOPEN, error);
-        ERR_add_error_data(5, "SbFileOpen('", filename, "','", mode, "')");
-        if (error == kSbFileErrorNotFound) {
-            BIOerr(BIO_F_BIO_NEW_FILE, BIO_R_NO_SUCH_FILE);
-        } else {
-            BIOerr(BIO_F_BIO_NEW_FILE, ERR_R_SYS_LIB);
-        }
-
-        return (NULL);
-    }
-    ret = BIO_new(BIO_s_file());
-    if (ret == NULL) {
-        SbFileClose(sb_file);
-        return (NULL);
-    }
-
-    BIO_clear_flags(ret, BIO_FLAGS_UPLINK);
-    BIO_set_fp(ret, sb_file, BIO_CLOSE);
-#  else  // defined(OPENSSL_SYS_STARBOARD)
     FILE *file = NULL;
 
 #   if defined(_WIN32) && defined(CP_UTF8)
@@ -191,6 +167,40 @@
 #   else
     file = fopen(filename, mode);
 #   endif
+    return (file);
+}
+
+#endif  // defined(OPENSSL_SYS_STARBOARD)
+
+BIO *BIO_new_file(const char *filename, const char *mode)
+{
+    BIO *ret = NULL;
+#  if defined(OPENSSL_SYS_STARBOARD)
+    SbFile sb_file = kSbFileInvalid;
+    SbFileError error = kSbFileOk;
+    sb_file = SbFileOpen(filename, SbFileModeStringToFlags(mode), NULL, &error);
+    if (!SbFileIsValid(sb_file)) {
+        SYSerr(SYS_F_FOPEN, error);
+        ERR_add_error_data(5, "SbFileOpen('", filename, "','", mode, "')");
+        if (error == kSbFileErrorNotFound) {
+            BIOerr(BIO_F_BIO_NEW_FILE, BIO_R_NO_SUCH_FILE);
+        } else {
+            BIOerr(BIO_F_BIO_NEW_FILE, ERR_R_SYS_LIB);
+        }
+
+        return (NULL);
+    }
+    ret = BIO_new(BIO_s_file());
+    if (ret == NULL) {
+        SbFileClose(sb_file);
+        return (NULL);
+    }
+
+    BIO_clear_flags(ret, BIO_FLAGS_UPLINK);
+    BIO_set_fp(ret, sb_file, BIO_CLOSE);
+#  else  // defined(OPENSSL_SYS_STARBOARD)
+    FILE *file = file_fopen(filename, mode);
+
     if (file == NULL) {
         SYSerr(SYS_F_FOPEN, get_last_sys_error());
         ERR_add_error_data(5, "fopen('", filename, "','", mode, "')");
diff --git a/src/third_party/openssl/openssl/crypto/bn/asm/armv4-gf2m.pl b/src/third_party/openssl/openssl/crypto/bn/asm/armv4-gf2m.pl
index c52e0b7..22ad1f8 100644
--- a/src/third_party/openssl/openssl/crypto/bn/asm/armv4-gf2m.pl
+++ b/src/third_party/openssl/openssl/crypto/bn/asm/armv4-gf2m.pl
@@ -41,13 +41,13 @@
 .align	5
 mul_1x1_neon:
 	vshl.u64	`&Dlo("q1")`,d16,#8	@ q1-q3 are slided $a
-	vmull.p8	`&Q("d0")`,d16,d17	@ a·bb
+	vmull.p8	`&Q("d0")`,d16,d17	@ a·bb
 	vshl.u64	`&Dlo("q2")`,d16,#16
-	vmull.p8	q1,`&Dlo("q1")`,d17	@ a<<8·bb
+	vmull.p8	q1,`&Dlo("q1")`,d17	@ a<<8·bb
 	vshl.u64	`&Dlo("q3")`,d16,#24
-	vmull.p8	q2,`&Dlo("q2")`,d17	@ a<<16·bb
+	vmull.p8	q2,`&Dlo("q2")`,d17	@ a<<16·bb
 	vshr.u64	`&Dlo("q1")`,#8
-	vmull.p8	q3,`&Dlo("q3")`,d17	@ a<<24·bb
+	vmull.p8	q3,`&Dlo("q3")`,d17	@ a<<24·bb
 	vshl.u64	`&Dhi("q1")`,#24
 	veor		d0,`&Dlo("q1")`
 	vshr.u64	`&Dlo("q2")`,#16
@@ -158,7 +158,7 @@
 ################
 # void	bn_GF2m_mul_2x2(BN_ULONG *r,
 #	BN_ULONG a1,BN_ULONG a0,
-#	BN_ULONG b1,BN_ULONG b0);	# r[3..0]=a1a0·b1b0
+#	BN_ULONG b1,BN_ULONG b0);	# r[3..0]=a1a0·b1b0
 
 ($A1,$B1,$A0,$B0,$A1B1,$A0B0)=map("d$_",(18..23));
 
@@ -184,20 +184,20 @@
 
 	vmov	d16,$A1
 	vmov	d17,$B1
-	bl	mul_1x1_neon		@ a1·b1
+	bl	mul_1x1_neon		@ a1·b1
 	vmov	$A1B1,d0
 
 	vmov	d16,$A0
 	vmov	d17,$B0
-	bl	mul_1x1_neon		@ a0·b0
+	bl	mul_1x1_neon		@ a0·b0
 	vmov	$A0B0,d0
 
 	veor	d16,$A0,$A1
 	veor	d17,$B0,$B1
 	veor	$A0,$A0B0,$A1B1
-	bl	mul_1x1_neon		@ (a0+a1)·(b0+b1)
+	bl	mul_1x1_neon		@ (a0+a1)·(b0+b1)
 
-	veor	d0,$A0			@ (a0+a1)·(b0+b1)-a0·b0-a1·b1
+	veor	d0,$A0			@ (a0+a1)·(b0+b1)-a0·b0-a1·b1
 	vshl.u64 d1,d0,#32
 	vshr.u64 d0,d0,#32
 	veor	$A0B0,d1
@@ -220,7 +220,7 @@
 	mov	$mask,#7<<2
 	sub	sp,sp,#32		@ allocate tab[8]
 
-	bl	mul_1x1_ialu		@ a1·b1
+	bl	mul_1x1_ialu		@ a1·b1
 	str	$lo,[$ret,#8]
 	str	$hi,[$ret,#12]
 
@@ -230,13 +230,13 @@
 	 eor	r2,r2,$a
 	eor	$b,$b,r3
 	 eor	$a,$a,r2
-	bl	mul_1x1_ialu		@ a0·b0
+	bl	mul_1x1_ialu		@ a0·b0
 	str	$lo,[$ret]
 	str	$hi,[$ret,#4]
 
 	eor	$a,$a,r2
 	eor	$b,$b,r3
-	bl	mul_1x1_ialu		@ (a1+a0)·(b1+b0)
+	bl	mul_1x1_ialu		@ (a1+a0)·(b1+b0)
 ___
 @r=map("r$_",(6..9));
 $code.=<<___;
diff --git a/src/third_party/openssl/openssl/crypto/bn/asm/ia64.S b/src/third_party/openssl/openssl/crypto/bn/asm/ia64.S
index 951abc5..a9a42ab 100644
--- a/src/third_party/openssl/openssl/crypto/bn/asm/ia64.S
+++ b/src/third_party/openssl/openssl/crypto/bn/asm/ia64.S
@@ -422,7 +422,7 @@
 
 // This loop spins in 3*(n+10) ticks on Itanium and in 2*(n+10) on
 // Itanium 2. Yes, unlike previous versions it scales:-) Previous
-// version was peforming *all* additions in IALU and was starving
+// version was performing *all* additions in IALU and was starving
 // for those even on Itanium 2. In this version one addition is
 // moved to FPU and is folded with multiplication. This is at cost
 // of propogating the result from previous call to this subroutine
@@ -568,7 +568,7 @@
 // I've estimated this routine to run in ~120 ticks, but in reality
 // (i.e. according to ar.itc) it takes ~160 ticks. Are those extra
 // cycles consumed for instructions fetch? Or did I misinterpret some
-// clause in Itanium µ-architecture manual? Comments are welcomed and
+// clause in Itanium µ-architecture manual? Comments are welcomed and
 // highly appreciated.
 //
 // On Itanium 2 it takes ~190 ticks. This is because of stalls on
diff --git a/src/third_party/openssl/openssl/crypto/bn/asm/s390x-gf2m.pl b/src/third_party/openssl/openssl/crypto/bn/asm/s390x-gf2m.pl
index cd9f13e..9d18d40 100644
--- a/src/third_party/openssl/openssl/crypto/bn/asm/s390x-gf2m.pl
+++ b/src/third_party/openssl/openssl/crypto/bn/asm/s390x-gf2m.pl
@@ -172,19 +172,19 @@
 if ($SIZE_T==8) {
 my @r=map("%r$_",(6..9));
 $code.=<<___;
-	bras	$ra,_mul_1x1			# a1·b1
+	bras	$ra,_mul_1x1			# a1·b1
 	stmg	$lo,$hi,16($rp)
 
 	lg	$a,`$stdframe+128+4*$SIZE_T`($sp)
 	lg	$b,`$stdframe+128+6*$SIZE_T`($sp)
-	bras	$ra,_mul_1x1			# a0·b0
+	bras	$ra,_mul_1x1			# a0·b0
 	stmg	$lo,$hi,0($rp)
 
 	lg	$a,`$stdframe+128+3*$SIZE_T`($sp)
 	lg	$b,`$stdframe+128+5*$SIZE_T`($sp)
 	xg	$a,`$stdframe+128+4*$SIZE_T`($sp)
 	xg	$b,`$stdframe+128+6*$SIZE_T`($sp)
-	bras	$ra,_mul_1x1			# (a0+a1)·(b0+b1)
+	bras	$ra,_mul_1x1			# (a0+a1)·(b0+b1)
 	lmg	@r[0],@r[3],0($rp)
 
 	xgr	$lo,$hi
diff --git a/src/third_party/openssl/openssl/crypto/bn/asm/x86-gf2m.pl b/src/third_party/openssl/openssl/crypto/bn/asm/x86-gf2m.pl
index 808a1e5..b579530 100644
--- a/src/third_party/openssl/openssl/crypto/bn/asm/x86-gf2m.pl
+++ b/src/third_party/openssl/openssl/crypto/bn/asm/x86-gf2m.pl
@@ -14,7 +14,7 @@
 # the time being... Except that it has three code paths: pure integer
 # code suitable for any x86 CPU, MMX code suitable for PIII and later
 # and PCLMULQDQ suitable for Westmere and later. Improvement varies
-# from one benchmark and µ-arch to another. Below are interval values
+# from one benchmark and µ-arch to another. Below are interval values
 # for 163- and 571-bit ECDH benchmarks relative to compiler-generated
 # code:
 #
@@ -226,22 +226,22 @@
 	&push	("edi");
 	&mov	($a,&wparam(1));
 	&mov	($b,&wparam(3));
-	&call	("_mul_1x1_mmx");	# a1·b1
+	&call	("_mul_1x1_mmx");	# a1·b1
 	&movq	("mm7",$R);
 
 	&mov	($a,&wparam(2));
 	&mov	($b,&wparam(4));
-	&call	("_mul_1x1_mmx");	# a0·b0
+	&call	("_mul_1x1_mmx");	# a0·b0
 	&movq	("mm6",$R);
 
 	&mov	($a,&wparam(1));
 	&mov	($b,&wparam(3));
 	&xor	($a,&wparam(2));
 	&xor	($b,&wparam(4));
-	&call	("_mul_1x1_mmx");	# (a0+a1)·(b0+b1)
+	&call	("_mul_1x1_mmx");	# (a0+a1)·(b0+b1)
 	&pxor	($R,"mm7");
 	&mov	($a,&wparam(0));
-	&pxor	($R,"mm6");		# (a0+a1)·(b0+b1)-a1·b1-a0·b0
+	&pxor	($R,"mm6");		# (a0+a1)·(b0+b1)-a1·b1-a0·b0
 
 	&movq	($A,$R);
 	&psllq	($R,32);
@@ -266,13 +266,13 @@
 
 	&mov	($a,&wparam(1));
 	&mov	($b,&wparam(3));
-	&call	("_mul_1x1_ialu");	# a1·b1
+	&call	("_mul_1x1_ialu");	# a1·b1
 	&mov	(&DWP(8,"esp"),$lo);
 	&mov	(&DWP(12,"esp"),$hi);
 
 	&mov	($a,&wparam(2));
 	&mov	($b,&wparam(4));
-	&call	("_mul_1x1_ialu");	# a0·b0
+	&call	("_mul_1x1_ialu");	# a0·b0
 	&mov	(&DWP(0,"esp"),$lo);
 	&mov	(&DWP(4,"esp"),$hi);
 
@@ -280,7 +280,7 @@
 	&mov	($b,&wparam(3));
 	&xor	($a,&wparam(2));
 	&xor	($b,&wparam(4));
-	&call	("_mul_1x1_ialu");	# (a0+a1)·(b0+b1)
+	&call	("_mul_1x1_ialu");	# (a0+a1)·(b0+b1)
 
 	&mov	("ebp",&wparam(0));
 		 @r=("ebx","ecx","edi","esi");
diff --git a/src/third_party/openssl/openssl/crypto/bn/asm/x86_64-gcc.c b/src/third_party/openssl/openssl/crypto/bn/asm/x86_64-gcc.c
index 9c5074b..0a5bb28 100644
--- a/src/third_party/openssl/openssl/crypto/bn/asm/x86_64-gcc.c
+++ b/src/third_party/openssl/openssl/crypto/bn/asm/x86_64-gcc.c
@@ -66,7 +66,7 @@
 # undef sqr
 
 /*-
- * "m"(a), "+m"(r)      is the way to favor DirectPath µ-code;
+ * "m"(a), "+m"(r)      is the way to favor DirectPath µ-code;
  * "g"(0)               let the compiler to decide where does it
  *                      want to keep the value of zero;
  */
diff --git a/src/third_party/openssl/openssl/crypto/bn/asm/x86_64-gf2m.pl b/src/third_party/openssl/openssl/crypto/bn/asm/x86_64-gf2m.pl
index 226c66c..42bbec2 100644
--- a/src/third_party/openssl/openssl/crypto/bn/asm/x86_64-gf2m.pl
+++ b/src/third_party/openssl/openssl/crypto/bn/asm/x86_64-gf2m.pl
@@ -13,7 +13,7 @@
 # in bn_gf2m.c. It's kind of low-hanging mechanical port from C for
 # the time being... Except that it has two code paths: code suitable
 # for any x86_64 CPU and PCLMULQDQ one suitable for Westmere and
-# later. Improvement varies from one benchmark and µ-arch to another.
+# later. Improvement varies from one benchmark and µ-arch to another.
 # Vanilla code path is at most 20% faster than compiler-generated code
 # [not very impressive], while PCLMULQDQ - whole 85%-160% better on
 # 163- and 571-bit ECDH benchmarks on Intel CPUs. Keep in mind that
@@ -184,13 +184,13 @@
 $code.=<<___;
 	movdqa		%xmm0,%xmm4
 	movdqa		%xmm1,%xmm5
-	pclmulqdq	\$0,%xmm1,%xmm0	# a1·b1
+	pclmulqdq	\$0,%xmm1,%xmm0	# a1·b1
 	pxor		%xmm2,%xmm4
 	pxor		%xmm3,%xmm5
-	pclmulqdq	\$0,%xmm3,%xmm2	# a0·b0
-	pclmulqdq	\$0,%xmm5,%xmm4	# (a0+a1)·(b0+b1)
+	pclmulqdq	\$0,%xmm3,%xmm2	# a0·b0
+	pclmulqdq	\$0,%xmm5,%xmm4	# (a0+a1)·(b0+b1)
 	xorps		%xmm0,%xmm4
-	xorps		%xmm2,%xmm4	# (a0+a1)·(b0+b1)-a0·b0-a1·b1
+	xorps		%xmm2,%xmm4	# (a0+a1)·(b0+b1)-a0·b0-a1·b1
 	movdqa		%xmm4,%xmm5
 	pslldq		\$8,%xmm4
 	psrldq		\$8,%xmm5
@@ -225,13 +225,13 @@
 	mov	\$0xf,$mask
 	mov	$a1,$a
 	mov	$b1,$b
-	call	_mul_1x1		# a1·b1
+	call	_mul_1x1		# a1·b1
 	mov	$lo,16(%rsp)
 	mov	$hi,24(%rsp)
 
 	mov	48(%rsp),$a
 	mov	64(%rsp),$b
-	call	_mul_1x1		# a0·b0
+	call	_mul_1x1		# a0·b0
 	mov	$lo,0(%rsp)
 	mov	$hi,8(%rsp)
 
@@ -239,7 +239,7 @@
 	mov	56(%rsp),$b
 	xor	48(%rsp),$a
 	xor	64(%rsp),$b
-	call	_mul_1x1		# (a0+a1)·(b0+b1)
+	call	_mul_1x1		# (a0+a1)·(b0+b1)
 ___
 	@r=("%rbx","%rcx","%rdi","%rsi");
 $code.=<<___;
diff --git a/src/third_party/openssl/openssl/crypto/bn/bn_exp.c b/src/third_party/openssl/openssl/crypto/bn/bn_exp.c
index 5bb3e7a..6b5fe2b 100644
--- a/src/third_party/openssl/openssl/crypto/bn/bn_exp.c
+++ b/src/third_party/openssl/openssl/crypto/bn/bn_exp.c
@@ -278,9 +278,14 @@
     }
 
     bits = BN_num_bits(p);
-
     if (bits == 0) {
-        ret = BN_one(r);
+        /* x**0 mod 1 is still zero. */
+        if (BN_is_one(m)) {
+            ret = 1;
+            BN_zero(r);
+        } else {
+            ret = BN_one(r);
+        }
         return ret;
     }
 
@@ -414,7 +419,13 @@
     }
     bits = BN_num_bits(p);
     if (bits == 0) {
-        ret = BN_one(rr);
+        /* x**0 mod 1 is still zero. */
+        if (BN_is_one(m)) {
+            ret = 1;
+            BN_zero(rr);
+        } else {
+            ret = BN_one(rr);
+        }
         return ret;
     }
 
@@ -586,7 +597,7 @@
  * precomputation memory layout to limit data-dependency to a minimum to
  * protect secret exponents (cf. the hyper-threading timing attacks pointed
  * out by Colin Percival,
- * http://www.daemong-consideredperthreading-considered-harmful/)
+ * http://www.daemonology.net/hyperthreading-considered-harmful/)
  */
 int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
                               const BIGNUM *m, BN_CTX *ctx,
@@ -606,15 +617,22 @@
     bn_check_top(p);
     bn_check_top(m);
 
-    top = m->top;
-
-    if (!(m->d[0] & 1)) {
+    if (!BN_is_odd(m)) {
         BNerr(BN_F_BN_MOD_EXP_MONT_CONSTTIME, BN_R_CALLED_WITH_EVEN_MODULUS);
         return (0);
     }
+
+    top = m->top;
+
     bits = BN_num_bits(p);
     if (bits == 0) {
-        ret = BN_one(rr);
+        /* x**0 mod 1 is still zero. */
+        if (BN_is_one(m)) {
+            ret = 1;
+            BN_zero(rr);
+        } else {
+            ret = BN_one(rr);
+        }
         return ret;
     }
 
@@ -914,8 +932,9 @@
         if (BN_is_one(m)) {
             ret = 1;
             BN_zero(rr);
-        } else
+        } else {
             ret = BN_one(rr);
+        }
         return ret;
     }
     if (a == 0) {
@@ -1029,9 +1048,14 @@
     }
 
     bits = BN_num_bits(p);
-
-    if (bits == 0) {
-        ret = BN_one(r);
+   if (bits == 0) {
+        /* x**0 mod 1 is still zero. */
+        if (BN_is_one(m)) {
+            ret = 1;
+            BN_zero(r);
+        } else {
+            ret = BN_one(r);
+        }
         return ret;
     }
 
diff --git a/src/third_party/openssl/openssl/crypto/bn/bn_gcd.c b/src/third_party/openssl/openssl/crypto/bn/bn_gcd.c
index 97c55ab..ce59fe7 100644
--- a/src/third_party/openssl/openssl/crypto/bn/bn_gcd.c
+++ b/src/third_party/openssl/openssl/crypto/bn/bn_gcd.c
@@ -583,6 +583,7 @@
          * BN_div_no_branch will be called eventually.
          */
         pB = &local_B;
+        local_B.flags = 0;
         BN_with_flags(pB, B, BN_FLG_CONSTTIME);
         if (!BN_nnmod(B, pB, A, ctx))
             goto err;
@@ -610,6 +611,7 @@
          * BN_div_no_branch will be called eventually.
          */
         pA = &local_A;
+        local_A.flags = 0;
         BN_with_flags(pA, A, BN_FLG_CONSTTIME);
 
         /* (D, M) := (A/B, A%B) ... */
diff --git a/src/third_party/openssl/openssl/crypto/bn/bn_gf2m.c b/src/third_party/openssl/openssl/crypto/bn/bn_gf2m.c
index eb7c21d..f009744 100644
--- a/src/third_party/openssl/openssl/crypto/bn/bn_gf2m.c
+++ b/src/third_party/openssl/openssl/crypto/bn/bn_gf2m.c
@@ -579,7 +579,7 @@
     bn_check_top(a);
     BN_CTX_start(ctx);
     if ((s = BN_CTX_get(ctx)) == NULL)
-        return 0;
+        goto err;
     if (!bn_wexpand(s, 2 * a->top))
         goto err;
 
@@ -703,18 +703,21 @@
         int top = p->top;
         BN_ULONG *udp, *bdp, *vdp, *cdp;
 
-        bn_wexpand(u, top);
+        if (!bn_wexpand(u, top))
+            goto err;
         udp = u->d;
         for (i = u->top; i < top; i++)
             udp[i] = 0;
         u->top = top;
-        bn_wexpand(b, top);
+        if (!bn_wexpand(b, top))
+          goto err;
         bdp = b->d;
         bdp[0] = 1;
         for (i = 1; i < top; i++)
             bdp[i] = 0;
         b->top = top;
-        bn_wexpand(c, top);
+        if (!bn_wexpand(c, top))
+          goto err;
         cdp = c->d;
         for (i = 0; i < top; i++)
             cdp[i] = 0;
diff --git a/src/third_party/openssl/openssl/crypto/bn/bn_mont.c b/src/third_party/openssl/openssl/crypto/bn/bn_mont.c
index 0c92530..f5add2d 100644
--- a/src/third_party/openssl/openssl/crypto/bn/bn_mont.c
+++ b/src/third_party/openssl/openssl/crypto/bn/bn_mont.c
@@ -364,9 +364,9 @@
     if (mont == NULL)
         return;
 
-    BN_free(&(mont->RR));
-    BN_free(&(mont->N));
-    BN_free(&(mont->Ni));
+    BN_clear_free(&(mont->RR));
+    BN_clear_free(&(mont->N));
+    BN_clear_free(&(mont->Ni));
     if (mont->flags & BN_FLG_MALLOCED)
         OPENSSL_free(mont);
 }
@@ -376,6 +376,9 @@
     int ret = 0;
     BIGNUM *Ri, *R;
 
+    if (BN_is_zero(mod))
+        return 0;
+
     BN_CTX_start(ctx);
     if ((Ri = BN_CTX_get(ctx)) == NULL)
         goto err;
diff --git a/src/third_party/openssl/openssl/crypto/bn/bn_recp.c b/src/third_party/openssl/openssl/crypto/bn/bn_recp.c
index 1f77bc5..027573c 100644
--- a/src/third_party/openssl/openssl/crypto/bn/bn_recp.c
+++ b/src/third_party/openssl/openssl/crypto/bn/bn_recp.c
@@ -155,8 +155,10 @@
 
     if (BN_ucmp(m, &(recp->N)) < 0) {
         BN_zero(d);
-        if (!BN_copy(r, m))
+        if (!BN_copy(r, m)) {
+            BN_CTX_end(ctx);
             return 0;
+        }
         BN_CTX_end(ctx);
         return (1);
     }
diff --git a/src/third_party/openssl/openssl/crypto/bn/bn_x931p.c b/src/third_party/openssl/openssl/crypto/bn/bn_x931p.c
index 6d76b12..efa48bd 100644
--- a/src/third_party/openssl/openssl/crypto/bn/bn_x931p.c
+++ b/src/third_party/openssl/openssl/crypto/bn/bn_x931p.c
@@ -213,14 +213,14 @@
      * exceeded.
      */
     if (!BN_rand(Xp, nbits, 1, 0))
-        return 0;
+        goto err;
 
     BN_CTX_start(ctx);
     t = BN_CTX_get(ctx);
 
     for (i = 0; i < 1000; i++) {
         if (!BN_rand(Xq, nbits, 1, 0))
-            return 0;
+            goto err;
         /* Check that |Xp - Xq| > 2^(nbits - 100) */
         BN_sub(t, Xp, Xq);
         if (BN_num_bits(t) > (nbits - 100))
@@ -234,6 +234,9 @@
 
     return 0;
 
+ err:
+    BN_CTX_end(ctx);
+    return 0;
 }
 
 /*
diff --git a/src/third_party/openssl/openssl/crypto/bn/bntest.c b/src/third_party/openssl/openssl/crypto/bn/bntest.c
index 06662c5..6d55049 100644
--- a/src/third_party/openssl/openssl/crypto/bn/bntest.c
+++ b/src/third_party/openssl/openssl/crypto/bn/bntest.c
@@ -441,6 +441,14 @@
     BN_init(&d);
     BN_init(&e);
 
+    BN_one(&a);
+    BN_zero(&b);
+
+    if (BN_div(&d, &c, &a, &b, ctx)) {
+        fprintf(stderr, "Division by zero succeeded!\n");
+        return 0;
+    }
+
     for (i = 0; i < num0 + num1; i++) {
         if (i < num1) {
             BN_bntest_rand(&a, 400, 0, 0);
@@ -516,9 +524,9 @@
         do {
             BN_bntest_rand(&a, 512, -1, 0);
             BN_bntest_rand(&b, BN_BITS2, -1, 0);
-            s = b.d[0];
-        } while (!s);
+        } while (BN_is_zero(&b));
 
+        s = b.d[0];
         BN_copy(&b, &a);
         r = BN_div_word(&b, s);
 
@@ -781,6 +789,18 @@
     if (mont == NULL)
         return 0;
 
+    BN_zero(&n);
+    if (BN_MONT_CTX_set(mont, &n, ctx)) {
+        fprintf(stderr, "BN_MONT_CTX_set succeeded for zero modulus!\n");
+        return 0;
+    }
+
+    BN_set_word(&n, 16);
+    if (BN_MONT_CTX_set(mont, &n, ctx)) {
+        fprintf(stderr, "BN_MONT_CTX_set succeeded for even modulus!\n");
+        return 0;
+    }
+
     BN_bntest_rand(&a, 100, 0, 0);
     BN_bntest_rand(&b, 100, 0, 0);
     for (i = 0; i < num2; i++) {
@@ -887,6 +907,14 @@
     d = BN_new();
     e = BN_new();
 
+    BN_one(a);
+    BN_one(b);
+    BN_zero(c);
+    if (BN_mod_mul(e, a, b, c, ctx)) {
+        fprintf(stderr, "BN_mod_mul with zero modulus succeeded!\n");
+        return 0;
+    }
+
     for (j = 0; j < 3; j++) {
         BN_bntest_rand(c, 1024, 0, 0);
         for (i = 0; i < num0; i++) {
@@ -952,6 +980,14 @@
     d = BN_new();
     e = BN_new();
 
+    BN_one(a);
+    BN_one(b);
+    BN_zero(c);
+    if (BN_mod_exp(d, a, b, c, ctx)) {
+        fprintf(stderr, "BN_mod_exp with zero modulus succeeded!\n");
+        return 0;
+    }
+
     BN_bntest_rand(c, 30, 0, 1); /* must be odd for montgomery */
     for (i = 0; i < num2; i++) {
         BN_bntest_rand(a, 20 + i * 5, 0, 0);
@@ -999,6 +1035,22 @@
     d = BN_new();
     e = BN_new();
 
+    BN_one(a);
+    BN_one(b);
+    BN_zero(c);
+    if (BN_mod_exp_mont_consttime(d, a, b, c, ctx, NULL)) {
+        fprintf(stderr, "BN_mod_exp_mont_consttime with zero modulus "
+                "succeeded\n");
+        return 0;
+    }
+
+    BN_set_word(c, 16);
+    if (BN_mod_exp_mont_consttime(d, a, b, c, ctx, NULL)) {
+        fprintf(stderr, "BN_mod_exp_mont_consttime with even modulus "
+                "succeeded\n");
+        return 0;
+    }
+
     BN_bntest_rand(c, 30, 0, 1); /* must be odd for montgomery */
     for (i = 0; i < num2; i++) {
         BN_bntest_rand(a, 20 + i * 5, 0, 0);
diff --git a/src/third_party/openssl/openssl/crypto/bn/exptest.c b/src/third_party/openssl/openssl/crypto/bn/exptest.c
index 8b3a4ba..ac611c2 100644
--- a/src/third_party/openssl/openssl/crypto/bn/exptest.c
+++ b/src/third_party/openssl/openssl/crypto/bn/exptest.c
@@ -73,14 +73,34 @@
     "string to make the random number generator think it has entropy";
 
 /*
+ * Test that r == 0 in test_exp_mod_zero(). Returns one on success,
+ * returns zero and prints debug output otherwise.
+ */
+static int a_is_zero_mod_one(const char *method, const BIGNUM *r,
+                             const BIGNUM *a) {
+    if (!BN_is_zero(r)) {
+        fprintf(stderr, "%s failed:\n", method);
+        fprintf(stderr, "a ** 0 mod 1 = r (should be 0)\n");
+        fprintf(stderr, "a = ");
+        BN_print_fp(stderr, a);
+        fprintf(stderr, "\nr = ");
+        BN_print_fp(stderr, r);
+        fprintf(stderr, "\n");
+        return 0;
+    }
+    return 1;
+}
+
+/*
  * test_exp_mod_zero tests that x**0 mod 1 == 0. It returns zero on success.
  */
 static int test_exp_mod_zero()
 {
     BIGNUM a, p, m;
     BIGNUM r;
+    BN_ULONG one_word = 1;
     BN_CTX *ctx = BN_CTX_new();
-    int ret = 1;
+    int ret = 1, failed = 0;
 
     BN_init(&m);
     BN_one(&m);
@@ -92,21 +112,65 @@
     BN_zero(&p);
 
     BN_init(&r);
-    BN_mod_exp(&r, &a, &p, &m, ctx);
-    BN_CTX_free(ctx);
 
-    if (BN_is_zero(&r))
-        ret = 0;
-    else {
-        printf("1**0 mod 1 = ");
-        BN_print_fp(stdout, &r);
-        printf(", should be 0\n");
+    if (!BN_rand(&a, 1024, 0, 0))
+        goto err;
+
+    if (!BN_mod_exp(&r, &a, &p, &m, ctx))
+        goto err;
+
+    if (!a_is_zero_mod_one("BN_mod_exp", &r, &a))
+        failed = 1;
+
+    if (!BN_mod_exp_recp(&r, &a, &p, &m, ctx))
+        goto err;
+
+    if (!a_is_zero_mod_one("BN_mod_exp_recp", &r, &a))
+        failed = 1;
+
+    if (!BN_mod_exp_simple(&r, &a, &p, &m, ctx))
+        goto err;
+
+    if (!a_is_zero_mod_one("BN_mod_exp_simple", &r, &a))
+        failed = 1;
+
+    if (!BN_mod_exp_mont(&r, &a, &p, &m, ctx, NULL))
+        goto err;
+
+    if (!a_is_zero_mod_one("BN_mod_exp_mont", &r, &a))
+        failed = 1;
+
+    if (!BN_mod_exp_mont_consttime(&r, &a, &p, &m, ctx, NULL)) {
+        goto err;
     }
 
+    if (!a_is_zero_mod_one("BN_mod_exp_mont_consttime", &r, &a))
+        failed = 1;
+
+    /*
+     * A different codepath exists for single word multiplication
+     * in non-constant-time only.
+     */
+    if (!BN_mod_exp_mont_word(&r, one_word, &p, &m, ctx, NULL))
+        goto err;
+
+    if (!BN_is_zero(&r)) {
+        fprintf(stderr, "BN_mod_exp_mont_word failed:\n");
+        fprintf(stderr, "1 ** 0 mod 1 = r (should be 0)\n");
+        fprintf(stderr, "r = ");
+        BN_print_fp(stderr, &r);
+        fprintf(stderr, "\n");
+        return 0;
+    }
+
+    ret = failed;
+
+ err:
     BN_free(&r);
     BN_free(&a);
     BN_free(&p);
     BN_free(&m);
+    BN_CTX_free(ctx);
 
     return ret;
 }
diff --git a/src/third_party/openssl/openssl/crypto/buffer/buf_str.c b/src/third_party/openssl/openssl/crypto/buffer/buf_str.c
index 4997367..dcd523d 100644
--- a/src/third_party/openssl/openssl/crypto/buffer/buf_str.c
+++ b/src/third_party/openssl/openssl/crypto/buffer/buf_str.c
@@ -61,12 +61,13 @@
 #include <stdio.h>
 #endif  // !defined(OPENSSL_SYS_STARBOARD)
 #include "cryptlib.h"
+#include <limits.h>
 #include <openssl/buffer.h>
 
 char *BUF_strdup(const char *str)
 {
     if (str == NULL)
-        return (NULL);
+        return NULL;
     return BUF_strndup(str, OPENSSL_port_strlen(str));
 }
 
@@ -75,14 +76,20 @@
     char *ret;
 
     if (str == NULL)
-        return (NULL);
+        return NULL;
+
+    if (siz >= INT_MAX)
+        return NULL;
 
     ret = OPENSSL_malloc(siz + 1);
     if (ret == NULL) {
         BUFerr(BUF_F_BUF_STRNDUP, ERR_R_MALLOC_FAILURE);
-        return (NULL);
+        return NULL;
     }
-    BUF_strlcpy(ret, str, siz + 1);
+
+    OPENSSL_port_memcpy(ret, str, siz);
+    ret[siz] = '\0';
+
     return (ret);
 }
 
@@ -90,13 +97,13 @@
 {
     void *ret;
 
-    if (data == NULL)
-        return (NULL);
+    if (data == NULL || siz >= INT_MAX)
+        return NULL;
 
     ret = OPENSSL_malloc(siz);
     if (ret == NULL) {
         BUFerr(BUF_F_BUF_MEMDUP, ERR_R_MALLOC_FAILURE);
-        return (NULL);
+        return NULL;
     }
     return OPENSSL_port_memcpy(ret, data, siz);
 }
diff --git a/src/third_party/openssl/openssl/crypto/buffer/buffer.h b/src/third_party/openssl/openssl/crypto/buffer/buffer.h
index 0818aae..1a8fa5d 100644
--- a/src/third_party/openssl/openssl/crypto/buffer/buffer.h
+++ b/src/third_party/openssl/openssl/crypto/buffer/buffer.h
@@ -88,7 +88,13 @@
 int BUF_MEM_grow(BUF_MEM *str, size_t len);
 int BUF_MEM_grow_clean(BUF_MEM *str, size_t len);
 char *BUF_strdup(const char *str);
+
+/*
+ * Like strndup, but in addition, explicitly guarantees to never read past the
+ * first |siz| bytes of |str|.
+ */
 char *BUF_strndup(const char *str, size_t siz);
+
 void *BUF_memdup(const void *data, size_t siz);
 void BUF_reverse(unsigned char *out, const unsigned char *in, size_t siz);
 
diff --git a/src/third_party/openssl/openssl/crypto/camellia/camellia.c b/src/third_party/openssl/openssl/crypto/camellia/camellia.c
index b4a6766..719fa61 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/camellia.c
+++ b/src/third_party/openssl/openssl/crypto/camellia/camellia.c
@@ -1,4 +1,4 @@
-/* crypto/camellia/camellia.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/camellia.c */
 /* ====================================================================
  * Copyright 2006 NTT (Nippon Telegraph and Telephone Corporation) .
  * ALL RIGHTS RESERVED.
@@ -67,7 +67,7 @@
 
 /*
  * Algorithm Specification
- * http://info.isl.llia/specicrypt/eng/camellia/specifications.html
+ * http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html
  */
 
 /*
diff --git a/src/third_party/openssl/openssl/crypto/camellia/camellia.h b/src/third_party/openssl/openssl/crypto/camellia/camellia.h
index 6b5bbf6..8612f8b 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/camellia.h
+++ b/src/third_party/openssl/openssl/crypto/camellia/camellia.h
@@ -1,4 +1,4 @@
-/* crypto/camellia/camellia.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/camellia.h */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/camellia/cmll_cbc.c b/src/third_party/openssl/openssl/crypto/camellia/cmll_cbc.c
index a4907ca..4017e00 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/cmll_cbc.c
+++ b/src/third_party/openssl/openssl/crypto/camellia/cmll_cbc.c
@@ -1,4 +1,4 @@
-/* crypto/camellia/camellia_cbc.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/camellia_cbc.c */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/camellia/cmll_cfb.c b/src/third_party/openssl/openssl/crypto/camellia/cmll_cfb.c
index 59b8522..78f2ae4 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/cmll_cfb.c
+++ b/src/third_party/openssl/openssl/crypto/camellia/cmll_cfb.c
@@ -1,4 +1,4 @@
-/* crypto/camellia/camellia_cfb.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/camellia_cfb.c */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/camellia/cmll_ctr.c b/src/third_party/openssl/openssl/crypto/camellia/cmll_ctr.c
index b8f523d..95e2662 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/cmll_ctr.c
+++ b/src/third_party/openssl/openssl/crypto/camellia/cmll_ctr.c
@@ -1,4 +1,4 @@
-/* crypto/camellia/camellia_ctr.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/camellia_ctr.c */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/camellia/cmll_ecb.c b/src/third_party/openssl/openssl/crypto/camellia/cmll_ecb.c
index 16f1af8..b030791 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/cmll_ecb.c
+++ b/src/third_party/openssl/openssl/crypto/camellia/cmll_ecb.c
@@ -1,4 +1,4 @@
-/* crypto/camellia/camellia_ecb.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/camellia_ecb.c */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/camellia/cmll_locl.h b/src/third_party/openssl/openssl/crypto/camellia/cmll_locl.h
index 4e4707b..2bd79b8 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/cmll_locl.h
+++ b/src/third_party/openssl/openssl/crypto/camellia/cmll_locl.h
@@ -1,4 +1,4 @@
-/* crypto/camellia/camellia_locl.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/camellia_locl.h */
 /* ====================================================================
  * Copyright 2006 NTT (Nippon Telegraph and Telephone Corporation) .
  * ALL RIGHTS RESERVED.
diff --git a/src/third_party/openssl/openssl/crypto/camellia/cmll_misc.c b/src/third_party/openssl/openssl/crypto/camellia/cmll_misc.c
index cbd2502..694d2fa 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/cmll_misc.c
+++ b/src/third_party/openssl/openssl/crypto/camellia/cmll_misc.c
@@ -1,4 +1,4 @@
-/* crypto/camellia/camellia_misc.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/camellia_misc.c */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/camellia/cmll_ofb.c b/src/third_party/openssl/openssl/crypto/camellia/cmll_ofb.c
index 46c3ae2..85eb892 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/cmll_ofb.c
+++ b/src/third_party/openssl/openssl/crypto/camellia/cmll_ofb.c
@@ -1,4 +1,4 @@
-/* crypto/camellia/camellia_ofb.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/camellia_ofb.c */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/camellia/cmll_utl.c b/src/third_party/openssl/openssl/crypto/camellia/cmll_utl.c
index d19ee19..d5eb6b4 100644
--- a/src/third_party/openssl/openssl/crypto/camellia/cmll_utl.c
+++ b/src/third_party/openssl/openssl/crypto/camellia/cmll_utl.c
@@ -1,4 +1,4 @@
-/* crypto/camellia/cmll_utl.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/camellia/cmll_utl.c */
 /* ====================================================================
  * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/cms/cms_enc.c b/src/third_party/openssl/openssl/crypto/cms/cms_enc.c
index 85ae928..b14b4b6 100644
--- a/src/third_party/openssl/openssl/crypto/cms/cms_enc.c
+++ b/src/third_party/openssl/openssl/crypto/cms/cms_enc.c
@@ -195,7 +195,7 @@
     ok = 1;
 
  err:
-    if (ec->key && !keep_key) {
+    if (ec->key && (!keep_key || !ok)) {
         OPENSSL_cleanse(ec->key, ec->keylen);
         OPENSSL_free(ec->key);
         ec->key = NULL;
diff --git a/src/third_party/openssl/openssl/crypto/cms/cms_pwri.c b/src/third_party/openssl/openssl/crypto/cms/cms_pwri.c
index a8322dc..b91c016 100644
--- a/src/third_party/openssl/openssl/crypto/cms/cms_pwri.c
+++ b/src/third_party/openssl/openssl/crypto/cms/cms_pwri.c
@@ -121,6 +121,9 @@
 
     /* Setup algorithm identifier for cipher */
     encalg = X509_ALGOR_new();
+    if (encalg == NULL) {
+        goto merr;
+    }
     EVP_CIPHER_CTX_init(&ctx);
 
     if (EVP_EncryptInit_ex(&ctx, kekciph, NULL, NULL, NULL) <= 0) {
diff --git a/src/third_party/openssl/openssl/crypto/cms/cms_smime.c b/src/third_party/openssl/openssl/crypto/cms/cms_smime.c
index 8b37560..f45693a 100644
--- a/src/third_party/openssl/openssl/crypto/cms/cms_smime.c
+++ b/src/third_party/openssl/openssl/crypto/cms/cms_smime.c
@@ -714,7 +714,7 @@
     BIO *cmsbio;
     int ret = 0;
     if (!(cmsbio = CMS_dataInit(cms, dcont))) {
-        CMSerr(CMS_F_CMS_FINAL, ERR_R_MALLOC_FAILURE);
+        CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_LIB);
         return 0;
     }
 
diff --git a/src/third_party/openssl/openssl/crypto/comp/c_zlib.c b/src/third_party/openssl/openssl/crypto/comp/c_zlib.c
index 6731af8..9c32614 100644
--- a/src/third_party/openssl/openssl/crypto/comp/c_zlib.c
+++ b/src/third_party/openssl/openssl/crypto/comp/c_zlib.c
@@ -404,8 +404,9 @@
 void COMP_zlib_cleanup(void)
 {
 #ifdef ZLIB_SHARED
-    if (zlib_dso)
+    if (zlib_dso != NULL)
         DSO_free(zlib_dso);
+    zlib_dso = NULL;
 #endif
 }
 
diff --git a/src/third_party/openssl/openssl/crypto/conf/conf_def.c b/src/third_party/openssl/openssl/crypto/conf/conf_def.c
index f70b2d0..d1a81fb 100644
--- a/src/third_party/openssl/openssl/crypto/conf/conf_def.c
+++ b/src/third_party/openssl/openssl/crypto/conf/conf_def.c
@@ -228,12 +228,11 @@
         goto err;
     }
 
-    section = (char *)OPENSSL_malloc(10);
+    section = BUF_strdup("default");
     if (section == NULL) {
         CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
         goto err;
     }
-    BUF_strlcpy(section, "default", 10);
 
     if (_CONF_new_data(conf) == 0) {
         CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
diff --git a/src/third_party/openssl/openssl/crypto/conf/conf_sap.c b/src/third_party/openssl/openssl/crypto/conf/conf_sap.c
index ce49e0e..33e3f72 100644
--- a/src/third_party/openssl/openssl/crypto/conf/conf_sap.c
+++ b/src/third_party/openssl/openssl/crypto/conf/conf_sap.c
@@ -93,6 +93,7 @@
     CONF_modules_load_file(NULL, config_name,
                                CONF_MFLAGS_DEFAULT_SECTION |
                                CONF_MFLAGS_IGNORE_MISSING_FILE);
+    openssl_configured = 1;
 }
 
 void OPENSSL_no_config()
diff --git a/src/third_party/openssl/openssl/crypto/cryptlib.c b/src/third_party/openssl/openssl/crypto/cryptlib.c
index 3d2c1b4..62c859f 100644
--- a/src/third_party/openssl/openssl/crypto/cryptlib.c
+++ b/src/third_party/openssl/openssl/crypto/cryptlib.c
@@ -941,13 +941,29 @@
 # if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333
     /* this -------------v--- guards NT-specific calls */
     if (check_winnt() && OPENSSL_isservice() > 0) {
-        HANDLE h = RegisterEventSource(0, _T("OPENSSL"));
-        const TCHAR *pmsg = buf;
-        ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 0, 0, 1, 0, &pmsg, 0);
-        DeregisterEventSource(h);
+        HANDLE hEventLog = RegisterEventSource(NULL, _T("OpenSSL"));
+
+        if (hEventLog != NULL) {
+            const TCHAR *pmsg = buf;
+
+            if (!ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, 0, 0, NULL,
+                             1, 0, &pmsg, NULL)) {
+#if defined(DEBUG)
+                /*
+                 * We are in a situation where we tried to report a critical
+                 * error and this failed for some reason. As a last resort,
+                 * in debug builds, send output to the debugger or any other
+                 * tool like DebugView which can monitor the output.
+                 */
+                OutputDebugString(pmsg);
+#endif
+            }
+
+            (void)DeregisterEventSource(hEventLog);
+        }
     } else
 # endif
-        MessageBox(NULL, buf, _T("OpenSSL: FATAL"), MB_OK | MB_ICONSTOP);
+        MessageBox(NULL, buf, _T("OpenSSL: FATAL"), MB_OK | MB_ICONERROR);
 }
 #else
 void OPENSSL_showfatal(const char *fmta, ...)
diff --git a/src/third_party/openssl/openssl/crypto/des/des_old.c b/src/third_party/openssl/openssl/crypto/des/des_old.c
index 54b0968..c5c5a00 100644
--- a/src/third_party/openssl/openssl/crypto/des/des_old.c
+++ b/src/third_party/openssl/openssl/crypto/des/des_old.c
@@ -1,4 +1,4 @@
-/* crypto/des/des_old.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/des/des_old.c */
 
 /*-
  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
diff --git a/src/third_party/openssl/openssl/crypto/des/des_old.h b/src/third_party/openssl/openssl/crypto/des/des_old.h
index f1e1e2c..ee7607a 100644
--- a/src/third_party/openssl/openssl/crypto/des/des_old.h
+++ b/src/third_party/openssl/openssl/crypto/des/des_old.h
@@ -1,4 +1,4 @@
-/* crypto/des/des_old.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/des/des_old.h */
 
 /*-
  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
diff --git a/src/third_party/openssl/openssl/crypto/des/des_old2.c b/src/third_party/openssl/openssl/crypto/des/des_old2.c
index f7d28a6..247ff8d 100644
--- a/src/third_party/openssl/openssl/crypto/des/des_old2.c
+++ b/src/third_party/openssl/openssl/crypto/des/des_old2.c
@@ -1,4 +1,4 @@
-/* crypto/des/des_old.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/des/des_old.c */
 
 /*
  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING The
diff --git a/src/third_party/openssl/openssl/crypto/dsa/dsa_ameth.c b/src/third_party/openssl/openssl/crypto/dsa/dsa_ameth.c
index c448c4e..11d57f2 100644
--- a/src/third_party/openssl/openssl/crypto/dsa/dsa_ameth.c
+++ b/src/third_party/openssl/openssl/crypto/dsa/dsa_ameth.c
@@ -321,6 +321,7 @@
     dplen = i2d_ASN1_INTEGER(prkey, &dp);
 
     ASN1_STRING_clear_free(prkey);
+    prkey = NULL;
 
     if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_dsa), 0,
                          V_ASN1_SEQUENCE, params, dp, dplen))
diff --git a/src/third_party/openssl/openssl/crypto/dsa/dsa_gen.c b/src/third_party/openssl/openssl/crypto/dsa/dsa_gen.c
index fd94005..bf683f4 100644
--- a/src/third_party/openssl/openssl/crypto/dsa/dsa_gen.c
+++ b/src/third_party/openssl/openssl/crypto/dsa/dsa_gen.c
@@ -115,16 +115,8 @@
     }
 # endif
     else {
-        const EVP_MD *evpmd;
-        size_t qbits = bits >= 2048 ? 256 : 160;
-
-        if (bits >= 2048) {
-            qbits = 256;
-            evpmd = EVP_sha256();
-        } else {
-            qbits = 160;
-            evpmd = EVP_sha1();
-        }
+        const EVP_MD *evpmd = bits >= 2048 ? EVP_sha256() : EVP_sha1();
+        size_t qbits = EVP_MD_size(evpmd) * 8;
 
         return dsa_builtin_paramgen(ret, bits, qbits, evpmd,
                                     seed_in, seed_len, NULL, counter_ret,
@@ -177,13 +169,14 @@
     if (seed_in != NULL)
         OPENSSL_port_memcpy(seed, seed_in, seed_len);
 
-    if ((ctx = BN_CTX_new()) == NULL)
-        goto err;
-
     if ((mont = BN_MONT_CTX_new()) == NULL)
         goto err;
 
+    if ((ctx = BN_CTX_new()) == NULL)
+        goto err;
+
     BN_CTX_start(ctx);
+
     r0 = BN_CTX_get(ctx);
     g = BN_CTX_get(ctx);
     W = BN_CTX_get(ctx);
@@ -204,7 +197,7 @@
             if (!BN_GENCB_call(cb, 0, m++))
                 goto err;
 
-            if (!seed_len) {
+            if (!seed_len || !seed_in) {
                 if (RAND_pseudo_bytes(seed, qsize) < 0)
                     goto err;
                 seed_is_random = 1;
diff --git a/src/third_party/openssl/openssl/crypto/dsa/dsa_ossl.c b/src/third_party/openssl/openssl/crypto/dsa/dsa_ossl.c
index 4e4af03..725c700 100644
--- a/src/third_party/openssl/openssl/crypto/dsa/dsa_ossl.c
+++ b/src/third_party/openssl/openssl/crypto/dsa/dsa_ossl.c
@@ -190,9 +190,6 @@
     if (!BN_mod_mul(s, s, kinv, dsa->q, ctx))
         goto err;
 
-    ret = DSA_SIG_new();
-    if (ret == NULL)
-        goto err;
     /*
      * Redo if r or s is zero as required by FIPS 186-3: this is very
      * unlikely.
@@ -204,11 +201,14 @@
         }
         goto redo;
     }
+    ret = DSA_SIG_new();
+    if (ret == NULL)
+        goto err;
     ret->r = r;
     ret->s = s;
 
  err:
-    if (!ret) {
+    if (ret == NULL) {
         DSAerr(DSA_F_DSA_DO_SIGN, reason);
         BN_free(r);
         BN_free(s);
diff --git a/src/third_party/openssl/openssl/crypto/dso/dso.h b/src/third_party/openssl/openssl/crypto/dso/dso.h
index 7c4a1dc..c9013f5 100644
--- a/src/third_party/openssl/openssl/crypto/dso/dso.h
+++ b/src/third_party/openssl/openssl/crypto/dso/dso.h
@@ -1,4 +1,4 @@
-/* dso.h -*- mode:C; c-file-style: "eay" -*- */
+/* dso.h */
 /*
  * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
  * 2000.
diff --git a/src/third_party/openssl/openssl/crypto/dso/dso_dl.c b/src/third_party/openssl/openssl/crypto/dso/dso_dl.c
index 0087ac5..ceedf66 100644
--- a/src/third_party/openssl/openssl/crypto/dso/dso_dl.c
+++ b/src/third_party/openssl/openssl/crypto/dso/dso_dl.c
@@ -1,4 +1,4 @@
-/* dso_dl.c -*- mode:C; c-file-style: "eay" -*- */
+/* dso_dl.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2000.
diff --git a/src/third_party/openssl/openssl/crypto/dso/dso_dlfcn.c b/src/third_party/openssl/openssl/crypto/dso/dso_dlfcn.c
index f629f03..78df723 100644
--- a/src/third_party/openssl/openssl/crypto/dso/dso_dlfcn.c
+++ b/src/third_party/openssl/openssl/crypto/dso/dso_dlfcn.c
@@ -1,4 +1,4 @@
-/* dso_dlfcn.c -*- mode:C; c-file-style: "eay" -*- */
+/* dso_dlfcn.c */
 /*
  * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
  * 2000.
diff --git a/src/third_party/openssl/openssl/crypto/dso/dso_lib.c b/src/third_party/openssl/openssl/crypto/dso/dso_lib.c
index 09b8eaf..3312450 100644
--- a/src/third_party/openssl/openssl/crypto/dso/dso_lib.c
+++ b/src/third_party/openssl/openssl/crypto/dso/dso_lib.c
@@ -1,4 +1,4 @@
-/* dso_lib.c -*- mode:C; c-file-style: "eay" -*- */
+/* dso_lib.c */
 /*
  * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
  * 2000.
diff --git a/src/third_party/openssl/openssl/crypto/dso/dso_vms.c b/src/third_party/openssl/openssl/crypto/dso/dso_vms.c
index d0794b8..1efd84b 100644
--- a/src/third_party/openssl/openssl/crypto/dso/dso_vms.c
+++ b/src/third_party/openssl/openssl/crypto/dso/dso_vms.c
@@ -1,4 +1,4 @@
-/* dso_vms.c -*- mode:C; c-file-style: "eay" -*- */
+/* dso_vms.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2000.
diff --git a/src/third_party/openssl/openssl/crypto/dso/dso_win32.c b/src/third_party/openssl/openssl/crypto/dso/dso_win32.c
index 54c943d..eaf1831 100644
--- a/src/third_party/openssl/openssl/crypto/dso/dso_win32.c
+++ b/src/third_party/openssl/openssl/crypto/dso/dso_win32.c
@@ -1,4 +1,4 @@
-/* dso_win32.c -*- mode:C; c-file-style: "eay" -*- */
+/* dso_win32.c */
 /*
  * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
  * 2000.
diff --git a/src/third_party/openssl/openssl/crypto/ec/ec.h b/src/third_party/openssl/openssl/crypto/ec/ec.h
index c4e7aea..2a935fd 100644
--- a/src/third_party/openssl/openssl/crypto/ec/ec.h
+++ b/src/third_party/openssl/openssl/crypto/ec/ec.h
@@ -106,7 +106,7 @@
         /** the point is encoded as z||x, where the octet z specifies
          *  which solution of the quadratic equation y is  */
     POINT_CONVERSION_COMPRESSED = 2,
-        /** the point is encoded as z||x||y, where z is the octet 0x02  */
+        /** the point is encoded as z||x||y, where z is the octet 0x04  */
     POINT_CONVERSION_UNCOMPRESSED = 4,
         /** the point is encoded as z||x||y, where the octet z specifies
          *  which solution of the quadratic equation y is  */
diff --git a/src/third_party/openssl/openssl/crypto/ec/ec_asn1.c b/src/third_party/openssl/openssl/crypto/ec/ec_asn1.c
index 0bf3146..929884e 100644
--- a/src/third_party/openssl/openssl/crypto/ec/ec_asn1.c
+++ b/src/third_party/openssl/openssl/crypto/ec/ec_asn1.c
@@ -973,8 +973,9 @@
 {
     EC_GROUP *group = NULL;
     ECPKPARAMETERS *params = NULL;
+    const unsigned char *p = *in;
 
-    if ((params = d2i_ECPKPARAMETERS(NULL, in, len)) == NULL) {
+    if ((params = d2i_ECPKPARAMETERS(NULL, &p, len)) == NULL) {
         ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_D2I_ECPKPARAMETERS_FAILURE);
         ECPKPARAMETERS_free(params);
         return NULL;
@@ -992,6 +993,7 @@
         *a = group;
 
     ECPKPARAMETERS_free(params);
+    *in = p;
     return (group);
 }
 
@@ -1019,8 +1021,9 @@
     int ok = 0;
     EC_KEY *ret = NULL;
     EC_PRIVATEKEY *priv_key = NULL;
+    const unsigned char *p = *in;
 
-    if ((priv_key = d2i_EC_PRIVATEKEY(NULL, in, len)) == NULL) {
+    if ((priv_key = d2i_EC_PRIVATEKEY(NULL, &p, len)) == NULL) {
         ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
         return NULL;
     }
@@ -1099,6 +1102,7 @@
 
     if (a)
         *a = ret;
+    *in = p;
     ok = 1;
  err:
     if (!ok) {
diff --git a/src/third_party/openssl/openssl/crypto/ec/ec_key.c b/src/third_party/openssl/openssl/crypto/ec/ec_key.c
index b39b7e9..c99db5a 100644
--- a/src/third_party/openssl/openssl/crypto/ec/ec_key.c
+++ b/src/third_party/openssl/openssl/crypto/ec/ec_key.c
@@ -369,7 +369,10 @@
     BN_CTX *ctx = NULL;
     BIGNUM *tx, *ty;
     EC_POINT *point = NULL;
-    int ok = 0, tmp_nid, is_char_two = 0;
+    int ok = 0;
+#ifndef OPENSSL_NO_EC2M
+    int tmp_nid, is_char_two = 0;
+#endif
 
     if (!key || !key->group || !x || !y) {
         ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES,
@@ -385,14 +388,15 @@
     if (!point)
         goto err;
 
+    tx = BN_CTX_get(ctx);
+    ty = BN_CTX_get(ctx);
+
+#ifndef OPENSSL_NO_EC2M
     tmp_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(key->group));
 
     if (tmp_nid == NID_X9_62_characteristic_two_field)
         is_char_two = 1;
 
-    tx = BN_CTX_get(ctx);
-    ty = BN_CTX_get(ctx);
-#ifndef OPENSSL_NO_EC2M
     if (is_char_two) {
         if (!EC_POINT_set_affine_coordinates_GF2m(key->group, point,
                                                   x, y, ctx))
diff --git a/src/third_party/openssl/openssl/crypto/ec/ectest.c b/src/third_party/openssl/openssl/crypto/ec/ectest.c
index fede530..efab0b0 100644
--- a/src/third_party/openssl/openssl/crypto/ec/ectest.c
+++ b/src/third_party/openssl/openssl/crypto/ec/ectest.c
@@ -1591,7 +1591,7 @@
     int degree;
     /*
      * Qx, Qy and D are taken from
-     * http://csrcdocut.gov/groups/ST/toolkit/documents/Examples/ECDSA_Prime.pdf
+     * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/ECDSA_Prime.pdf
      * Otherwise, values are standard curve parameters from FIPS 180-3
      */
     const char *p, *a, *b, *Qx, *Qy, *Gx, *Gy, *order, *d;
diff --git a/src/third_party/openssl/openssl/crypto/engine/eng_all.c b/src/third_party/openssl/openssl/crypto/engine/eng_all.c
index 7edf12e..66c4374 100644
--- a/src/third_party/openssl/openssl/crypto/engine/eng_all.c
+++ b/src/third_party/openssl/openssl/crypto/engine/eng_all.c
@@ -1,4 +1,4 @@
-/* crypto/engine/eng_all.c -*- mode: C; c-file-style: "eay" -*- */
+/* crypto/engine/eng_all.c */
 /*
  * Written by Richard Levitte <richard@levitte.org> for the OpenSSL project
  * 2000.
diff --git a/src/third_party/openssl/openssl/crypto/engine/eng_cryptodev.c b/src/third_party/openssl/openssl/crypto/engine/eng_cryptodev.c
index bcb936d..a8a24d0 100644
--- a/src/third_party/openssl/openssl/crypto/engine/eng_cryptodev.c
+++ b/src/third_party/openssl/openssl/crypto/engine/eng_cryptodev.c
@@ -1230,15 +1230,18 @@
     if (cryptodev_asym(&kop, BN_num_bytes(dsa->q), r,
                        BN_num_bytes(dsa->q), s) == 0) {
         dsaret = DSA_SIG_new();
+        if (dsaret == NULL)
+            goto err;
         dsaret->r = r;
         dsaret->s = s;
+        r = s = NULL;
     } else {
         const DSA_METHOD *meth = DSA_OpenSSL();
-        BN_free(r);
-        BN_free(s);
         dsaret = (meth->dsa_do_sign) (dgst, dlen, dsa);
     }
  err:
+    BN_free(r);
+    BN_free(s);
     kop.crk_param[0].crp_p = NULL;
     zapparams(&kop);
     return (dsaret);
diff --git a/src/third_party/openssl/openssl/crypto/engine/eng_list.c b/src/third_party/openssl/openssl/crypto/engine/eng_list.c
index 3384e31..83c95d5 100644
--- a/src/third_party/openssl/openssl/crypto/engine/eng_list.c
+++ b/src/third_party/openssl/openssl/crypto/engine/eng_list.c
@@ -260,6 +260,7 @@
     }
     if ((e->id == NULL) || (e->name == NULL)) {
         ENGINEerr(ENGINE_F_ENGINE_ADD, ENGINE_R_ID_OR_NAME_MISSING);
+        return 0;
     }
     CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
     if (!engine_list_add(e)) {
diff --git a/src/third_party/openssl/openssl/crypto/evp/e_camellia.c b/src/third_party/openssl/openssl/crypto/evp/e_camellia.c
index 27bc489..f7b135d 100644
--- a/src/third_party/openssl/openssl/crypto/evp/e_camellia.c
+++ b/src/third_party/openssl/openssl/crypto/evp/e_camellia.c
@@ -1,4 +1,4 @@
-/* crypto/evp/e_camellia.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/evp/e_camellia.c */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/evp/e_des3.c b/src/third_party/openssl/openssl/crypto/evp/e_des3.c
index da5d4c9..bcc0db5 100644
--- a/src/third_party/openssl/openssl/crypto/evp/e_des3.c
+++ b/src/third_party/openssl/openssl/crypto/evp/e_des3.c
@@ -244,7 +244,7 @@
     DES_cblock *deskey = (DES_cblock *)key;
 #  ifdef EVP_CHECK_DES_KEY
     if (DES_set_key_checked(&deskey[0], &data(ctx)->ks1)
-        ! !DES_set_key_checked(&deskey[1], &data(ctx)->ks2))
+        || DES_set_key_checked(&deskey[1], &data(ctx)->ks2))
         return 0;
 #  else
     DES_set_key_unchecked(&deskey[0], &data(ctx)->ks1);
diff --git a/src/third_party/openssl/openssl/crypto/evp/e_old.c b/src/third_party/openssl/openssl/crypto/evp/e_old.c
index c93f5a5..a23d143 100644
--- a/src/third_party/openssl/openssl/crypto/evp/e_old.c
+++ b/src/third_party/openssl/openssl/crypto/evp/e_old.c
@@ -1,4 +1,4 @@
-/* crypto/evp/e_old.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/evp/e_old.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2004.
diff --git a/src/third_party/openssl/openssl/crypto/evp/e_seed.c b/src/third_party/openssl/openssl/crypto/evp/e_seed.c
index c948a8f..7249d1b 100644
--- a/src/third_party/openssl/openssl/crypto/evp/e_seed.c
+++ b/src/third_party/openssl/openssl/crypto/evp/e_seed.c
@@ -1,4 +1,4 @@
-/* crypto/evp/e_seed.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/evp/e_seed.c */
 /* ====================================================================
  * Copyright (c) 2007 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/evp/encode.c b/src/third_party/openssl/openssl/crypto/evp/encode.c
index 6894fd0..dcf937f 100644
--- a/src/third_party/openssl/openssl/crypto/evp/encode.c
+++ b/src/third_party/openssl/openssl/crypto/evp/encode.c
@@ -63,9 +63,9 @@
 #include "cryptlib.h"
 #include <openssl/evp.h>
 
+static unsigned char conv_ascii2bin(unsigned char a);
 #ifndef CHARSET_EBCDIC
 # define conv_bin2ascii(a)       (data_bin2ascii[(a)&0x3f])
-# define conv_ascii2bin(a)       (data_ascii2bin[(a)&0x7f])
 #else
 /*
  * We assume that PEM encoded files are EBCDIC files (i.e., printable text
@@ -74,7 +74,6 @@
  * as the underlying textstring data_bin2ascii[] is already EBCDIC)
  */
 # define conv_bin2ascii(a)       (data_bin2ascii[(a)&0x3f])
-# define conv_ascii2bin(a)       (data_ascii2bin[os_toascii[a]&0x7f])
 #endif
 
 /*-
@@ -106,6 +105,7 @@
 #define B64_WS                  0xE0
 #define B64_ERROR               0xFF
 #define B64_NOT_BASE64(a)       (((a)|0x13) == 0xF3)
+#define B64_BASE64(a)           !B64_NOT_BASE64(a)
 
 static const unsigned char data_ascii2bin[128] = {
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -126,6 +126,23 @@
     0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 };
 
+#ifndef CHARSET_EBCDIC
+static unsigned char conv_ascii2bin(unsigned char a)
+{
+    if (a & 0x80)
+        return B64_ERROR;
+    return data_ascii2bin[a];
+}
+#else
+static unsigned char conv_ascii2bin(unsigned char a)
+{
+    a = os_toascii[a];
+    if (a & 0x80)
+        return B64_ERROR;
+    return data_ascii2bin[a];
+}
+#endif
+
 void EVP_EncodeInit(EVP_ENCODE_CTX *ctx)
 {
     ctx->length = 48;
@@ -142,7 +159,7 @@
     *outl = 0;
     if (inl <= 0)
         return;
-    OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
+    OPENSSL_port_assert(ctx->length <= (int)sizeof(ctx->enc_data));
     if ((ctx->num + inl) < ctx->length) {
         OPENSSL_port_memcpy(&(ctx->enc_data[ctx->num]), in, inl);
         ctx->num += inl;
@@ -221,8 +238,9 @@
 
 void EVP_DecodeInit(EVP_ENCODE_CTX *ctx)
 {
-    ctx->length = 30;
+    /* Only ctx->num is used during decoding. */
     ctx->num = 0;
+    ctx->length = 0;
     ctx->line_num = 0;
     ctx->expect_nl = 0;
 }
@@ -231,139 +249,123 @@
  * -1 for error
  *  0 for last line
  *  1 for full line
+ *
+ * Note: even though EVP_DecodeUpdate attempts to detect and report end of
+ * content, the context doesn't currently remember it and will accept more data
+ * in the next call. Therefore, the caller is responsible for checking and
+ * rejecting a 0 return value in the middle of content.
+ *
+ * Note: even though EVP_DecodeUpdate has historically tried to detect end of
+ * content based on line length, this has never worked properly. Therefore,
+ * we now return 0 when one of the following is true:
+ *   - Padding or B64_EOF was detected and the last block is complete.
+ *   - Input has zero-length.
+ * -1 is returned if:
+ *   - Invalid characters are detected.
+ *   - There is extra trailing padding, or data after padding.
+ *   - B64_EOF is detected after an incomplete base64 block.
  */
 int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
                      const unsigned char *in, int inl)
 {
-    int seof = -1, eof = 0, rv = -1, ret = 0, i, v, tmp, n, ln, exp_nl;
+    int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len;
     unsigned char *d;
 
     n = ctx->num;
     d = ctx->enc_data;
-    ln = ctx->line_num;
-    exp_nl = ctx->expect_nl;
 
-    /* last line of input. */
-    if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF))) {
+    if (n > 0 && d[n - 1] == '=') {
+        eof++;
+        if (n > 1 && d[n - 2] == '=')
+            eof++;
+    }
+
+     /* Legacy behaviour: an empty input chunk signals end of input. */
+    if (inl == 0) {
         rv = 0;
         goto end;
     }
 
-    /* We parse the input data */
     for (i = 0; i < inl; i++) {
-        /* If the current line is > 80 characters, scream alot */
-        if (ln >= 80) {
-            rv = -1;
-            goto end;
-        }
-
-        /* Get char and put it into the buffer */
         tmp = *(in++);
         v = conv_ascii2bin(tmp);
-        /* only save the good data :-) */
-        if (!B64_NOT_BASE64(v)) {
-            OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
-            d[n++] = tmp;
-            ln++;
-        } else if (v == B64_ERROR) {
+        if (v == B64_ERROR) {
             rv = -1;
             goto end;
         }
 
-        /*
-         * have we seen a '=' which is 'definitly' the last input line.  seof
-         * will point to the character that holds it. and eof will hold how
-         * many characters to chop off.
-         */
         if (tmp == '=') {
-            if (seof == -1)
-                seof = n;
             eof++;
+        } else if (eof > 0 && B64_BASE64(v)) {
+            /* More data after padding. */
+            rv = -1;
+            goto end;
         }
 
-        if (v == B64_CR) {
-            ln = 0;
-            if (exp_nl)
-                continue;
+        if (eof > 2) {
+            rv = -1;
+            goto end;
         }
 
-        /* eoln */
-        if (v == B64_EOLN) {
-            ln = 0;
-            if (exp_nl) {
-                exp_nl = 0;
-                continue;
-            }
-        }
-        exp_nl = 0;
-
-        /*
-         * If we are at the end of input and it looks like a line, process
-         * it.
-         */
-        if (((i + 1) == inl) && (((n & 3) == 0) || eof)) {
-            v = B64_EOF;
-            /*
-             * In case things were given us in really small records (so two
-             * '=' were given in separate updates), eof may contain the
-             * incorrect number of ending bytes to skip, so let's redo the
-             * count
-             */
-            eof = 0;
-            if (d[n - 1] == '=')
-                eof++;
-            if (d[n - 2] == '=')
-                eof++;
-            /* There will never be more than two '=' */
+        if (v == B64_EOF) {
+            seof = 1;
+            goto tail;
         }
 
-        if ((v == B64_EOF && (n & 3) == 0) || (n >= 64)) {
-            /*
-             * This is needed to work correctly on 64 byte input lines.  We
-             * process the line and then need to accept the '\n'
-             */
-            if ((v != B64_EOF) && (n >= 64))
-                exp_nl = 1;
-            if (n > 0) {
-                v = EVP_DecodeBlock(out, d, n);
-                n = 0;
-                if (v < 0) {
-                    rv = 0;
-                    goto end;
-                }
-                if (eof > v) {
-                    rv = -1;
-                    goto end;
-                }
-                ret += (v - eof);
-            } else {
-                eof = 1;
-                v = 0;
-            }
-
-            /*
-             * This is the case where we have had a short but valid input
-             * line
-             */
-            if ((v < ctx->length) && eof) {
-                rv = 0;
-                goto end;
-            } else
-                ctx->length = v;
-
-            if (seof >= 0) {
-                rv = 0;
+        /* Only save valid base64 characters. */
+        if (B64_BASE64(v)) {
+            if (n >= 64) {
+                /*
+                 * We increment n once per loop, and empty the buffer as soon as
+                 * we reach 64 characters, so this can only happen if someone's
+                 * manually messed with the ctx. Refuse to write any more data.
+                 */
+                rv = -1;
                 goto end;
             }
-            out += v;
+            OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
+            d[n++] = tmp;
+        }
+
+        if (n == 64) {
+            decoded_len = EVP_DecodeBlock(out, d, n);
+            n = 0;
+            if (decoded_len < 0 || eof > decoded_len) {
+                rv = -1;
+                goto end;
+            }
+            ret += decoded_len - eof;
+            out += decoded_len - eof;
         }
     }
-    rv = 1;
- end:
+
+    /*
+     * Legacy behaviour: if the current line is a full base64-block (i.e., has
+     * 0 mod 4 base64 characters), it is processed immediately. We keep this
+     * behaviour as applications may not be calling EVP_DecodeFinal properly.
+     */
+tail:
+    if (n > 0) {
+        if ((n & 3) == 0) {
+            decoded_len = EVP_DecodeBlock(out, d, n);
+            n = 0;
+            if (decoded_len < 0 || eof > decoded_len) {
+                rv = -1;
+                goto end;
+            }
+            ret += (decoded_len - eof);
+        } else if (seof) {
+            /* EOF in the middle of a base64 block. */
+            rv = -1;
+            goto end;
+        }
+    }
+
+    rv = seof || (n == 0 && eof) ? 0 : 1;
+end:
+    /* Legacy behaviour. This should probably rather be zeroed on error. */
     *outl = ret;
     ctx->num = n;
-    ctx->line_num = ln;
-    ctx->expect_nl = exp_nl;
     return (rv);
 }
 
diff --git a/src/third_party/openssl/openssl/crypto/evp/evp_key.c b/src/third_party/openssl/openssl/crypto/evp/evp_key.c
index cba8867..2ab7a82 100644
--- a/src/third_party/openssl/openssl/crypto/evp/evp_key.c
+++ b/src/third_party/openssl/openssl/crypto/evp/evp_key.c
@@ -109,6 +109,8 @@
     if ((prompt == NULL) && (prompt_string[0] != '\0'))
         prompt = prompt_string;
     ui = UI_new();
+    if (ui == NULL)
+        return -1;
     UI_add_input_string(ui, prompt, 0, buf, min,
                         (len >= BUFSIZ) ? BUFSIZ - 1 : len);
     if (verify)
@@ -143,7 +145,7 @@
     EVP_MD_CTX_init(&c);
     for (;;) {
         if (!EVP_DigestInit_ex(&c, md, NULL))
-            return 0;
+            goto err;
         if (addmd++)
             if (!EVP_DigestUpdate(&c, &(md_buf[0]), mds))
                 goto err;
@@ -194,6 +196,6 @@
     rv = type->key_len;
  err:
     EVP_MD_CTX_cleanup(&c);
-    OPENSSL_cleanse(&(md_buf[0]), EVP_MAX_MD_SIZE);
+    OPENSSL_cleanse(md_buf, sizeof(md_buf));
     return rv;
 }
diff --git a/src/third_party/openssl/openssl/crypto/evp/evp_lib.c b/src/third_party/openssl/openssl/crypto/evp/evp_lib.c
index 15c1ef9..b7f0c50 100644
--- a/src/third_party/openssl/openssl/crypto/evp/evp_lib.c
+++ b/src/third_party/openssl/openssl/crypto/evp/evp_lib.c
@@ -70,9 +70,19 @@
 
     if (c->cipher->set_asn1_parameters != NULL)
         ret = c->cipher->set_asn1_parameters(c, type);
-    else if (c->cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1)
-        ret = EVP_CIPHER_set_asn1_iv(c, type);
-    else
+    else if (c->cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1) {
+        switch (EVP_CIPHER_CTX_mode(c)) {
+
+        case EVP_CIPH_GCM_MODE:
+        case EVP_CIPH_CCM_MODE:
+        case EVP_CIPH_XTS_MODE:
+            ret = -1;
+            break;
+
+        default:
+            ret = EVP_CIPHER_set_asn1_iv(c, type);
+        }
+    } else
         ret = -1;
     return (ret);
 }
@@ -83,9 +93,20 @@
 
     if (c->cipher->get_asn1_parameters != NULL)
         ret = c->cipher->get_asn1_parameters(c, type);
-    else if (c->cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1)
-        ret = EVP_CIPHER_get_asn1_iv(c, type);
-    else
+    else if (c->cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1) {
+        switch (EVP_CIPHER_CTX_mode(c)) {
+
+        case EVP_CIPH_GCM_MODE:
+        case EVP_CIPH_CCM_MODE:
+        case EVP_CIPH_XTS_MODE:
+            ret = -1;
+            break;
+
+        default:
+            ret = EVP_CIPHER_get_asn1_iv(c, type);
+            break;
+        }
+    } else
         ret = -1;
     return (ret);
 }
diff --git a/src/third_party/openssl/openssl/crypto/evp/evp_pbe.c b/src/third_party/openssl/openssl/crypto/evp/evp_pbe.c
index 0962242..ffc7e22 100644
--- a/src/third_party/openssl/openssl/crypto/evp/evp_pbe.c
+++ b/src/third_party/openssl/openssl/crypto/evp/evp_pbe.c
@@ -231,12 +231,16 @@
                          int md_nid, EVP_PBE_KEYGEN *keygen)
 {
     EVP_PBE_CTL *pbe_tmp;
-    if (!pbe_algs)
+
+    if (pbe_algs == NULL) {
         pbe_algs = sk_EVP_PBE_CTL_new(pbe_cmp);
-    if (!(pbe_tmp = (EVP_PBE_CTL *)OPENSSL_malloc(sizeof(EVP_PBE_CTL)))) {
-        EVPerr(EVP_F_EVP_PBE_ALG_ADD_TYPE, ERR_R_MALLOC_FAILURE);
-        return 0;
+        if (pbe_algs == NULL)
+            goto err;
     }
+
+    if ((pbe_tmp = OPENSSL_port_malloc(sizeof(*pbe_tmp))) == NULL)
+        goto err;
+
     pbe_tmp->pbe_type = pbe_type;
     pbe_tmp->pbe_nid = pbe_nid;
     pbe_tmp->cipher_nid = cipher_nid;
@@ -245,6 +249,10 @@
 
     sk_EVP_PBE_CTL_push(pbe_algs, pbe_tmp);
     return 1;
+
+ err:
+    EVPerr(EVP_F_EVP_PBE_ALG_ADD_TYPE, ERR_R_MALLOC_FAILURE);
+    return 0;
 }
 
 int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md,
diff --git a/src/third_party/openssl/openssl/crypto/evp/p_lib.c b/src/third_party/openssl/openssl/crypto/evp/p_lib.c
index 9220528..8da900e 100644
--- a/src/third_party/openssl/openssl/crypto/evp/p_lib.c
+++ b/src/third_party/openssl/openssl/crypto/evp/p_lib.c
@@ -256,7 +256,7 @@
 
 int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key)
 {
-    if (!EVP_PKEY_set_type(pkey, type))
+    if (pkey == NULL || !EVP_PKEY_set_type(pkey, type))
         return 0;
     pkey->pkey.ptr = key;
     return (key != NULL);
diff --git a/src/third_party/openssl/openssl/crypto/evp/pmeth_gn.c b/src/third_party/openssl/openssl/crypto/evp/pmeth_gn.c
index 55b3120..b7ee41e 100644
--- a/src/third_party/openssl/openssl/crypto/evp/pmeth_gn.c
+++ b/src/third_party/openssl/openssl/crypto/evp/pmeth_gn.c
@@ -99,12 +99,17 @@
         return -1;
     }
 
-    if (!ppkey)
+    if (ppkey == NULL)
         return -1;
 
-    if (!*ppkey)
+    if (*ppkey == NULL)
         *ppkey = EVP_PKEY_new();
 
+    if (*ppkey == NULL) {
+        EVPerr(EVP_F_EVP_PKEY_PARAMGEN, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+
     ret = ctx->pmeth->paramgen(ctx, *ppkey);
     if (ret <= 0) {
         EVP_PKEY_free(*ppkey);
diff --git a/src/third_party/openssl/openssl/crypto/hmac/hm_ameth.c b/src/third_party/openssl/openssl/crypto/hmac/hm_ameth.c
index 4358f0a..6bed3a2 100644
--- a/src/third_party/openssl/openssl/crypto/hmac/hm_ameth.c
+++ b/src/third_party/openssl/openssl/crypto/hmac/hm_ameth.c
@@ -111,9 +111,14 @@
     ASN1_OCTET_STRING *os;
     os = ASN1_OCTET_STRING_new();
     if (!os || !ASN1_OCTET_STRING_set(os, *pder, derlen))
-        return 0;
-    EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, os);
+        goto err;
+    if (!EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, os))
+        goto err;
     return 1;
+
+ err:
+    ASN1_OCTET_STRING_free(os);
+    return 0;
 }
 
 static int old_hmac_encode(const EVP_PKEY *pkey, unsigned char **pder)
diff --git a/src/third_party/openssl/openssl/crypto/jpake/jpake.c b/src/third_party/openssl/openssl/crypto/jpake/jpake.c
index ed2e888..ac853d4 100644
--- a/src/third_party/openssl/openssl/crypto/jpake/jpake.c
+++ b/src/third_party/openssl/openssl/crypto/jpake/jpake.c
@@ -218,6 +218,9 @@
     BIGNUM *t3 = BN_new();
     int ret = 0;
 
+    if (h == NULL || t1 == NULL || t2 == NULL || t3 == NULL)
+        goto end;
+
     zkp_hash(h, zkpg, p, ctx->p.peer_name);
 
     /* t1 = g^b */
@@ -233,6 +236,7 @@
     else
         JPAKEerr(JPAKE_F_VERIFY_ZKP, JPAKE_R_ZKP_VERIFY_FAILED);
 
+end:
     /* cleanup */
     BN_free(t3);
     BN_free(t2);
diff --git a/src/third_party/openssl/openssl/crypto/mem_clr.c b/src/third_party/openssl/openssl/crypto/mem_clr.c
index ab82b42..3d5612f 100644
--- a/src/third_party/openssl/openssl/crypto/mem_clr.c
+++ b/src/third_party/openssl/openssl/crypto/mem_clr.c
@@ -1,4 +1,4 @@
-/* crypto/mem_clr.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/mem_clr.c */
 /*
  * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
  * 2002.
@@ -69,6 +69,10 @@
 {
     unsigned char *p = ptr;
     size_t loop = len, ctr = cleanse_ctr;
+
+    if (ptr == NULL)
+        return;
+
     while (loop--) {
         *(p++) = (unsigned char)ctr;
         ctr += (17 + ((size_t)p & 0xF));
diff --git a/src/third_party/openssl/openssl/crypto/modes/asm/ghash-armv4.pl b/src/third_party/openssl/openssl/crypto/modes/asm/ghash-armv4.pl
index d91586e..e46f8e3 100644
--- a/src/third_party/openssl/openssl/crypto/modes/asm/ghash-armv4.pl
+++ b/src/third_party/openssl/openssl/crypto/modes/asm/ghash-armv4.pl
@@ -374,8 +374,8 @@
 	vdup.8		$xi,`&Dlo("$IN")`[0]	@ broadcast lowest byte
 .Linner_neon:
 	subs		$cnt,$cnt,#1
-	vmull.p8	$Qlo,$Hlo,$xi		@ H.lo·Xi[i]
-	vmull.p8	$Qhi,$Hhi,$xi		@ H.hi·Xi[i]
+	vmull.p8	$Qlo,$Hlo,$xi		@ H.lo·Xi[i]
+	vmull.p8	$Qhi,$Hhi,$xi		@ H.hi·Xi[i]
 	vext.8		$IN,$zero,#1		@ IN>>=8
 
 	veor		$Z,$Qpost		@ modulo-scheduled part
@@ -388,7 +388,7 @@
 	vsli.8		$Zo,$T,#1		@ compose the "carry" byte
 	vext.8		$Z,$zero,#1		@ Z>>=8
 
-	vmull.p8	$R,$Zo,$mod		@ "carry"·0xe1
+	vmull.p8	$R,$Zo,$mod		@ "carry"·0xe1
 	vshr.u8		$Zo,$T,#7		@ save Z's bottom bit
 	vext.8		$Qpost,$Qlo,$zero,#1	@ Qlo>>=8
 	veor		$Z,$Qhi
diff --git a/src/third_party/openssl/openssl/crypto/modes/asm/ghash-x86.pl b/src/third_party/openssl/openssl/crypto/modes/asm/ghash-x86.pl
index 83c727e..2426cd0 100644
--- a/src/third_party/openssl/openssl/crypto/modes/asm/ghash-x86.pl
+++ b/src/third_party/openssl/openssl/crypto/modes/asm/ghash-x86.pl
@@ -346,7 +346,7 @@
 # effective address calculation and finally merge of value to Z.hi.
 # Reference to rem_4bit is scheduled so late that I had to >>4
 # rem_4bit elements. This resulted in 20-45% procent improvement
-# on contemporary µ-archs.
+# on contemporary µ-archs.
 {
     my $cnt;
     my $rem_4bit = "eax";
diff --git a/src/third_party/openssl/openssl/crypto/o_dir.c b/src/third_party/openssl/openssl/crypto/o_dir.c
index 01a98df..c90b95f 100644
--- a/src/third_party/openssl/openssl/crypto/o_dir.c
+++ b/src/third_party/openssl/openssl/crypto/o_dir.c
@@ -1,4 +1,4 @@
-/* crypto/o_dir.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/o_dir.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2004.
diff --git a/src/third_party/openssl/openssl/crypto/o_dir.h b/src/third_party/openssl/openssl/crypto/o_dir.h
index 6c1b881..8125918 100644
--- a/src/third_party/openssl/openssl/crypto/o_dir.h
+++ b/src/third_party/openssl/openssl/crypto/o_dir.h
@@ -1,4 +1,4 @@
-/* crypto/o_dir.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/o_dir.h */
 /*
  * Copied from Richard Levitte's (richard@levitte.org) LP library.  All
  * symbol names have been changed, with permission from the author.
diff --git a/src/third_party/openssl/openssl/crypto/o_dir_test.c b/src/third_party/openssl/openssl/crypto/o_dir_test.c
index 7cdbbbc..60436b7 100644
--- a/src/third_party/openssl/openssl/crypto/o_dir_test.c
+++ b/src/third_party/openssl/openssl/crypto/o_dir_test.c
@@ -1,4 +1,4 @@
-/* crypto/o_dir.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/o_dir.h */
 /*
  * Copied from Richard Levitte's (richard@levitte.org) LP library.  All
  * symbol names have been changed, with permission from the author.
diff --git a/src/third_party/openssl/openssl/crypto/o_str.c b/src/third_party/openssl/openssl/crypto/o_str.c
index 95ecf04..325b48e 100644
--- a/src/third_party/openssl/openssl/crypto/o_str.c
+++ b/src/third_party/openssl/openssl/crypto/o_str.c
@@ -1,4 +1,4 @@
-/* crypto/o_str.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/o_str.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2003.
diff --git a/src/third_party/openssl/openssl/crypto/o_str.h b/src/third_party/openssl/openssl/crypto/o_str.h
index 5313528..fa512eb 100644
--- a/src/third_party/openssl/openssl/crypto/o_str.h
+++ b/src/third_party/openssl/openssl/crypto/o_str.h
@@ -1,4 +1,4 @@
-/* crypto/o_str.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/o_str.h */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2003.
diff --git a/src/third_party/openssl/openssl/crypto/o_time.c b/src/third_party/openssl/openssl/crypto/o_time.c
index ee6c780..f21fe79 100644
--- a/src/third_party/openssl/openssl/crypto/o_time.c
+++ b/src/third_party/openssl/openssl/crypto/o_time.c
@@ -1,4 +1,4 @@
-/* crypto/o_time.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/o_time.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2001.
diff --git a/src/third_party/openssl/openssl/crypto/o_time.h b/src/third_party/openssl/openssl/crypto/o_time.h
index 700f2ef..2ad88e1 100644
--- a/src/third_party/openssl/openssl/crypto/o_time.h
+++ b/src/third_party/openssl/openssl/crypto/o_time.h
@@ -1,4 +1,4 @@
-/* crypto/o_time.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/o_time.h */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2001.
diff --git a/src/third_party/openssl/openssl/crypto/ocsp/ocsp_lib.c b/src/third_party/openssl/openssl/crypto/ocsp/ocsp_lib.c
index 6ffeb39..ecfbb9b 100644
--- a/src/third_party/openssl/openssl/crypto/ocsp/ocsp_lib.c
+++ b/src/third_party/openssl/openssl/crypto/ocsp/ocsp_lib.c
@@ -249,12 +249,6 @@
     if ((p = OPENSSL_port_strchr(p, ':'))) {
         *p = 0;
         port = p + 1;
-    } else {
-        /* Not found: set default port */
-        if (*pssl)
-            port = "443";
-        else
-            port = "80";
     }
 
     *pport = BUF_strdup(port);
diff --git a/src/third_party/openssl/openssl/crypto/ocsp/ocsp_prn.c b/src/third_party/openssl/openssl/crypto/ocsp/ocsp_prn.c
index 1834256..47d5f83 100644
--- a/src/third_party/openssl/openssl/crypto/ocsp/ocsp_prn.c
+++ b/src/third_party/openssl/openssl/crypto/ocsp/ocsp_prn.c
@@ -212,8 +212,7 @@
         return 1;
     }
 
-    i = ASN1_STRING_length(rb->response);
-    if (!(br = OCSP_response_get1_basic(o)))
+    if ((br = OCSP_response_get1_basic(o)) == NULL)
         goto err;
     rd = br->tbsResponseData;
     l = ASN1_INTEGER_get(rd->version);
diff --git a/src/third_party/openssl/openssl/crypto/opensslconf.h.in b/src/third_party/openssl/openssl/crypto/opensslconf.h.in
index 814309b..7a1c85d 100644
--- a/src/third_party/openssl/openssl/crypto/opensslconf.h.in
+++ b/src/third_party/openssl/openssl/crypto/opensslconf.h.in
@@ -120,7 +120,7 @@
    optimization options.  Older Sparc's work better with only UNROLL, but
    there's no way to tell at compile time what it is you're running on */
  
-#if defined( sun )		/* Newer Sparc's */
+#if defined( __sun ) || defined ( sun )		/* Newer Sparc's */
 #  define DES_PTR
 #  define DES_RISC1
 #  define DES_UNROLL
diff --git a/src/third_party/openssl/openssl/crypto/opensslv.h b/src/third_party/openssl/openssl/crypto/opensslv.h
index bd66999..3af71c4 100644
--- a/src/third_party/openssl/openssl/crypto/opensslv.h
+++ b/src/third_party/openssl/openssl/crypto/opensslv.h
@@ -30,11 +30,11 @@
  * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
  *  major minor fix final patch/beta)
  */
-# define OPENSSL_VERSION_NUMBER  0x1000110fL
+# define OPENSSL_VERSION_NUMBER  0x1000112fL
 # ifdef OPENSSL_FIPS
-#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.0.1p-fips 9 Jul 2015"
+#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.0.1r-fips  28 Jan 2016"
 # else
-#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.0.1p 9 Jul 2015"
+#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.0.1r  28 Jan 2016"
 # endif
 # define OPENSSL_VERSION_PTEXT   " part of " OPENSSL_VERSION_TEXT
 
diff --git a/src/third_party/openssl/openssl/crypto/pem/pem_info.c b/src/third_party/openssl/openssl/crypto/pem/pem_info.c
index 3f7da0e..941e05f 100644
--- a/src/third_party/openssl/openssl/crypto/pem/pem_info.c
+++ b/src/third_party/openssl/openssl/crypto/pem/pem_info.c
@@ -175,6 +175,8 @@
             xi->enc_len = 0;
 
             xi->x_pkey = X509_PKEY_new();
+            if (xi->x_pkey == NULL)
+                goto err;
             ptype = EVP_PKEY_RSA;
             pp = &xi->x_pkey->dec_pkey;
             if ((int)OPENSSL_port_strlen(header) > 10) /* assume encrypted */
@@ -196,6 +198,8 @@
             xi->enc_len = 0;
 
             xi->x_pkey = X509_PKEY_new();
+            if (xi->x_pkey == NULL)
+                goto err;
             ptype = EVP_PKEY_DSA;
             pp = &xi->x_pkey->dec_pkey;
             if ((int)OPENSSL_port_strlen(header) > 10) /* assume encrypted */
@@ -217,6 +221,8 @@
             xi->enc_len = 0;
 
             xi->x_pkey = X509_PKEY_new();
+            if (xi->x_pkey == NULL)
+                goto err;
             ptype = EVP_PKEY_EC;
             pp = &xi->x_pkey->dec_pkey;
             if ((int)OPENSSL_port_strlen(header) > 10) /* assume encrypted */
diff --git a/src/third_party/openssl/openssl/crypto/pem/pvkfmt.c b/src/third_party/openssl/openssl/crypto/pem/pvkfmt.c
index dc4c7bf..21f4f42 100644
--- a/src/third_party/openssl/openssl/crypto/pem/pvkfmt.c
+++ b/src/third_party/openssl/openssl/crypto/pem/pvkfmt.c
@@ -624,13 +624,11 @@
             PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT);
             return 0;
         }
-        length -= 20;
     } else {
         if (length < 24) {
             PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT);
             return 0;
         }
-        length -= 24;
         pvk_magic = read_ledword(&p);
         if (pvk_magic != MS_PVKMAGIC) {
             PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_BAD_MAGIC_NUMBER);
@@ -692,23 +690,23 @@
             inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u);
         if (inlen <= 0) {
             PEMerr(PEM_F_DO_PVK_BODY, PEM_R_BAD_PASSWORD_READ);
-            return NULL;
+            goto err;
         }
         enctmp = OPENSSL_malloc(keylen + 8);
         if (!enctmp) {
             PEMerr(PEM_F_DO_PVK_BODY, ERR_R_MALLOC_FAILURE);
-            return NULL;
+            goto err;
         }
         if (!derive_pvk_key(keybuf, p, saltlen,
                             (unsigned char *)psbuf, inlen))
-            return NULL;
+            goto err;
         p += saltlen;
         /* Copy BLOBHEADER across, decrypt rest */
         OPENSSL_port_memcpy(enctmp, p, 8);
         p += 8;
         if (keylen < 8) {
             PEMerr(PEM_F_DO_PVK_BODY, PEM_R_PVK_TOO_SHORT);
-            return NULL;
+            goto err;
         }
         inlen = keylen - 8;
         q = enctmp + 8;
diff --git a/src/third_party/openssl/openssl/crypto/pkcs12/p12_add.c b/src/third_party/openssl/openssl/crypto/pkcs12/p12_add.c
index 2db8ee0..8ea0e45 100644
--- a/src/third_party/openssl/openssl/crypto/pkcs12/p12_add.c
+++ b/src/third_party/openssl/openssl/crypto/pkcs12/p12_add.c
@@ -78,15 +78,19 @@
     bag->type = OBJ_nid2obj(nid1);
     if (!ASN1_item_pack(obj, it, &bag->value.octet)) {
         PKCS12err(PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG, ERR_R_MALLOC_FAILURE);
-        return NULL;
+        goto err;
     }
     if (!(safebag = PKCS12_SAFEBAG_new())) {
         PKCS12err(PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG, ERR_R_MALLOC_FAILURE);
-        return NULL;
+        goto err;
     }
     safebag->value.bag = bag;
     safebag->type = OBJ_nid2obj(nid2);
     return safebag;
+
+ err:
+    PKCS12_BAGS_free(bag);
+    return NULL;
 }
 
 /* Turn PKCS8 object into a keybag */
@@ -130,6 +134,7 @@
           PKCS8_encrypt(pbe_nid, pbe_ciph, pass, passlen, salt, saltlen, iter,
                         p8))) {
         PKCS12err(PKCS12_F_PKCS12_MAKE_SHKEYBAG, ERR_R_MALLOC_FAILURE);
+        PKCS12_SAFEBAG_free(bag);
         return NULL;
     }
 
@@ -147,14 +152,18 @@
     p7->type = OBJ_nid2obj(NID_pkcs7_data);
     if (!(p7->d.data = M_ASN1_OCTET_STRING_new())) {
         PKCS12err(PKCS12_F_PKCS12_PACK_P7DATA, ERR_R_MALLOC_FAILURE);
-        return NULL;
+        goto err;
     }
 
     if (!ASN1_item_pack(sk, ASN1_ITEM_rptr(PKCS12_SAFEBAGS), &p7->d.data)) {
         PKCS12err(PKCS12_F_PKCS12_PACK_P7DATA, PKCS12_R_CANT_PACK_STRUCTURE);
-        return NULL;
+        goto err;
     }
     return p7;
+
+ err:
+    PKCS7_free(p7);
+    return NULL;
 }
 
 /* Unpack SAFEBAGS from PKCS#7 data ContentInfo */
@@ -184,7 +193,7 @@
     if (!PKCS7_set_type(p7, NID_pkcs7_encrypted)) {
         PKCS12err(PKCS12_F_PKCS12_PACK_P7ENCDATA,
                   PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE);
-        return NULL;
+        goto err;
     }
 
     pbe_ciph = EVP_get_cipherbynid(pbe_nid);
@@ -196,7 +205,7 @@
 
     if (!pbe) {
         PKCS12err(PKCS12_F_PKCS12_PACK_P7ENCDATA, ERR_R_MALLOC_FAILURE);
-        return NULL;
+        goto err;
     }
     X509_ALGOR_free(p7->d.encrypted->enc_data->algorithm);
     p7->d.encrypted->enc_data->algorithm = pbe;
@@ -205,10 +214,14 @@
           PKCS12_item_i2d_encrypt(pbe, ASN1_ITEM_rptr(PKCS12_SAFEBAGS), pass,
                                   passlen, bags, 1))) {
         PKCS12err(PKCS12_F_PKCS12_PACK_P7ENCDATA, PKCS12_R_ENCRYPT_ERROR);
-        return NULL;
+        goto err;
     }
 
     return p7;
+
+ err:
+    PKCS7_free(p7);
+    return NULL;
 }
 
 STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7encdata(PKCS7 *p7, const char *pass,
diff --git a/src/third_party/openssl/openssl/crypto/pkcs12/p12_crpt.c b/src/third_party/openssl/openssl/crypto/pkcs12/p12_crpt.c
index 9606d4b..9a62038 100644
--- a/src/third_party/openssl/openssl/crypto/pkcs12/p12_crpt.c
+++ b/src/third_party/openssl/openssl/crypto/pkcs12/p12_crpt.c
@@ -80,6 +80,9 @@
     const unsigned char *pbuf;
     unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
 
+    if (cipher == NULL)
+        return 0;
+
     /* Extract useful info from parameter */
     if (param == NULL || param->type != V_ASN1_SEQUENCE ||
         param->value.sequence == NULL) {
diff --git a/src/third_party/openssl/openssl/crypto/pkcs12/p12_mutl.c b/src/third_party/openssl/openssl/crypto/pkcs12/p12_mutl.c
index a57e1f6..3820604 100644
--- a/src/third_party/openssl/openssl/crypto/pkcs12/p12_mutl.c
+++ b/src/third_party/openssl/openssl/crypto/pkcs12/p12_mutl.c
@@ -176,11 +176,11 @@
     }
     if (!saltlen)
         saltlen = PKCS12_SALT_LEN;
-    p12->mac->salt->length = saltlen;
-    if (!(p12->mac->salt->data = OPENSSL_malloc(saltlen))) {
+    if ((p12->mac->salt->data = OPENSSL_port_malloc(saltlen)) == NULL) {
         PKCS12err(PKCS12_F_PKCS12_SETUP_MAC, ERR_R_MALLOC_FAILURE);
         return 0;
     }
+    p12->mac->salt->length = saltlen;
     if (!salt) {
         if (RAND_pseudo_bytes(p12->mac->salt->data, saltlen) < 0)
             return 0;
diff --git a/src/third_party/openssl/openssl/crypto/pkcs7/pk7_doit.c b/src/third_party/openssl/openssl/crypto/pkcs7/pk7_doit.c
index f1157a4..6a5cb9c 100644
--- a/src/third_party/openssl/openssl/crypto/pkcs7/pk7_doit.c
+++ b/src/third_party/openssl/openssl/crypto/pkcs7/pk7_doit.c
@@ -659,6 +659,8 @@
             bio = BIO_new_mem_buf(data_body->data, data_body->length);
         else {
             bio = BIO_new(BIO_s_mem());
+            if (bio == NULL)
+                goto err;
             BIO_set_mem_eof_return(bio, 0);
         }
         if (bio == NULL)
@@ -1159,7 +1161,6 @@
     rsk = p7->d.signed_and_enveloped->recipientinfo;
     if (rsk == NULL)
         return NULL;
-    ri = sk_PKCS7_RECIP_INFO_value(rsk, 0);
     if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx)
         return (NULL);
     ri = sk_PKCS7_RECIP_INFO_value(rsk, idx);
diff --git a/src/third_party/openssl/openssl/crypto/rand/rand_vms.c b/src/third_party/openssl/openssl/crypto/rand/rand_vms.c
index a7179a4..0e10c36 100644
--- a/src/third_party/openssl/openssl/crypto/rand/rand_vms.c
+++ b/src/third_party/openssl/openssl/crypto/rand/rand_vms.c
@@ -1,4 +1,4 @@
-/* crypto/rand/rand_vms.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/rand/rand_vms.c */
 /*
  * Written by Richard Levitte <richard@levitte.org> for the OpenSSL project
  * 2000.
diff --git a/src/third_party/openssl/openssl/crypto/rc4/asm/rc4-x86_64.pl b/src/third_party/openssl/openssl/crypto/rc4/asm/rc4-x86_64.pl
index 75750db..20722d3 100755
--- a/src/third_party/openssl/openssl/crypto/rc4/asm/rc4-x86_64.pl
+++ b/src/third_party/openssl/openssl/crypto/rc4/asm/rc4-x86_64.pl
@@ -56,7 +56,7 @@
 # achieves respectful 432MBps on 2.8GHz processor now. For reference.
 # If executed on Xeon, current RC4_CHAR code-path is 2.7x faster than
 # RC4_INT code-path. While if executed on Opteron, it's only 25%
-# slower than the RC4_INT one [meaning that if CPU µ-arch detection
+# slower than the RC4_INT one [meaning that if CPU µ-arch detection
 # is not implemented, then this final RC4_CHAR code-path should be
 # preferred, as it provides better *all-round* performance].
 
diff --git a/src/third_party/openssl/openssl/crypto/rc4/rc4_utl.c b/src/third_party/openssl/openssl/crypto/rc4/rc4_utl.c
index 7c6a15f..cbd4a24 100644
--- a/src/third_party/openssl/openssl/crypto/rc4/rc4_utl.c
+++ b/src/third_party/openssl/openssl/crypto/rc4/rc4_utl.c
@@ -1,4 +1,4 @@
-/* crypto/rc4/rc4_utl.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/rc4/rc4_utl.c */
 /* ====================================================================
  * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/rsa/rsa_ameth.c b/src/third_party/openssl/openssl/crypto/rsa/rsa_ameth.c
index a5b1fd4..17f5d88 100644
--- a/src/third_party/openssl/openssl/crypto/rsa/rsa_ameth.c
+++ b/src/third_party/openssl/openssl/crypto/rsa/rsa_ameth.c
@@ -282,7 +282,7 @@
     if (pss->maskGenAlgorithm) {
         ASN1_TYPE *param = pss->maskGenAlgorithm->parameter;
         if (OBJ_obj2nid(pss->maskGenAlgorithm->algorithm) == NID_mgf1
-            && param->type == V_ASN1_SEQUENCE) {
+            && param && param->type == V_ASN1_SEQUENCE) {
             p = param->value.sequence->data;
             plen = param->value.sequence->length;
             *pmaskHash = d2i_X509_ALGOR(NULL, &p, plen);
diff --git a/src/third_party/openssl/openssl/crypto/rsa/rsa_chk.c b/src/third_party/openssl/openssl/crypto/rsa/rsa_chk.c
index f438386..607faa0 100644
--- a/src/third_party/openssl/openssl/crypto/rsa/rsa_chk.c
+++ b/src/third_party/openssl/openssl/crypto/rsa/rsa_chk.c
@@ -1,4 +1,4 @@
-/* crypto/rsa/rsa_chk.c  -*- Mode: C; c-file-style: "eay" -*- */
+/* crypto/rsa/rsa_chk.c  */
 /* ====================================================================
  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/rsa/rsa_gen.c b/src/third_party/openssl/openssl/crypto/rsa/rsa_gen.c
index 27f3432..ff0788d 100644
--- a/src/third_party/openssl/openssl/crypto/rsa/rsa_gen.c
+++ b/src/third_party/openssl/openssl/crypto/rsa/rsa_gen.c
@@ -72,6 +72,8 @@
 #include <openssl/rsa.h>
 #ifdef OPENSSL_FIPS
 # include <openssl/fips.h>
+extern int FIPS_rsa_x931_generate_key_ex(RSA *rsa, int bits, BIGNUM *e,
+                                         BN_GENCB *cb);
 #endif
 
 static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
@@ -97,7 +99,7 @@
         return rsa->meth->rsa_keygen(rsa, bits, e_value, cb);
 #ifdef OPENSSL_FIPS
     if (FIPS_mode())
-        return FIPS_rsa_generate_key_ex(rsa, bits, e_value, cb);
+        return FIPS_rsa_x931_generate_key_ex(rsa, bits, e_value, cb);
 #endif
     return rsa_builtin_keygen(rsa, bits, e_value, cb);
 }
diff --git a/src/third_party/openssl/openssl/crypto/rsa/rsa_sign.c b/src/third_party/openssl/openssl/crypto/rsa/rsa_sign.c
index 9363971..e1b5aff 100644
--- a/src/third_party/openssl/openssl/crypto/rsa/rsa_sign.c
+++ b/src/third_party/openssl/openssl/crypto/rsa/rsa_sign.c
@@ -87,7 +87,7 @@
         return 0;
     }
 #endif
-    if ((rsa->flags & RSA_FLAG_SIGN_VER) && rsa->meth->rsa_sign) {
+    if (rsa->meth->rsa_sign) {
         return rsa->meth->rsa_sign(type, m, m_len, sigret, siglen, rsa);
     }
     /* Special case: SSL signature, just check the length */
@@ -221,14 +221,13 @@
             OPENSSL_port_memcpy(rm, s + 2, 16);
             *prm_len = 16;
             ret = 1;
-        } else if (OPENSSL_port_memcmp(m, s + 2, 16))
+        } else if (OPENSSL_port_memcmp(m, s + 2, 16)) {
             RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE);
-        else
+        } else {
             ret = 1;
-    }
-
-    /* Special case: SSL signature */
-    if (dtype == NID_md5_sha1) {
+        }
+    } else if (dtype == NID_md5_sha1) {
+        /* Special case: SSL signature */
         if ((i != SSL_SIG_LENGTH) || OPENSSL_port_memcmp(s, m, SSL_SIG_LENGTH))
             RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE);
         else
@@ -308,7 +307,7 @@
                const unsigned char *sigbuf, unsigned int siglen, RSA *rsa)
 {
 
-    if ((rsa->flags & RSA_FLAG_SIGN_VER) && rsa->meth->rsa_verify) {
+    if (rsa->meth->rsa_verify) {
         return rsa->meth->rsa_verify(dtype, m, m_len, sigbuf, siglen, rsa);
     }
 
diff --git a/src/third_party/openssl/openssl/crypto/rsa/rsa_test.c b/src/third_party/openssl/openssl/crypto/rsa/rsa_test.c
index e971295..85c7440 100644
--- a/src/third_party/openssl/openssl/crypto/rsa/rsa_test.c
+++ b/src/third_party/openssl/openssl/crypto/rsa/rsa_test.c
@@ -297,22 +297,30 @@
         } else
             printf("OAEP encryption/decryption ok\n");
 
-        /* Try decrypting corrupted ciphertexts */
+        /* Try decrypting corrupted ciphertexts. */
         for (n = 0; n < clen; ++n) {
-            int b;
-            unsigned char saved = ctext[n];
-            for (b = 0; b < 256; ++b) {
-                if (b == saved)
-                    continue;
-                ctext[n] = b;
-                num = RSA_private_decrypt(num, ctext, ptext, key,
+            ctext[n] ^= 1;
+            num = RSA_private_decrypt(clen, ctext, ptext, key,
                                           RSA_PKCS1_OAEP_PADDING);
-                if (num > 0) {
-                    printf("Corrupt data decrypted!\n");
-                    err = 1;
-                }
+            if (num > 0) {
+                printf("Corrupt data decrypted!\n");
+                err = 1;
+                break;
+            }
+            ctext[n] ^= 1;
+        }
+
+        /* Test truncated ciphertexts, as well as negative length. */
+        for (n = -1; n < clen; ++n) {
+            num = RSA_private_decrypt(n, ctext, ptext, key,
+                                      RSA_PKCS1_OAEP_PADDING);
+            if (num > 0) {
+                printf("Truncated data decrypted!\n");
+                err = 1;
+                break;
             }
         }
+
  next:
         RSA_free(key);
     }
diff --git a/src/third_party/openssl/openssl/crypto/seed/seed_cbc.c b/src/third_party/openssl/openssl/crypto/seed/seed_cbc.c
index 33e6887..ee1115b 100644
--- a/src/third_party/openssl/openssl/crypto/seed/seed_cbc.c
+++ b/src/third_party/openssl/openssl/crypto/seed/seed_cbc.c
@@ -1,4 +1,4 @@
-/* crypto/seed/seed_cbc.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/seed/seed_cbc.c */
 /* ====================================================================
  * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/seed/seed_cfb.c b/src/third_party/openssl/openssl/crypto/seed/seed_cfb.c
index 3437d7b..b6a5648 100644
--- a/src/third_party/openssl/openssl/crypto/seed/seed_cfb.c
+++ b/src/third_party/openssl/openssl/crypto/seed/seed_cfb.c
@@ -1,4 +1,4 @@
-/* crypto/seed/seed_cfb.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/seed/seed_cfb.c */
 /* ====================================================================
  * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/seed/seed_ecb.c b/src/third_party/openssl/openssl/crypto/seed/seed_ecb.c
index 937a31b..9363d55 100644
--- a/src/third_party/openssl/openssl/crypto/seed/seed_ecb.c
+++ b/src/third_party/openssl/openssl/crypto/seed/seed_ecb.c
@@ -1,4 +1,4 @@
-/* crypto/seed/seed_ecb.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/seed/seed_ecb.c */
 /* ====================================================================
  * Copyright (c) 2007 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/seed/seed_ofb.c b/src/third_party/openssl/openssl/crypto/seed/seed_ofb.c
index 6974302..48b7122 100644
--- a/src/third_party/openssl/openssl/crypto/seed/seed_ofb.c
+++ b/src/third_party/openssl/openssl/crypto/seed/seed_ofb.c
@@ -1,4 +1,4 @@
-/* crypto/seed/seed_ofb.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/seed/seed_ofb.c */
 /* ====================================================================
  * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/sha/asm/sha1-586.pl b/src/third_party/openssl/openssl/crypto/sha/asm/sha1-586.pl
index 1084d22..2b119ff 100644
--- a/src/third_party/openssl/openssl/crypto/sha/asm/sha1-586.pl
+++ b/src/third_party/openssl/openssl/crypto/sha/asm/sha1-586.pl
@@ -66,9 +66,9 @@
 # switch to AVX alone improves performance by as little as 4% in
 # comparison to SSSE3 code path. But below result doesn't look like
 # 4% improvement... Trouble is that Sandy Bridge decodes 'ro[rl]' as
-# pair of µ-ops, and it's the additional µ-ops, two per round, that
+# pair of µ-ops, and it's the additional µ-ops, two per round, that
 # make it run slower than Core2 and Westmere. But 'sh[rl]d' is decoded
-# as single µ-op by Sandy Bridge and it's replacing 'ro[rl]' with
+# as single µ-op by Sandy Bridge and it's replacing 'ro[rl]' with
 # equivalent 'sh[rl]d' that is responsible for the impressive 5.1
 # cycles per processed byte. But 'sh[rl]d' is not something that used
 # to be fast, nor does it appear to be fast in upcoming Bulldozer
diff --git a/src/third_party/openssl/openssl/crypto/sha/asm/sha256-586.pl b/src/third_party/openssl/openssl/crypto/sha/asm/sha256-586.pl
index 928ec53..52a7c7f 100644
--- a/src/third_party/openssl/openssl/crypto/sha/asm/sha256-586.pl
+++ b/src/third_party/openssl/openssl/crypto/sha/asm/sha256-586.pl
@@ -21,7 +21,7 @@
 #     purposes.
 #
 # Performance improvement over compiler generated code varies from
-# 10% to 40% [see above]. Not very impressive on some µ-archs, but
+# 10% to 40% [see above]. Not very impressive on some µ-archs, but
 # it's 5 times smaller and optimizies amount of writes.
 
 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
diff --git a/src/third_party/openssl/openssl/crypto/sha/asm/sha512-586.pl b/src/third_party/openssl/openssl/crypto/sha/asm/sha512-586.pl
index 7eab6a5..9f8c51eb 100644
--- a/src/third_party/openssl/openssl/crypto/sha/asm/sha512-586.pl
+++ b/src/third_party/openssl/openssl/crypto/sha/asm/sha512-586.pl
@@ -23,7 +23,7 @@
 #
 # IALU code-path is optimized for elder Pentiums. On vanilla Pentium
 # performance improvement over compiler generated code reaches ~60%,
-# while on PIII - ~35%. On newer µ-archs improvement varies from 15%
+# while on PIII - ~35%. On newer µ-archs improvement varies from 15%
 # to 50%, but it's less important as they are expected to execute SSE2
 # code-path, which is commonly ~2-3x faster [than compiler generated
 # code]. SSE2 code-path is as fast as original sha512-sse2.pl, even
diff --git a/src/third_party/openssl/openssl/crypto/sha/asm/sha512-parisc.pl b/src/third_party/openssl/openssl/crypto/sha/asm/sha512-parisc.pl
old mode 100644
new mode 100755
index fc0e15b..6cad72e
--- a/src/third_party/openssl/openssl/crypto/sha/asm/sha512-parisc.pl
+++ b/src/third_party/openssl/openssl/crypto/sha/asm/sha512-parisc.pl
@@ -19,7 +19,7 @@
 # SHA512 performance is >2.9x better than gcc 3.2 generated code on
 # PA-7100LC, PA-RISC 1.1 processor. Then implementation detects if the
 # code is executed on PA-RISC 2.0 processor and switches to 64-bit
-# code path delivering adequate peformance even in "blended" 32-bit
+# code path delivering adequate performance even in "blended" 32-bit
 # build. Though 64-bit code is not any faster than code generated by
 # vendor compiler on PA-8600...
 #
diff --git a/src/third_party/openssl/openssl/crypto/sha/sha1test.c b/src/third_party/openssl/openssl/crypto/sha/sha1test.c
index 0052a95..551a348 100644
--- a/src/third_party/openssl/openssl/crypto/sha/sha1test.c
+++ b/src/third_party/openssl/openssl/crypto/sha/sha1test.c
@@ -157,8 +157,8 @@
     if (err)
         printf("ERROR: %d\n", err);
 # endif
-    EXIT(err);
     EVP_MD_CTX_cleanup(&c);
+    EXIT(err);
     return (0);
 }
 
diff --git a/src/third_party/openssl/openssl/crypto/sparccpuid.S b/src/third_party/openssl/openssl/crypto/sparccpuid.S
index 0cc247e..c63d5da 100644
--- a/src/third_party/openssl/openssl/crypto/sparccpuid.S
+++ b/src/third_party/openssl/openssl/crypto/sparccpuid.S
@@ -123,7 +123,7 @@
 			fmovs	%f1,%f3
 			fmovs	%f0,%f2
 
-	add	%fp,BIAS,%i0	! return pointer to caller´s top of stack
+	add	%fp,BIAS,%i0	! return pointer to caller´s top of stack
 
 	ret
 	restore
diff --git a/src/third_party/openssl/openssl/crypto/srp/srp_vfy.c b/src/third_party/openssl/openssl/crypto/srp/srp_vfy.c
index 50f75d7..c4c5ee4 100644
--- a/src/third_party/openssl/openssl/crypto/srp/srp_vfy.c
+++ b/src/third_party/openssl/openssl/crypto/srp/srp_vfy.c
@@ -198,7 +198,7 @@
 
 static SRP_user_pwd *SRP_user_pwd_new()
 {
-    SRP_user_pwd *ret = OPENSSL_malloc(sizeof(SRP_user_pwd));
+    SRP_user_pwd *ret = OPENSSL_port_malloc(sizeof(SRP_user_pwd));
     if (ret == NULL)
         return NULL;
     ret->N = NULL;
@@ -249,7 +249,7 @@
 
 SRP_VBASE *SRP_VBASE_new(char *seed_key)
 {
-    SRP_VBASE *vb = (SRP_VBASE *)OPENSSL_malloc(sizeof(SRP_VBASE));
+    SRP_VBASE *vb = (SRP_VBASE *)OPENSSL_port_malloc(sizeof(SRP_VBASE));
 
     if (vb == NULL)
         return NULL;
@@ -285,7 +285,7 @@
     int len;
 
     SRP_gN_cache *newgN =
-        (SRP_gN_cache *)OPENSSL_malloc(sizeof(SRP_gN_cache));
+        (SRP_gN_cache *)OPENSSL_port_malloc(sizeof(SRP_gN_cache));
     if (newgN == NULL)
         return NULL;
 
@@ -391,7 +391,7 @@
              * we add this couple in the internal Stack
              */
 
-            if ((gN = (SRP_gN *) OPENSSL_malloc(sizeof(SRP_gN))) == NULL)
+            if ((gN = (SRP_gN *) OPENSSL_port_malloc(sizeof(SRP_gN))) == NULL)
                 goto err;
 
             if (!(gN->id = BUF_strdup(pp[DB_srpid]))
@@ -521,12 +521,12 @@
                           char **verifier, const char *N, const char *g)
 {
     int len;
-    char *result = NULL;
-    char *vf;
+    char *result = NULL, *vf = NULL;
     BIGNUM *N_bn = NULL, *g_bn = NULL, *s = NULL, *v = NULL;
     unsigned char tmp[MAX_LEN];
     unsigned char tmp2[MAX_LEN];
     char *defgNid = NULL;
+    int vfsize = 0;
 
     if ((user == NULL) ||
         (pass == NULL) || (salt == NULL) || (verifier == NULL))
@@ -564,22 +564,23 @@
         goto err;
 
     BN_bn2bin(v, tmp);
-    if (((vf = OPENSSL_malloc(BN_num_bytes(v) * 2)) == NULL))
+    vfsize = BN_num_bytes(v) * 2;
+    if (((vf = OPENSSL_port_malloc(vfsize)) == NULL))
         goto err;
     t_tob64(vf, tmp, BN_num_bytes(v));
 
-    *verifier = vf;
     if (*salt == NULL) {
         char *tmp_salt;
 
-        if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) {
-            OPENSSL_free(vf);
+        if ((tmp_salt = OPENSSL_port_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) {
             goto err;
         }
         t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN);
         *salt = tmp_salt;
     }
 
+    *verifier = vf;
+    vf = NULL;
     result = defgNid;
 
  err:
@@ -587,11 +588,21 @@
         BN_free(N_bn);
         BN_free(g_bn);
     }
+    OPENSSL_cleanse(vf, vfsize);
+    OPENSSL_free(vf);
+    BN_clear_free(s);
+    BN_clear_free(v);
     return result;
 }
 
 /*
- * create a verifier (*salt,*verifier,g and N are BIGNUMs)
+ * create a verifier (*salt,*verifier,g and N are BIGNUMs). If *salt != NULL
+ * then the provided salt will be used. On successful exit *verifier will point
+ * to a newly allocated BIGNUM containing the verifier and (if a salt was not
+ * provided) *salt will be populated with a newly allocated BIGNUM containing a
+ * random salt.
+ * The caller is responsible for freeing the allocated *salt and *verifier
+ * BIGNUMS.
  */
 int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt,
                            BIGNUM **verifier, BIGNUM *N, BIGNUM *g)
@@ -600,6 +611,7 @@
     BIGNUM *x = NULL;
     BN_CTX *bn_ctx = BN_CTX_new();
     unsigned char tmp2[MAX_LEN];
+    BIGNUM *salttmp = NULL;
 
     if ((user == NULL) ||
         (pass == NULL) ||
@@ -614,10 +626,12 @@
         if (RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN) < 0)
             goto err;
 
-        *salt = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL);
+        salttmp = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL);
+    } else {
+        salttmp = *salt;
     }
 
-    x = SRP_Calc_x(*salt, user, pass);
+    x = SRP_Calc_x(salttmp, user, pass);
 
     *verifier = BN_new();
     if (*verifier == NULL)
@@ -631,9 +645,11 @@
     srp_bn_print(*verifier);
 
     result = 1;
+    *salt = salttmp;
 
  err:
-
+    if (*salt != salttmp)
+        BN_clear_free(salttmp);
     BN_clear_free(x);
     BN_CTX_free(bn_ctx);
     return result;
diff --git a/src/third_party/openssl/openssl/crypto/store/store.h b/src/third_party/openssl/openssl/crypto/store/store.h
index 8343341..ce3709d 100644
--- a/src/third_party/openssl/openssl/crypto/store/store.h
+++ b/src/third_party/openssl/openssl/crypto/store/store.h
@@ -1,4 +1,4 @@
-/* crypto/store/store.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/store/store.h */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2003.
diff --git a/src/third_party/openssl/openssl/crypto/store/str_lib.c b/src/third_party/openssl/openssl/crypto/store/str_lib.c
index 227b797..e3d5da9 100644
--- a/src/third_party/openssl/openssl/crypto/store/str_lib.c
+++ b/src/third_party/openssl/openssl/crypto/store/str_lib.c
@@ -1,4 +1,4 @@
-/* crypto/store/str_lib.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/store/str_lib.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2003.
diff --git a/src/third_party/openssl/openssl/crypto/store/str_locl.h b/src/third_party/openssl/openssl/crypto/store/str_locl.h
index ac55784..c0b40f0 100644
--- a/src/third_party/openssl/openssl/crypto/store/str_locl.h
+++ b/src/third_party/openssl/openssl/crypto/store/str_locl.h
@@ -1,4 +1,4 @@
-/* crypto/store/str_locl.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/store/str_locl.h */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2003.
diff --git a/src/third_party/openssl/openssl/crypto/store/str_mem.c b/src/third_party/openssl/openssl/crypto/store/str_mem.c
index 8edd0eb..6eee5bb 100644
--- a/src/third_party/openssl/openssl/crypto/store/str_mem.c
+++ b/src/third_party/openssl/openssl/crypto/store/str_mem.c
@@ -1,4 +1,4 @@
-/* crypto/store/str_mem.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/store/str_mem.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2003.
diff --git a/src/third_party/openssl/openssl/crypto/store/str_meth.c b/src/third_party/openssl/openssl/crypto/store/str_meth.c
index d83a6de..c83fbc5 100644
--- a/src/third_party/openssl/openssl/crypto/store/str_meth.c
+++ b/src/third_party/openssl/openssl/crypto/store/str_meth.c
@@ -1,4 +1,4 @@
-/* crypto/store/str_meth.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/store/str_meth.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2003.
diff --git a/src/third_party/openssl/openssl/crypto/ts/ts_rsp_verify.c b/src/third_party/openssl/openssl/crypto/ts/ts_rsp_verify.c
index 32b4d99..e24b2d5 100644
--- a/src/third_party/openssl/openssl/crypto/ts/ts_rsp_verify.c
+++ b/src/third_party/openssl/openssl/crypto/ts/ts_rsp_verify.c
@@ -255,7 +255,8 @@
 
     /* chain is an out argument. */
     *chain = NULL;
-    X509_STORE_CTX_init(&cert_ctx, store, signer, untrusted);
+    if (!X509_STORE_CTX_init(&cert_ctx, store, signer, untrusted))
+        return 0;
     X509_STORE_CTX_set_purpose(&cert_ctx, X509_PURPOSE_TIMESTAMP_SIGN);
     i = X509_verify_cert(&cert_ctx);
     if (i <= 0) {
@@ -522,7 +523,7 @@
             if (ASN1_BIT_STRING_get_bit(info->failure_info,
                                         TS_failure_info[i].code)) {
                 if (!first)
-                    strcpy(failure_text, ",");
+                    strcat(failure_text, ",");
                 else
                     first = 0;
                 strcat(failure_text, TS_failure_info[i].text);
diff --git a/src/third_party/openssl/openssl/crypto/ui/ui.h b/src/third_party/openssl/openssl/crypto/ui/ui.h
index b917eda..0dc1633 100644
--- a/src/third_party/openssl/openssl/crypto/ui/ui.h
+++ b/src/third_party/openssl/openssl/crypto/ui/ui.h
@@ -1,4 +1,4 @@
-/* crypto/ui/ui.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/ui/ui.h */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2001.
diff --git a/src/third_party/openssl/openssl/crypto/ui/ui_compat.c b/src/third_party/openssl/openssl/crypto/ui/ui_compat.c
index 0ca5284..e79d54e 100644
--- a/src/third_party/openssl/openssl/crypto/ui/ui_compat.c
+++ b/src/third_party/openssl/openssl/crypto/ui/ui_compat.c
@@ -1,4 +1,4 @@
-/* crypto/ui/ui_compat.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/ui/ui_compat.c */
 /* ====================================================================
  * Copyright (c) 2001-2002 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/ui/ui_compat.h b/src/third_party/openssl/openssl/crypto/ui/ui_compat.h
index 42fb9ff..bf54154 100644
--- a/src/third_party/openssl/openssl/crypto/ui/ui_compat.h
+++ b/src/third_party/openssl/openssl/crypto/ui/ui_compat.h
@@ -1,4 +1,4 @@
-/* crypto/ui/ui.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/ui/ui.h */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2001.
diff --git a/src/third_party/openssl/openssl/crypto/ui/ui_lib.c b/src/third_party/openssl/openssl/crypto/ui/ui_lib.c
index 5ddd731..2f58035 100644
--- a/src/third_party/openssl/openssl/crypto/ui/ui_lib.c
+++ b/src/third_party/openssl/openssl/crypto/ui/ui_lib.c
@@ -1,4 +1,4 @@
-/* crypto/ui/ui_lib.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/ui/ui_lib.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2001.
diff --git a/src/third_party/openssl/openssl/crypto/ui/ui_locl.h b/src/third_party/openssl/openssl/crypto/ui/ui_locl.h
index 0d919cd..bebc13a 100644
--- a/src/third_party/openssl/openssl/crypto/ui/ui_locl.h
+++ b/src/third_party/openssl/openssl/crypto/ui/ui_locl.h
@@ -1,4 +1,4 @@
-/* crypto/ui/ui.h -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/ui/ui.h */
 /*
  * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
  * 2001.
diff --git a/src/third_party/openssl/openssl/crypto/ui/ui_openssl.c b/src/third_party/openssl/openssl/crypto/ui/ui_openssl.c
index 7753ad8..b4fb703 100644
--- a/src/third_party/openssl/openssl/crypto/ui/ui_openssl.c
+++ b/src/third_party/openssl/openssl/crypto/ui/ui_openssl.c
@@ -1,4 +1,4 @@
-/* crypto/ui/ui_openssl.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/ui/ui_openssl.c */
 /*
  * Written by Richard Levitte (richard@levitte.org) and others for the
  * OpenSSL project 2001.
diff --git a/src/third_party/openssl/openssl/crypto/ui/ui_util.c b/src/third_party/openssl/openssl/crypto/ui/ui_util.c
index f65f80d..0f29011 100644
--- a/src/third_party/openssl/openssl/crypto/ui/ui_util.c
+++ b/src/third_party/openssl/openssl/crypto/ui/ui_util.c
@@ -1,4 +1,4 @@
-/* crypto/ui/ui_util.c -*- mode:C; c-file-style: "eay" -*- */
+/* crypto/ui/ui_util.c */
 /* ====================================================================
  * Copyright (c) 2001-2002 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/whrlpool/asm/wp-mmx.pl b/src/third_party/openssl/openssl/crypto/whrlpool/asm/wp-mmx.pl
index cb2381c..90c2eca 100644
--- a/src/third_party/openssl/openssl/crypto/whrlpool/asm/wp-mmx.pl
+++ b/src/third_party/openssl/openssl/crypto/whrlpool/asm/wp-mmx.pl
@@ -16,7 +16,7 @@
 # table]. I stick to value of 2 for two reasons: 1. smaller table
 # minimizes cache trashing and thus mitigates the hazard of side-
 # channel leakage similar to AES cache-timing one; 2. performance
-# gap among different µ-archs is smaller.
+# gap among different µ-archs is smaller.
 #
 # Performance table lists rounded amounts of CPU cycles spent by
 # whirlpool_block_mmx routine on single 64 byte input block, i.e.
diff --git a/src/third_party/openssl/openssl/crypto/x509/x509_cmp.c b/src/third_party/openssl/openssl/crypto/x509/x509_cmp.c
index 006ad6c..cdbd31a 100644
--- a/src/third_party/openssl/openssl/crypto/x509/x509_cmp.c
+++ b/src/third_party/openssl/openssl/crypto/x509/x509_cmp.c
@@ -182,11 +182,24 @@
  */
 int X509_cmp(const X509 *a, const X509 *b)
 {
+    int rv;
+
     /* ensure hash is valid */
     X509_check_purpose((X509 *)a, -1, 0);
     X509_check_purpose((X509 *)b, -1, 0);
 
-    return OPENSSL_port_memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
+    rv = OPENSSL_port_memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
+    if (rv)
+        return rv;
+    /* Check for match against stored encoding too */
+    if (!a->cert_info->enc.modified && !b->cert_info->enc.modified) {
+        rv = (int)(a->cert_info->enc.len - b->cert_info->enc.len);
+        if (rv)
+            return rv;
+        return OPENSSL_port_memcmp(a->cert_info->enc.enc, b->cert_info->enc.enc,
+                                   a->cert_info->enc.len);
+    }
+    return rv;
 }
 #endif
 
diff --git a/src/third_party/openssl/openssl/crypto/x509/x509_lu.c b/src/third_party/openssl/openssl/crypto/x509/x509_lu.c
index cbba742..28f00a4 100644
--- a/src/third_party/openssl/openssl/crypto/x509/x509_lu.c
+++ b/src/third_party/openssl/openssl/crypto/x509/x509_lu.c
@@ -526,8 +526,6 @@
     X509_OBJECT *obj, xobj;
     sk = sk_X509_CRL_new_null();
     CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
-    /* Check cache first */
-    idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_CRL, nm, &cnt);
 
     /*
      * Always do lookup to possibly add new CRLs to cache
diff --git a/src/third_party/openssl/openssl/crypto/x509/x509_vfy.c b/src/third_party/openssl/openssl/crypto/x509/x509_vfy.c
index 4839b5e..c2cd1ed 100644
--- a/src/third_party/openssl/openssl/crypto/x509/x509_vfy.c
+++ b/src/third_party/openssl/openssl/crypto/x509/x509_vfy.c
@@ -2029,9 +2029,10 @@
     ctx->current_reasons = 0;
     ctx->tree = NULL;
     ctx->parent = NULL;
+    /* Zero ex_data to make sure we're cleanup-safe */
+    OPENSSL_port_memset(&ctx->ex_data, 0, sizeof(ctx->ex_data));
 
     ctx->param = X509_VERIFY_PARAM_new();
-
     if (!ctx->param) {
         X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
         return 0;
@@ -2040,7 +2041,6 @@
     /*
      * Inherit callbacks and flags from X509_STORE if not set use defaults.
      */
-
     if (store)
         ret = X509_VERIFY_PARAM_inherit(ctx->param, store->param);
     else
@@ -2048,6 +2048,7 @@
 
     if (store) {
         ctx->verify_cb = store->verify_cb;
+        /* Seems to always be 0 in OpenSSL, else must be idempotent */
         ctx->cleanup = store->cleanup;
     } else
         ctx->cleanup = 0;
@@ -2058,7 +2059,7 @@
 
     if (ret == 0) {
         X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
-        return 0;
+        goto err;
     }
 
     if (store && store->check_issued)
@@ -2113,19 +2114,18 @@
 
     ctx->check_policy = check_policy;
 
+    if (CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx,
+                           &ctx->ex_data))
+        return 1;
+    X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
+
+ err:
     /*
-     * This OPENSSL_port_memset() can't make any sense anyway, so it's removed. As
-     * X509_STORE_CTX_cleanup does a proper "free" on the ex_data, we put a
-     * corresponding "new" here and remove this bogus initialisation.
+     * On error clean up allocated storage, if the store context was not
+     * allocated with X509_STORE_CTX_new() this is our last chance to do so.
      */
-    /* OPENSSL_port_memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA)); */
-    if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx,
-                            &(ctx->ex_data))) {
-        OPENSSL_free(ctx);
-        X509err(X509_F_X509_STORE_CTX_INIT, ERR_R_MALLOC_FAILURE);
-        return 0;
-    }
-    return 1;
+    X509_STORE_CTX_cleanup(ctx);
+    return 0;
 }
 
 /*
@@ -2141,8 +2141,17 @@
 
 void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
 {
-    if (ctx->cleanup)
+    /*
+     * We need to be idempotent because, unfortunately, free() also calls
+     * cleanup(), so the natural call sequence new(), init(), cleanup(), free()
+     * calls cleanup() for the same object twice!  Thus we must zero the
+     * pointers below after they're freed!
+     */
+    /* Seems to always be 0 in OpenSSL, do this at most once. */
+    if (ctx->cleanup != NULL) {
         ctx->cleanup(ctx);
+        ctx->cleanup = NULL;
+    }
     if (ctx->param != NULL) {
         if (ctx->parent == NULL)
             X509_VERIFY_PARAM_free(ctx->param);
diff --git a/src/third_party/openssl/openssl/crypto/x509/x509_vfy.h b/src/third_party/openssl/openssl/crypto/x509/x509_vfy.h
index 02f2f89..31c7007 100644
--- a/src/third_party/openssl/openssl/crypto/x509/x509_vfy.h
+++ b/src/third_party/openssl/openssl/crypto/x509/x509_vfy.h
@@ -310,7 +310,7 @@
                 X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL)
 
 # define         X509_V_OK                                       0
-/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */
+# define         X509_V_ERR_UNSPECIFIED                          1
 
 # define         X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT            2
 # define         X509_V_ERR_UNABLE_TO_GET_CRL                    3
diff --git a/src/third_party/openssl/openssl/crypto/x509v3/v3_cpols.c b/src/third_party/openssl/openssl/crypto/x509v3/v3_cpols.c
index 29470c2..764e858 100644
--- a/src/third_party/openssl/openssl/crypto/x509v3/v3_cpols.c
+++ b/src/third_party/openssl/openssl/crypto/x509v3/v3_cpols.c
@@ -189,6 +189,10 @@
                 goto err;
             }
             pol = POLICYINFO_new();
+            if (pol == NULL) {
+                X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
             pol->policyid = pobj;
         }
         if (!sk_POLICYINFO_push(pols, pol)) {
diff --git a/src/third_party/openssl/openssl/crypto/x509v3/v3_ncons.c b/src/third_party/openssl/openssl/crypto/x509v3/v3_ncons.c
index 211519a..4967084 100644
--- a/src/third_party/openssl/openssl/crypto/x509v3/v3_ncons.c
+++ b/src/third_party/openssl/openssl/crypto/x509v3/v3_ncons.c
@@ -135,6 +135,8 @@
         }
         tval.value = val->value;
         sub = GENERAL_SUBTREE_new();
+        if (sub == NULL)
+            goto memerr;
         if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1))
             goto err;
         if (!*ptree)
diff --git a/src/third_party/openssl/openssl/crypto/x509v3/v3_pci.c b/src/third_party/openssl/openssl/crypto/x509v3/v3_pci.c
index f3ba5d2..e44bb86 100644
--- a/src/third_party/openssl/openssl/crypto/x509v3/v3_pci.c
+++ b/src/third_party/openssl/openssl/crypto/x509v3/v3_pci.c
@@ -1,9 +1,9 @@
-/* v3_pci.c -*- mode:C; c-file-style: "eay" -*- */
+/* v3_pci.c */
 /*
  * Contributed to the OpenSSL Project 2004 by Richard Levitte
  * (richard@levitte.org)
  */
-/* Copyright (c) 2004 Kungliga Tekniska Högskolan
+/* Copyright (c) 2004 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden).
  * All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/crypto/x509v3/v3_pcia.c b/src/third_party/openssl/openssl/crypto/x509v3/v3_pcia.c
index 350b398..e53c82e 100644
--- a/src/third_party/openssl/openssl/crypto/x509v3/v3_pcia.c
+++ b/src/third_party/openssl/openssl/crypto/x509v3/v3_pcia.c
@@ -1,9 +1,9 @@
-/* v3_pcia.c -*- mode:C; c-file-style: "eay" -*- */
+/* v3_pcia.c */
 /*
  * Contributed to the OpenSSL Project 2004 by Richard Levitte
  * (richard@levitte.org)
  */
-/* Copyright (c) 2004 Kungliga Tekniska Högskolan
+/* Copyright (c) 2004 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden).
  * All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/demos/easy_tls/README b/src/third_party/openssl/openssl/demos/easy_tls/README
index 816a580..ee89dfb 100644
--- a/src/third_party/openssl/openssl/demos/easy_tls/README
+++ b/src/third_party/openssl/openssl/demos/easy_tls/README
@@ -62,4 +62,4 @@
 day, which means that future revisions will not be fully compatible to
 the current version.
 
-Bodo Möller <bodo@openssl.org>
+Bodo Möller <bodo@openssl.org>
diff --git a/src/third_party/openssl/openssl/demos/easy_tls/easy-tls.c b/src/third_party/openssl/openssl/demos/easy_tls/easy-tls.c
index 5682e91..ebcadaf 100644
--- a/src/third_party/openssl/openssl/demos/easy_tls/easy-tls.c
+++ b/src/third_party/openssl/openssl/demos/easy_tls/easy-tls.c
@@ -1,4 +1,4 @@
-/* -*- Mode: C; c-file-style: "bsd" -*- */
+/* */
 /*-
  * easy-tls.c -- generic TLS proxy.
  * $Id: easy-tls.c,v 1.4 2002/03/05 09:07:16 bodo Exp $
diff --git a/src/third_party/openssl/openssl/demos/easy_tls/easy-tls.h b/src/third_party/openssl/openssl/demos/easy_tls/easy-tls.h
index 1c587b8..b88d21c 100644
--- a/src/third_party/openssl/openssl/demos/easy_tls/easy-tls.h
+++ b/src/third_party/openssl/openssl/demos/easy_tls/easy-tls.h
@@ -1,4 +1,4 @@
-/* -*- Mode: C; c-file-style: "bsd" -*- */
+/* */
 /*-
  * easy-tls.h -- generic TLS proxy.
  * $Id: easy-tls.h,v 1.1 2001/09/17 19:06:59 bodo Exp $
diff --git a/src/third_party/openssl/openssl/demos/engines/zencod/hw_zencod.c b/src/third_party/openssl/openssl/demos/engines/zencod/hw_zencod.c
index 0c0f524..daf0aef 100644
--- a/src/third_party/openssl/openssl/demos/engines/zencod/hw_zencod.c
+++ b/src/third_party/openssl/openssl/demos/engines/zencod/hw_zencod.c
@@ -610,7 +610,7 @@
     ptr_zencod_rc4_cipher = ptr_rc4_1;
 
     /*
-     * We should peform a test to see if there is actually any unit runnig on
+     * We should perform a test to see if there is actually any unit runnig on
      * the system ... Even if the cryptozen library is loaded the module coul
      * not be loaded on the system ... For now we may just open and close the
      * device !!
diff --git a/src/third_party/openssl/openssl/demos/tunala/tunala.c b/src/third_party/openssl/openssl/demos/tunala/tunala.c
index 11a7c5b..3ceea02 100644
--- a/src/third_party/openssl/openssl/demos/tunala/tunala.c
+++ b/src/third_party/openssl/openssl/demos/tunala/tunala.c
@@ -1154,7 +1154,7 @@
     /*
      * This function name is attributed to the term donated by David Schwartz
      * on openssl-dev, message-ID:
-     * <NCBBLIEPOCbmasEKBEAKEEDGLIAA.davids@webmaster.com>. :-)
+     * <NCBBLIEPOCNJOAEKBEAKEEDGLIAA.davids@webmaster.com>. :-)
      */
     if (!state_machine_churn(&item->sm))
         /*
diff --git a/src/third_party/openssl/openssl/doc/apps/ciphers.pod b/src/third_party/openssl/openssl/doc/apps/ciphers.pod
index 0aa1bad..0afe80d 100644
--- a/src/third_party/openssl/openssl/doc/apps/ciphers.pod
+++ b/src/third_party/openssl/openssl/doc/apps/ciphers.pod
@@ -205,7 +205,7 @@
 cipher suites using ephemeral ECDH key agreement, including anonymous
 cipher suites.
 
-=item B<EECDHE>
+=item B<EECDH>
 
 cipher suites using authenticated ephemeral ECDH key agreement.
 
diff --git a/src/third_party/openssl/openssl/doc/apps/dgst.pod b/src/third_party/openssl/openssl/doc/apps/dgst.pod
index 9e15798..b27bb94 100644
--- a/src/third_party/openssl/openssl/doc/apps/dgst.pod
+++ b/src/third_party/openssl/openssl/doc/apps/dgst.pod
@@ -13,7 +13,6 @@
 [B<-hex>]
 [B<-binary>]
 [B<-r>]
-[B<-hmac arg>]
 [B<-non-fips-allow>]
 [B<-out filename>]
 [B<-sign filename>]
@@ -64,10 +63,6 @@
 
 output the digest in the "coreutils" format used by programs like B<sha1sum>.
 
-=item B<-hmac arg>
-
-set the HMAC key to "arg".
-
 =item B<-non-fips-allow>
 
 Allow use of non FIPS digest when in FIPS mode.  This has no effect when not in
diff --git a/src/third_party/openssl/openssl/doc/apps/genrsa.pod b/src/third_party/openssl/openssl/doc/apps/genrsa.pod
index cb03d09..3dc9870 100644
--- a/src/third_party/openssl/openssl/doc/apps/genrsa.pod
+++ b/src/third_party/openssl/openssl/doc/apps/genrsa.pod
@@ -10,12 +10,6 @@
 [B<-out filename>]
 [B<-passout arg>]
 [B<-aes128>]
-[B<-aes128>]
-[B<-aes192>]
-[B<-aes256>]
-[B<-camellia128>]
-[B<-camellia192>]
-[B<-camellia256>]
 [B<-aes192>]
 [B<-aes256>]
 [B<-camellia128>]
diff --git a/src/third_party/openssl/openssl/doc/apps/req.pod b/src/third_party/openssl/openssl/doc/apps/req.pod
index 0730d11..37ed377 100644
--- a/src/third_party/openssl/openssl/doc/apps/req.pod
+++ b/src/third_party/openssl/openssl/doc/apps/req.pod
@@ -490,7 +490,7 @@
 The actual permitted field names are any object identifier short or
 long names. These are compiled into OpenSSL and include the usual
 values such as commonName, countryName, localityName, organizationName,
-organizationUnitName, stateOrProvinceName. Additionally emailAddress
+organizationalUnitName, stateOrProvinceName. Additionally emailAddress
 is include as well as name, surname, givenName initials and dnQualifier.
 
 Additional object identifiers can be defined with the B<oid_file> or
diff --git a/src/third_party/openssl/openssl/doc/apps/s_time.pod b/src/third_party/openssl/openssl/doc/apps/s_time.pod
index 5a38aa2..9082d87 100644
--- a/src/third_party/openssl/openssl/doc/apps/s_time.pod
+++ b/src/third_party/openssl/openssl/doc/apps/s_time.pod
@@ -26,7 +26,7 @@
 
 =head1 DESCRIPTION
 
-The B<s_client> command implements a generic SSL/TLS client which connects to a
+The B<s_time> command implements a generic SSL/TLS client which connects to a
 remote host using SSL/TLS. It can request a page from the server and includes
 the time to transfer the payload data in its timing measurements. It measures
 the number of connections within a given timeframe, the amount of data
@@ -127,7 +127,7 @@
 
 =head1 NOTES
 
-B<s_client> can be used to measure the performance of an SSL connection.
+B<s_time> can be used to measure the performance of an SSL connection.
 To connect to an SSL HTTP server and get the default page the command
 
  openssl s_time -connect servername:443 -www / -CApath yourdir -CAfile yourfile.pem -cipher commoncipher [-ssl3]
diff --git a/src/third_party/openssl/openssl/doc/apps/x509.pod b/src/third_party/openssl/openssl/doc/apps/x509.pod
index 6109389..1bb0550 100644
--- a/src/third_party/openssl/openssl/doc/apps/x509.pod
+++ b/src/third_party/openssl/openssl/doc/apps/x509.pod
@@ -529,7 +529,8 @@
 "space" additionally place a space after the separator to make it
 more readable. The B<sep_multiline> uses a linefeed character for
 the RDN separator and a spaced B<+> for the AVA separator. It also
-indents the fields by four characters.
+indents the fields by four characters. If no field separator is specified
+then B<sep_comma_plus_space> is used by default.
 
 =item B<dn_rev>
 
diff --git a/src/third_party/openssl/openssl/doc/crypto/BIO_read.pod b/src/third_party/openssl/openssl/doc/crypto/BIO_read.pod
index b345281..2c177f0 100644
--- a/src/third_party/openssl/openssl/doc/crypto/BIO_read.pod
+++ b/src/third_party/openssl/openssl/doc/crypto/BIO_read.pod
@@ -9,9 +9,9 @@
  #include <openssl/bio.h>
 
  int	BIO_read(BIO *b, void *buf, int len);
- int	BIO_gets(BIO *b,char *buf, int size);
+ int	BIO_gets(BIO *b, char *buf, int size);
  int	BIO_write(BIO *b, const void *buf, int len);
- int	BIO_puts(BIO *b,const char *buf);
+ int	BIO_puts(BIO *b, const char *buf);
 
 =head1 DESCRIPTION
 
@@ -26,7 +26,7 @@
 
 BIO_write() attempts to write B<len> bytes from B<buf> to BIO B<b>.
 
-BIO_puts() attempts to write a null terminated string B<buf> to BIO B<b>
+BIO_puts() attempts to write a null terminated string B<buf> to BIO B<b>.
 
 =head1 RETURN VALUES
 
diff --git a/src/third_party/openssl/openssl/doc/crypto/BIO_s_connect.pod b/src/third_party/openssl/openssl/doc/crypto/BIO_s_connect.pod
index bcf7d8d..e238aee 100644
--- a/src/third_party/openssl/openssl/doc/crypto/BIO_s_connect.pod
+++ b/src/third_party/openssl/openssl/doc/crypto/BIO_s_connect.pod
@@ -21,8 +21,8 @@
  long BIO_set_conn_int_port(BIO *b, char *port);
  char *BIO_get_conn_hostname(BIO *b);
  char *BIO_get_conn_port(BIO *b);
- char *BIO_get_conn_ip(BIO *b, dummy);
- long BIO_get_conn_int_port(BIO *b, int port);
+ char *BIO_get_conn_ip(BIO *b);
+ long BIO_get_conn_int_port(BIO *b);
 
  long BIO_set_nbio(BIO *b, long n);
 
diff --git a/src/third_party/openssl/openssl/doc/crypto/BN_rand.pod b/src/third_party/openssl/openssl/doc/crypto/BN_rand.pod
index 3b2796c..fde5f72 100644
--- a/src/third_party/openssl/openssl/doc/crypto/BN_rand.pod
+++ b/src/third_party/openssl/openssl/doc/crypto/BN_rand.pod
@@ -19,7 +19,7 @@
 =head1 DESCRIPTION
 
 BN_rand() generates a cryptographically strong pseudo-random number of
-B<bits> bits in length and stores it in B<rnd>. If B<top> is -1, the
+B<bits> in length and stores it in B<rnd>. If B<top> is -1, the
 most significant bit of the random number can be zero. If B<top> is 0,
 it is set to 1, and if B<top> is 1, the two most significant bits of
 the number will be set to 1, so that the product of two such random
@@ -33,7 +33,7 @@
 protocols, but usually not for key generation etc.
 
 BN_rand_range() generates a cryptographically strong pseudo-random
-number B<rnd> in the range 0 <lt>= B<rnd> E<lt> B<range>.
+number B<rnd> in the range 0 E<lt>= B<rnd> E<lt> B<range>.
 BN_pseudo_rand_range() does the same, but is based on BN_pseudo_rand(),
 and hence numbers generated by it are not necessarily unpredictable.
 
diff --git a/src/third_party/openssl/openssl/doc/crypto/DSA_generate_parameters.pod b/src/third_party/openssl/openssl/doc/crypto/DSA_generate_parameters.pod
index be7c924..f24c9c7 100644
--- a/src/third_party/openssl/openssl/doc/crypto/DSA_generate_parameters.pod
+++ b/src/third_party/openssl/openssl/doc/crypto/DSA_generate_parameters.pod
@@ -23,7 +23,7 @@
 If B<seed> is B<NULL> or B<seed_len> E<lt> 20, the primes will be
 generated at random. Otherwise, the seed is used to generate
 them. If the given seed does not yield a prime q, a new random
-seed is chosen and placed at B<seed>.
+seed is chosen.
 
 DSA_generate_parameters() places the iteration count in
 *B<counter_ret> and a counter used for finding a generator in
diff --git a/src/third_party/openssl/openssl/doc/crypto/EVP_DigestVerifyInit.pod b/src/third_party/openssl/openssl/doc/crypto/EVP_DigestVerifyInit.pod
index cfeccd9..54cad92 100644
--- a/src/third_party/openssl/openssl/doc/crypto/EVP_DigestVerifyInit.pod
+++ b/src/third_party/openssl/openssl/doc/crypto/EVP_DigestVerifyInit.pod
@@ -37,10 +37,11 @@
 or a negative value for failure. In particular a return value of -2 indicates
 the operation is not supported by the public key algorithm.
 
-Unlike other functions the return value 0 from EVP_DigestVerifyFinal() only
-indicates that the signature did not verify successfully (that is tbs did
-not match the original data or the signature was of invalid form) it is not an
-indication of a more serious error.
+EVP_DigestVerifyFinal() returns 1 for success; any other value indicates
+failure.  A return value of zero indicates that the signature did not verify
+successfully (that is, tbs did not match the original data or the signature had
+an invalid form), while other values indicate a more serious error (and
+sometimes also indicate an invalid signature form).
 
 The error codes can be obtained from L<ERR_get_error(3)|ERR_get_error(3)>.
 
diff --git a/src/third_party/openssl/openssl/doc/crypto/EVP_SignInit.pod b/src/third_party/openssl/openssl/doc/crypto/EVP_SignInit.pod
index 14ecc77..c63d6b3 100644
--- a/src/third_party/openssl/openssl/doc/crypto/EVP_SignInit.pod
+++ b/src/third_party/openssl/openssl/doc/crypto/EVP_SignInit.pod
@@ -2,7 +2,8 @@
 
 =head1 NAME
 
-EVP_SignInit, EVP_SignUpdate, EVP_SignFinal - EVP signing functions
+EVP_SignInit, EVP_SignInit_ex, EVP_SignUpdate, EVP_SignFinal - EVP signing
+functions
 
 =head1 SYNOPSIS
 
diff --git a/src/third_party/openssl/openssl/doc/crypto/buffer.pod b/src/third_party/openssl/openssl/doc/crypto/buffer.pod
index 781f5b1..9d6de53 100644
--- a/src/third_party/openssl/openssl/doc/crypto/buffer.pod
+++ b/src/third_party/openssl/openssl/doc/crypto/buffer.pod
@@ -2,8 +2,11 @@
 
 =head1 NAME
 
-BUF_MEM_new, BUF_MEM_free, BUF_MEM_grow, BUF_strdup - simple
-character arrays structure
+BUF_MEM_new, BUF_MEM_new_ex, BUF_MEM_free, BUF_MEM_grow - simple
+character array structure
+
+BUF_strdup, BUF_strndup, BUF_memdup, BUF_strlcpy, BUF_strlcat -
+standard C library equivalents
 
 =head1 SYNOPSIS
 
@@ -15,26 +18,21 @@
 
  int	BUF_MEM_grow(BUF_MEM *str, int len);
 
- char *	BUF_strdup(const char *str);
+ char *BUF_strdup(const char *str);
+
+ char *BUF_strndup(const char *str, size_t siz);
+
+ void *BUF_memdup(const void *data, size_t siz);
+
+ size_t BUF_strlcpy(char *dst, const char *src, size_t size);
+
+ size_t BUF_strlcat(char *dst, const char *src, size_t size);
 
 =head1 DESCRIPTION
 
 The buffer library handles simple character arrays. Buffers are used for
 various purposes in the library, most notably memory BIOs.
 
-The library uses the BUF_MEM structure defined in buffer.h:
-
- typedef struct buf_mem_st
- {
-        int length;     /* current number of bytes */
-        char *data;
-        int max;        /* size of buffer */
- } BUF_MEM;
-
-B<length> is the current size of the buffer in bytes, B<max> is the amount of
-memory allocated to the buffer. There are three functions which handle these
-and one "miscellaneous" function.
-
 BUF_MEM_new() allocates a new buffer of zero size.
 
 BUF_MEM_free() frees up an already existing buffer. The data is zeroed
@@ -44,14 +42,17 @@
 B<len>. Any data already in the buffer is preserved if it increases in
 size.
 
-BUF_strdup() copies a null terminated string into a block of allocated
-memory and returns a pointer to the allocated block.
-Unlike the standard C library strdup() this function uses OPENSSL_malloc() and so
-should be used in preference to the standard library strdup() because it can
-be used for memory leak checking or replacing the malloc() function.
+BUF_strdup(), BUF_strndup(), BUF_memdup(), BUF_strlcpy() and
+BUF_strlcat() are equivalents of the standard C library functions. The
+dup() functions use OPENSSL_malloc() underneath and so should be used
+in preference to the standard library for memory leak checking or
+replacing the malloc() function.
 
-The memory allocated from BUF_strdup() should be freed up using the OPENSSL_free()
-function.
+Memory allocated from these functions should be freed up using the
+OPENSSL_free() function.
+
+BUF_strndup makes the explicit guarantee that it will never read past
+the first B<siz> bytes of B<str>.
 
 =head1 RETURN VALUES
 
diff --git a/src/third_party/openssl/openssl/doc/crypto/d2i_X509_NAME.pod b/src/third_party/openssl/openssl/doc/crypto/d2i_X509_NAME.pod
index 343ffe1..b025de7 100644
--- a/src/third_party/openssl/openssl/doc/crypto/d2i_X509_NAME.pod
+++ b/src/third_party/openssl/openssl/doc/crypto/d2i_X509_NAME.pod
@@ -14,7 +14,7 @@
 =head1 DESCRIPTION
 
 These functions decode and encode an B<X509_NAME> structure which is the
-the same as the B<Name> type defined in RFC2459 (and elsewhere) and used
+same as the B<Name> type defined in RFC2459 (and elsewhere) and used
 for example in certificate subject and issuer names.
 
 Othewise the functions behave in a similar way to d2i_X509() and i2d_X509()
diff --git a/src/third_party/openssl/openssl/doc/dir-locals.example.el b/src/third_party/openssl/openssl/doc/dir-locals.example.el
new file mode 100644
index 0000000..79d0b01
--- /dev/null
+++ b/src/third_party/openssl/openssl/doc/dir-locals.example.el
@@ -0,0 +1,15 @@
+;;; This is an example of what a .dir-locals.el suitable for OpenSSL
+;;; development could look like.
+;;;
+;;; Apart from setting the CC mode style to "OpenSSL-II", it also
+;;; makes sure that tabs are never used for indentation in any file,
+;;; and that the fill column is 78.
+;;;
+;;; For more information see (info "(emacs) Directory Variables")
+
+((nil
+  (indent-tabs-mode . nil)
+  (fill-column . 78)
+  )
+ (c-mode
+  (c-file-style . "OpenSSL-II")))
diff --git a/src/third_party/openssl/openssl/doc/openssl-c-indent.el b/src/third_party/openssl/openssl/doc/openssl-c-indent.el
new file mode 100644
index 0000000..144a915
--- /dev/null
+++ b/src/third_party/openssl/openssl/doc/openssl-c-indent.el
@@ -0,0 +1,62 @@
+;;; This Emacs Lisp file defines a C indentation style for OpenSSL.
+;;;
+;;; This definition is for the "CC mode" package, which is the default
+;;; mode for editing C source files in Emacs 20, not for the older
+;;; c-mode.el (which was the default in less recent releaes of Emacs 19).
+;;;
+;;; Recommended use is to add this line in your .emacs:
+;;;
+;;;   (load (expand-file-name "~/PATH/TO/openssl-c-indent.el"))
+;;;
+;;; To activate this indentation style, visit a C file, type
+;;; M-x c-set-style <RET> (or C-c . for short), and enter "eay".
+;;; To toggle the auto-newline feature of CC mode, type C-c C-a.
+;;;
+;;; If you're a OpenSSL developer, you might find it more comfortable
+;;; to have this style be permanent in your OpenSSL development
+;;; directory.  To have that, please perform this:
+;;;
+;;;    M-x add-dir-local-variable <RET> c-mode <RET> c-file-style <RET>
+;;;    "OpenSSL-II" <RET>
+;;;
+;;; A new buffer with .dir-locals.el will appear.  Save it (C-x C-s).
+;;;
+;;; Alternatively, have a look at dir-locals.example.el
+
+;;; For suggesting improvements, please send e-mail to levitte@openssl.org.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Note, it could be easy to inherit from the "gnu" style...  however,
+;; one never knows if that style will change somewhere in the future,
+;; so I've chosen to copy the "gnu" style values explicitely instead
+;; and mark them with a comment.                // RLevitte 2015-08-31
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(c-add-style "OpenSSL-II"
+             '((c-basic-offset . 4)
+               (indent-tabs-mode . nil)
+               (fill-column . 78)
+               (comment-column . 33)
+               (c-comment-only-line-offset 0 . 0)            ; From "gnu" style
+               (c-hanging-braces-alist                       ; From "gnu" style
+                (substatement-open before after)             ; From "gnu" style
+                (arglist-cont-nonempty))                     ; From "gnu" style
+               (c-offsets-alist
+                (statement-block-intro . +)                  ; From "gnu" style
+                (knr-argdecl-intro . 0)
+                (knr-argdecl . 0)
+                (substatement-open . +)                      ; From "gnu" style
+                (substatement-label . 0)                     ; From "gnu" style
+                (label . 1)
+                (statement-case-open . +)                    ; From "gnu" style
+                (statement-cont . +)                         ; From "gnu" style
+                (arglist-intro . c-lineup-arglist-intro-after-paren) ; From "gnu" style
+                (arglist-close . c-lineup-arglist)           ; From "gnu" style
+                (inline-open . 0)                            ; From "gnu" style
+                (brace-list-open . +)                        ; From "gnu" style
+                (topmost-intro-cont first c-lineup-topmost-intro-cont
+                                    c-lineup-gnu-DEFUN-intro-cont) ; From "gnu" style
+                )
+               (c-special-indent-hook . c-gnu-impose-minimum) ; From "gnu" style
+               (c-block-comment-prefix . "* ")
+               ))
diff --git a/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_add_extra_chain_cert.pod b/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_add_extra_chain_cert.pod
index 5955ee1..18fb2e2 100644
--- a/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_add_extra_chain_cert.pod
+++ b/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_add_extra_chain_cert.pod
@@ -2,29 +2,39 @@
 
 =head1 NAME
 
-SSL_CTX_add_extra_chain_cert - add certificate to chain
+SSL_CTX_add_extra_chain_cert, SSL_CTX_clear_extra_chain_certs - add or clear
+extra chain certificates
 
 =head1 SYNOPSIS
 
  #include <openssl/ssl.h>
 
- long SSL_CTX_add_extra_chain_cert(SSL_CTX ctx, X509 *x509)
+ long SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509);
+ long SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx);
 
 =head1 DESCRIPTION
 
-SSL_CTX_add_extra_chain_cert() adds the certificate B<x509> to the certificate
-chain presented together with the certificate. Several certificates
-can be added one after the other.
+SSL_CTX_add_extra_chain_cert() adds the certificate B<x509> to the extra chain
+certificates associated with B<ctx>. Several certificates can be added one
+after another.
+
+SSL_CTX_clear_extra_chain_certs() clears all extra chain certificates
+associated with B<ctx>.
+
+These functions are implemented as macros.
 
 =head1 NOTES
 
-When constructing the certificate chain, the chain will be formed from
-these certificates explicitly specified. If no chain is specified,
-the library will try to complete the chain from the available CA
-certificates in the trusted CA storage, see
+When sending a certificate chain, extra chain certificates are sent in order
+following the end entity certificate.
+
+If no chain is specified, the library will try to complete the chain from the
+available CA certificates in the trusted CA storage, see
 L<SSL_CTX_load_verify_locations(3)|SSL_CTX_load_verify_locations(3)>.
 
-The B<x509> certificate provided to SSL_CTX_add_extra_chain_cert() will be freed by the library when the B<SSL_CTX> is destroyed. An application B<should not> free the B<x509> object.
+The B<x509> certificate provided to SSL_CTX_add_extra_chain_cert() will be
+freed by the library when the B<SSL_CTX> is destroyed. An application
+B<should not> free the B<x509> object.
 
 =head1 RESTRICTIONS
 
@@ -36,8 +46,9 @@
 
 =head1 RETURN VALUES
 
-SSL_CTX_add_extra_chain_cert() returns 1 on success. Check out the
-error stack to find out the reason for failure otherwise.
+SSL_CTX_add_extra_chain_cert() and SSL_CTX_clear_extra_chain_certs() return
+1 on success and 0 for failure. Check out the error stack to find out the
+reason for failure.
 
 =head1 SEE ALSO
 
diff --git a/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_set_tlsext_status_cb.pod b/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_set_tlsext_status_cb.pod
new file mode 100644
index 0000000..b8147ba
--- /dev/null
+++ b/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_set_tlsext_status_cb.pod
@@ -0,0 +1,73 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_tlsext_status_cb, SSL_CTX_set_tlsext_status_arg,
+SSL_set_tlsext_status_type, SSL_get_tlsext_status_ocsp_resp,
+SSL_set_tlsext_status_ocsp_resp - OCSP Certificate Status Request functions
+
+=head1 SYNOPSIS
+
+ #include <openssl/tls1.h>
+
+ long SSL_CTX_set_tlsext_status_cb(SSL_CTX *ctx,
+                                   int (*callback)(SSL *, void *));
+ long SSL_CTX_set_tlsext_status_arg(SSL_CTX *ctx, void *arg);
+
+ long SSL_set_tlsext_status_type(SSL *s, int type);
+
+ long SSL_get_tlsext_status_ocsp_resp(ssl, unsigned char **resp);
+ long SSL_set_tlsext_status_ocsp_resp(ssl, unsigned char *resp, int len);
+
+=head1 DESCRIPTION
+
+A client application may request that a server send back an OCSP status response
+(also known as OCSP stapling). To do so the client should call the
+SSL_set_tlsext_status_type() function prior to the start of the handshake.
+Currently the only supported type is B<TLSEXT_STATUSTYPE_ocsp>. This value
+should be passed in the B<type> argument. The client should additionally provide
+a callback function to decide what to do with the returned OCSP response by
+calling SSL_CTX_set_tlsext_status_cb(). The callback function should determine
+whether the returned OCSP response is acceptable or not. The callback will be
+passed as an argument the value previously set via a call to
+SSL_CTX_set_tlsext_status_arg(). Note that the callback will not be called in
+the event of a handshake where session resumption occurs (because there are no
+Certificates exchanged in such a handshake).
+
+The response returned by the server can be obtained via a call to
+SSL_get_tlsext_status_ocsp_resp(). The value B<*resp> will be updated to point
+to the OCSP response data and the return value will be the length of that data.
+Typically a callback would obtain an OCSP_RESPONSE object from this data via a
+call to the d2i_OCSP_RESPONSE() function. If the server has not provided any
+response data then B<*resp> will be NULL and the return value from
+SSL_get_tlsext_status_ocsp_resp() will be -1.
+
+A server application must also call the SSL_CTX_set_tlsext_status_cb() function
+if it wants to be able to provide clients with OCSP Certificate Status
+responses. Typically the server callback would obtain the server certificate
+that is being sent back to the client via a call to SSL_get_certificate();
+obtain the OCSP response to be sent back; and then set that response data by
+calling SSL_set_tlsext_status_ocsp_resp(). A pointer to the response data should
+be provided in the B<resp> argument, and the length of that data should be in
+the B<len> argument.
+
+=head1 RETURN VALUES
+
+The callback when used on the client side should return a negative value on
+error; 0 if the response is not acceptable (in which case the handshake will
+fail) or a positive value if it is acceptable.
+
+The callback when used on the server side should return with either
+SSL_TLSEXT_ERR_OK (meaning that the OCSP response that has been set should be
+returned), SSL_TLSEXT_ERR_NOACK (meaning that an OCSP response should not be
+returned) or SSL_TLSEXT_ERR_ALERT_FATAL (meaning that a fatal error has
+occurred).
+
+SSL_CTX_set_tlsext_status_cb(), SSL_CTX_set_tlsext_status_arg(),
+SSL_set_tlsext_status_type() and SSL_set_tlsext_status_ocsp_resp() return 0 on
+error or 1 on success.
+
+SSL_get_tlsext_status_ocsp_resp() returns the length of the OCSP response data
+or -1 if there is no OCSP response data.
+
+=cut
diff --git a/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_set_tmp_dh_callback.pod b/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_set_tmp_dh_callback.pod
index b754c16..234fbc8 100644
--- a/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_set_tmp_dh_callback.pod
+++ b/src/third_party/openssl/openssl/doc/ssl/SSL_CTX_set_tmp_dh_callback.pod
@@ -48,25 +48,8 @@
 only used for signing.
 
 In order to perform a DH key exchange the server must use a DH group
-(DH parameters) and generate a DH key.
-The server will always generate a new DH key during the negotiation
-if either the DH parameters are supplied via callback or the
-SSL_OP_SINGLE_DH_USE option of SSL_CTX_set_options(3) is set (or both).
-It will  immediately create a DH key if DH parameters are supplied via
-SSL_CTX_set_tmp_dh() and SSL_OP_SINGLE_DH_USE is not set.
-In this case,
-it may happen that a key is generated on initialization without later
-being needed, while on the other hand the computer time during the
-negotiation is being saved.
-
-If "strong" primes were used to generate the DH parameters, it is not strictly
-necessary to generate a new key for each handshake but it does improve forward
-secrecy. If it is not assured that "strong" primes were used,
-SSL_OP_SINGLE_DH_USE must be used in order to prevent small subgroup
-attacks. Always using SSL_OP_SINGLE_DH_USE has an impact on the
-computer time needed during negotiation, but it is not very large, so
-application authors/users should consider always enabling this option.
-The option is required to implement perfect forward secrecy (PFS).
+(DH parameters) and generate a DH key. The server will always generate
+a new DH key during the negotiation.
 
 As generating DH parameters is extremely time consuming, an application
 should not generate the parameters on the fly but supply the parameters.
@@ -93,10 +76,9 @@
 Previous versions of the callback used B<is_export> and B<keylength>
 parameters to control parameter generation for export and non-export
 cipher suites. Modern servers that do not support export ciphersuites
-are advised to either use SSL_CTX_set_tmp_dh() in combination with
-SSL_OP_SINGLE_DH_USE, or alternatively, use the callback but ignore
-B<keylength> and B<is_export> and simply supply at least 2048-bit
-parameters in the callback.
+are advised to either use SSL_CTX_set_tmp_dh() or alternatively, use
+the callback but ignore B<keylength> and B<is_export> and simply
+supply at least 2048-bit parameters in the callback.
 
 =head1 EXAMPLES
 
@@ -128,7 +110,6 @@
  if (SSL_CTX_set_tmp_dh(ctx, dh_2048) != 1) {
    /* Error. */
  }
- SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
  ...
 
 =head1 RETURN VALUES
diff --git a/src/third_party/openssl/openssl/e_os.h b/src/third_party/openssl/openssl/e_os.h
index c86a1e4..8f67237 100644
--- a/src/third_party/openssl/openssl/e_os.h
+++ b/src/third_party/openssl/openssl/e_os.h
@@ -326,7 +326,7 @@
 #    undef isxdigit
 #   endif
 #   if defined(_MSC_VER) && !defined(_DLL) && defined(stdin)
-#    if _MSC_VER>=1300
+#    if _MSC_VER>=1300 && _MSC_VER<1600
 #     undef stdin
 #     undef stdout
 #     undef stderr
@@ -334,7 +334,7 @@
 #     define stdin  (&__iob_func()[0])
 #     define stdout (&__iob_func()[1])
 #     define stderr (&__iob_func()[2])
-#    elif defined(I_CAN_LIVE_WITH_LNK4049)
+#    elif _MSC_VER<1300 && defined(I_CAN_LIVE_WITH_LNK4049)
 #     undef stdin
 #     undef stdout
 #     undef stderr
@@ -625,7 +625,7 @@
 #    include <sys/select.h>
 #   endif
 
-#   if defined(sun)
+#   if defined(__sun) || defined(sun)
 #    include <sys/filio.h>
 #   else
 #    ifndef VMS
@@ -667,7 +667,7 @@
 
 # endif
 
-# if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
+# if (defined(__sun) || defined(sun)) && !defined(__svr4__) && !defined(__SVR4)
   /* include headers first, so our defines don't break it */
 #  include <stdlib.h>
 #  include <string.h>
diff --git a/src/third_party/openssl/openssl/engines/e_chil.c b/src/third_party/openssl/openssl/engines/e_chil.c
index 69d49d7..5dfab51 100644
--- a/src/third_party/openssl/openssl/engines/e_chil.c
+++ b/src/third_party/openssl/openssl/engines/e_chil.c
@@ -1,4 +1,4 @@
-/* crypto/engine/e_chil.c -*- mode: C; c-file-style: "eay" -*- */
+/* crypto/engine/e_chil.c */
 /*
  * Written by Richard Levitte (richard@levitte.org), Geoff Thorpe
  * (geoff@geoffthorpe.net) and Dr Stephen N Henson (steve@openssl.org) for
@@ -839,6 +839,10 @@
     bn_fix_top(rtmp->n);
 
     res = EVP_PKEY_new();
+    if (res == NULL) {
+        HWCRHKerr(HWCRHK_F_HWCRHK_LOAD_PRIVKEY, HWCRHK_R_CHIL_ERROR);
+        goto err;
+    }
     EVP_PKEY_assign_RSA(res, rtmp);
 #  endif
 
diff --git a/src/third_party/openssl/openssl/openssl.spec b/src/third_party/openssl/openssl/openssl.spec
index 67a6074..386f9f6 100644
--- a/src/third_party/openssl/openssl/openssl.spec
+++ b/src/third_party/openssl/openssl/openssl.spec
@@ -7,7 +7,7 @@
 Summary: Secure Sockets Layer and cryptography libraries and tools
 Name: openssl
 #Version: %{libmaj}.%{libmin}.%{librel}
-Version: 1.0.1p
+Version: 1.0.1r
 Source0: ftp://ftp.openssl.org/source/%{name}-%{version}.tar.gz
 License: OpenSSL
 Group: System Environment/Libraries
diff --git a/src/third_party/openssl/openssl/ssl/Makefile b/src/third_party/openssl/openssl/ssl/Makefile
index 29d9e45..ad14abb 100644
--- a/src/third_party/openssl/openssl/ssl/Makefile
+++ b/src/third_party/openssl/openssl/ssl/Makefile
@@ -15,7 +15,7 @@
 CFLAGS= $(INCLUDES) $(CFLAG)
 
 GENERAL=Makefile README ssl-lib.com install.com
-TEST=ssltest.c heartbeat_test.c
+TEST=ssltest.c heartbeat_test.c clienthellotest.c
 APPS=
 
 LIB=$(TOP)/libssl.a
diff --git a/src/third_party/openssl/openssl/ssl/bio_ssl.c b/src/third_party/openssl/openssl/ssl/bio_ssl.c
index 02de512..231ba55 100644
--- a/src/third_party/openssl/openssl/ssl/bio_ssl.c
+++ b/src/third_party/openssl/openssl/ssl/bio_ssl.c
@@ -422,6 +422,10 @@
             BIO_set_flags(b, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY);
             b->retry_reason = b->next_bio->retry_reason;
             break;
+        case SSL_ERROR_WANT_X509_LOOKUP:
+            BIO_set_retry_special(b);
+            b->retry_reason = BIO_RR_SSL_X509_LOOKUP;
+            break;
         default:
             break;
         }
diff --git a/src/third_party/openssl/openssl/ssl/clienthellotest.c b/src/third_party/openssl/openssl/ssl/clienthellotest.c
new file mode 100644
index 0000000..a00a7ea
--- /dev/null
+++ b/src/third_party/openssl/openssl/ssl/clienthellotest.c
@@ -0,0 +1,218 @@
+/* Written by Matt Caswell for the OpenSSL Project */
+/* ====================================================================
+ * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+
+#define CLIENT_VERSION_LEN      2
+#define SESSION_ID_LEN_LEN      1
+#define CIPHERS_LEN_LEN         2
+#define COMPRESSION_LEN_LEN     1
+#define EXTENSIONS_LEN_LEN      2
+#define EXTENSION_TYPE_LEN      2
+#define EXTENSION_SIZE_LEN      2
+
+
+#define TOTAL_NUM_TESTS                         2
+
+/*
+ * Test that explicitly setting ticket data results in it appearing in the
+ * ClientHello for TLS1.2
+ */
+#define TEST_SET_SESSION_TICK_DATA_TLS_1_2      0
+
+/*
+ * Test that explicitly setting ticket data results in it appearing in the
+ * ClientHello for a negotiated SSL/TLS version
+ */
+#define TEST_SET_SESSION_TICK_DATA_VER_NEG      1
+
+int main(int argc, char *argv[])
+{
+    SSL_CTX *ctx;
+    SSL *con;
+    BIO *rbio;
+    BIO *wbio;
+    BIO *err;
+    long len;
+    unsigned char *data;
+    unsigned char *dataend;
+    char *dummytick = "Hello World!";
+    unsigned int tmplen;
+    unsigned int type;
+    unsigned int size;
+    int testresult = 0;
+    int currtest = 0;
+
+    SSL_library_init();
+    SSL_load_error_strings();
+
+    err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+
+    CRYPTO_malloc_debug_init();
+    CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
+    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+
+    /*
+     * For each test set up an SSL_CTX and SSL and see what ClientHello gets
+     * produced when we try to connect
+     */
+    for (; currtest < TOTAL_NUM_TESTS; currtest++) {
+        testresult = 0;
+        if (currtest == TEST_SET_SESSION_TICK_DATA_TLS_1_2) {
+            ctx = SSL_CTX_new(TLSv1_2_method());
+        } else {
+            ctx = SSL_CTX_new(SSLv23_method());
+        }
+        con = SSL_new(ctx);
+
+        rbio = BIO_new(BIO_s_mem());
+        wbio = BIO_new(BIO_s_mem());
+        SSL_set_bio(con, rbio, wbio);
+        SSL_set_connect_state(con);
+
+        if (currtest == TEST_SET_SESSION_TICK_DATA_TLS_1_2
+                || currtest == TEST_SET_SESSION_TICK_DATA_VER_NEG) {
+            if (!SSL_set_session_ticket_ext(con, dummytick, strlen(dummytick)))
+                goto end;
+        }
+
+        if (SSL_connect(con) > 0) {
+            /* This shouldn't succeed because we don't have a server! */
+            goto end;
+        }
+
+        len = BIO_get_mem_data(wbio, (char **)&data);
+        dataend = data + len;
+
+        /* Skip the record header */
+        data += SSL3_RT_HEADER_LENGTH;
+        /* Skip the handshake message header */
+        data += SSL3_HM_HEADER_LENGTH;
+        /* Skip client version and random */
+        data += CLIENT_VERSION_LEN + SSL3_RANDOM_SIZE;
+        if (data + SESSION_ID_LEN_LEN > dataend)
+            goto end;
+        /* Skip session id */
+        tmplen = *data;
+        data += SESSION_ID_LEN_LEN + tmplen;
+        if (data + CIPHERS_LEN_LEN > dataend)
+            goto end;
+        /* Skip ciphers */
+        tmplen = ((*data) << 8) | *(data + 1);
+        data += CIPHERS_LEN_LEN + tmplen;
+        if (data + COMPRESSION_LEN_LEN > dataend)
+            goto end;
+        /* Skip compression */
+        tmplen = *data;
+        data += COMPRESSION_LEN_LEN + tmplen;
+        if (data + EXTENSIONS_LEN_LEN > dataend)
+            goto end;
+        /* Extensions len */
+        tmplen = ((*data) << 8) | *(data + 1);
+        data += EXTENSIONS_LEN_LEN;
+        if (data + tmplen > dataend)
+            goto end;
+
+        /* Loop through all extensions */
+        while (tmplen > EXTENSION_TYPE_LEN + EXTENSION_SIZE_LEN) {
+            type = ((*data) << 8) | *(data + 1);
+            data += EXTENSION_TYPE_LEN;
+            size = ((*data) << 8) | *(data + 1);
+            data += EXTENSION_SIZE_LEN;
+            if (data + size > dataend)
+                goto end;
+
+            if (type == TLSEXT_TYPE_session_ticket) {
+                if (currtest == TEST_SET_SESSION_TICK_DATA_TLS_1_2
+                        || currtest == TEST_SET_SESSION_TICK_DATA_VER_NEG) {
+                    if (size == strlen(dummytick)
+                            && memcmp(data, dummytick, size) == 0) {
+                        /* Ticket data is as we expected */
+                        testresult = 1;
+                    } else {
+                        printf("Received session ticket is not as expected\n");
+                    }
+                    break;
+                }
+            }
+
+            tmplen -= EXTENSION_TYPE_LEN + EXTENSION_SIZE_LEN + size;
+            data += size;
+        }
+
+ end:
+        SSL_free(con);
+        SSL_CTX_free(ctx);
+        if (!testresult) {
+            printf("ClientHello test: FAILED (Test %d)\n", currtest);
+            break;
+        }
+    }
+
+    ERR_free_strings();
+    ERR_remove_thread_state(NULL);
+    EVP_cleanup();
+    CRYPTO_cleanup_all_ex_data();
+    CRYPTO_mem_leaks(err);
+
+    return testresult?0:1;
+}
diff --git a/src/third_party/openssl/openssl/ssl/d1_both.c b/src/third_party/openssl/openssl/ssl/d1_both.c
index 8dd8ea3..aaa1867 100644
--- a/src/third_party/openssl/openssl/ssl/d1_both.c
+++ b/src/third_party/openssl/openssl/ssl/d1_both.c
@@ -291,8 +291,44 @@
         blocksize = 0;
 
     frag_off = 0;
+    s->rwstate = SSL_NOTHING;
+
     /* s->init_num shouldn't ever be < 0...but just in case */
     while (s->init_num > 0) {
+        if (type == SSL3_RT_HANDSHAKE && s->init_off != 0) {
+            /* We must be writing a fragment other than the first one */
+
+            if (frag_off > 0) {
+                /* This is the first attempt at writing out this fragment */
+
+                if (s->init_off <= DTLS1_HM_HEADER_LENGTH) {
+                    /*
+                     * Each fragment that was already sent must at least have
+                     * contained the message header plus one other byte.
+                     * Therefore |init_off| must have progressed by at least
+                     * |DTLS1_HM_HEADER_LENGTH + 1| bytes. If not something went
+                     * wrong.
+                     */
+                    return -1;
+                }
+
+                /*
+                 * Adjust |init_off| and |init_num| to allow room for a new
+                 * message header for this fragment.
+                 */
+                s->init_off -= DTLS1_HM_HEADER_LENGTH;
+                s->init_num += DTLS1_HM_HEADER_LENGTH;
+            } else {
+                /*
+                 * We must have been called again after a retry so use the
+                 * fragment offset from our last attempt. We do not need
+                 * to adjust |init_off| and |init_num| as above, because
+                 * that should already have been done before the retry.
+                 */
+                frag_off = s->d1->w_msg_hdr.frag_off;
+            }
+        }
+
         used_len = BIO_wpending(SSL_get_wbio(s)) + DTLS1_RT_HEADER_LENGTH
             + mac_size + blocksize;
         if (s->d1->mtu > used_len)
@@ -305,8 +341,10 @@
              * grr.. we could get an error if MTU picked was wrong
              */
             ret = BIO_flush(SSL_get_wbio(s));
-            if (ret <= 0)
+            if (ret <= 0) {
+                s->rwstate = SSL_WRITING;
                 return ret;
+            }
             used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize;
             if (s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) {
                 curr_mtu = s->d1->mtu - used_len;
@@ -332,25 +370,6 @@
          * XDTLS: this function is too long.  split out the CCS part
          */
         if (type == SSL3_RT_HANDSHAKE) {
-            if (s->init_off != 0) {
-                OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH);
-                s->init_off -= DTLS1_HM_HEADER_LENGTH;
-                s->init_num += DTLS1_HM_HEADER_LENGTH;
-
-                /*
-                 * We just checked that s->init_num > 0 so this cast should
-                 * be safe
-                 */
-                if (((unsigned int)s->init_num) > curr_mtu)
-                    len = curr_mtu;
-                else
-                    len = s->init_num;
-            }
-
-            /* Shouldn't ever happen */
-            if (len > INT_MAX)
-                len = INT_MAX;
-
             if (len < DTLS1_HM_HEADER_LENGTH) {
                 /*
                  * len is so small that we really can't do anything sensible
@@ -438,7 +457,16 @@
             }
             s->init_off += ret;
             s->init_num -= ret;
-            frag_off += (ret -= DTLS1_HM_HEADER_LENGTH);
+            ret -= DTLS1_HM_HEADER_LENGTH;
+            frag_off += ret;
+
+            /*
+             * We save the fragment offset for the next fragment so we have it
+             * available in case of an IO retry. We don't know the length of the
+             * next fragment yet so just set that to 0 for now. It will be
+             * updated again later.
+             */
+            dtls1_fix_message_header(s, frag_off, 0);
         }
     }
     return (0);
@@ -1490,9 +1518,12 @@
 {
     int ret;
 #ifndef OPENSSL_NO_SCTP
-    if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
+    BIO *wbio;
+
+    wbio = SSL_get_wbio(s);
+    if (wbio != NULL && BIO_dgram_is_sctp(wbio) &&
         !(s->shutdown & SSL_SENT_SHUTDOWN)) {
-        ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
+        ret = BIO_dgram_sctp_wait_for_dry(wbio);
         if (ret < 0)
             return -1;
 
diff --git a/src/third_party/openssl/openssl/ssl/d1_clnt.c b/src/third_party/openssl/openssl/ssl/d1_clnt.c
index 377c1e6..eb371a2 100644
--- a/src/third_party/openssl/openssl/ssl/d1_clnt.c
+++ b/src/third_party/openssl/openssl/ssl/d1_clnt.c
@@ -299,13 +299,12 @@
 #endif
 
         case SSL3_ST_CW_CLNT_HELLO_A:
-        case SSL3_ST_CW_CLNT_HELLO_B:
-
             s->shutdown = 0;
 
             /* every DTLS ClientHello resets Finished MAC */
             ssl3_init_finished_mac(s);
 
+        case SSL3_ST_CW_CLNT_HELLO_B:
             dtls1_start_timer(s);
             ret = dtls1_client_hello(s);
             if (ret <= 0)
@@ -350,11 +349,15 @@
                              sizeof(DTLS1_SCTP_AUTH_LABEL),
                              DTLS1_SCTP_AUTH_LABEL);
 
-                    SSL_export_keying_material(s, sctpauthkey,
+                    if (SSL_export_keying_material(s, sctpauthkey,
                                                sizeof(sctpauthkey),
                                                labelbuffer,
                                                sizeof(labelbuffer), NULL, 0,
-                                               0);
+                                               0) <= 0) {
+                        ret = -1;
+                        s->state = SSL_ST_ERR;
+                        goto end;
+                    }
 
                     BIO_ctrl(SSL_get_wbio(s),
                              BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
@@ -362,6 +365,10 @@
 #endif
 
                     s->state = SSL3_ST_CR_FINISHED_A;
+                    if (s->tlsext_ticket_expected) {
+                        /* receive renewed session ticket */
+                        s->state = SSL3_ST_CR_SESSION_TICKET_A;
+                    }
                 } else
                     s->state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
             }
@@ -484,9 +491,13 @@
             snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
                      DTLS1_SCTP_AUTH_LABEL);
 
-            SSL_export_keying_material(s, sctpauthkey,
+            if (SSL_export_keying_material(s, sctpauthkey,
                                        sizeof(sctpauthkey), labelbuffer,
-                                       sizeof(labelbuffer), NULL, 0, 0);
+                                       sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+                ret = -1;
+                s->state = SSL_ST_ERR;
+                goto end;
+            }
 
             BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
                      sizeof(sctpauthkey), sctpauthkey);
diff --git a/src/third_party/openssl/openssl/ssl/d1_srvr.c b/src/third_party/openssl/openssl/ssl/d1_srvr.c
index 41c7dc5..f01b8a6 100644
--- a/src/third_party/openssl/openssl/ssl/d1_srvr.c
+++ b/src/third_party/openssl/openssl/ssl/d1_srvr.c
@@ -267,6 +267,19 @@
                 ssl3_init_finished_mac(s);
                 s->state = SSL3_ST_SR_CLNT_HELLO_A;
                 s->ctx->stats.sess_accept++;
+            } else if (!s->s3->send_connection_binding &&
+                       !(s->options &
+                         SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
+                /*
+                 * Server attempting to renegotiate with client that doesn't
+                 * support secure renegotiation.
+                 */
+                SSLerr(SSL_F_DTLS1_ACCEPT,
+                       SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+                ret = -1;
+                s->state = SSL_ST_ERR;
+                goto end;
             } else {
                 /*
                  * s->state == SSL_ST_RENEGOTIATE, we will just send a
@@ -405,9 +418,13 @@
                 snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
                          DTLS1_SCTP_AUTH_LABEL);
 
-                SSL_export_keying_material(s, sctpauthkey,
-                                           sizeof(sctpauthkey), labelbuffer,
-                                           sizeof(labelbuffer), NULL, 0, 0);
+                if (SSL_export_keying_material(s, sctpauthkey,
+                        sizeof(sctpauthkey), labelbuffer,
+                        sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+                    ret = -1;
+                    s->state = SSL_ST_ERR;
+                    goto end;
+                }
 
                 BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
                          sizeof(sctpauthkey), sctpauthkey);
@@ -628,9 +645,13 @@
             snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
                      DTLS1_SCTP_AUTH_LABEL);
 
-            SSL_export_keying_material(s, sctpauthkey,
+            if (SSL_export_keying_material(s, sctpauthkey,
                                        sizeof(sctpauthkey), labelbuffer,
-                                       sizeof(labelbuffer), NULL, 0, 0);
+                                       sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+                ret = -1;
+                s->state = SSL_ST_ERR;
+                goto end;
+            }
 
             BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
                      sizeof(sctpauthkey), sctpauthkey);
diff --git a/src/third_party/openssl/openssl/ssl/kssl.c b/src/third_party/openssl/openssl/ssl/kssl.c
index cf58567..f2839bd 100644
--- a/src/third_party/openssl/openssl/ssl/kssl.c
+++ b/src/third_party/openssl/openssl/ssl/kssl.c
@@ -1,4 +1,4 @@
-/* ssl/kssl.c -*- mode: C; c-file-style: "eay" -*- */
+/* ssl/kssl.c */
 /*
  * Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project
  * 2000.
diff --git a/src/third_party/openssl/openssl/ssl/kssl.h b/src/third_party/openssl/openssl/ssl/kssl.h
index 9a57672..ae8a51f 100644
--- a/src/third_party/openssl/openssl/ssl/kssl.h
+++ b/src/third_party/openssl/openssl/ssl/kssl.h
@@ -1,4 +1,4 @@
-/* ssl/kssl.h -*- mode: C; c-file-style: "eay" -*- */
+/* ssl/kssl.h */
 /*
  * Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project
  * 2000. project 2000.
diff --git a/src/third_party/openssl/openssl/ssl/kssl_lcl.h b/src/third_party/openssl/openssl/ssl/kssl_lcl.h
index 46dcef2..8e6a6d6 100644
--- a/src/third_party/openssl/openssl/ssl/kssl_lcl.h
+++ b/src/third_party/openssl/openssl/ssl/kssl_lcl.h
@@ -1,4 +1,4 @@
-/* ssl/kssl.h -*- mode: C; c-file-style: "eay" -*- */
+/* ssl/kssl.h */
 /*
  * Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project
  * 2000. project 2000.
diff --git a/src/third_party/openssl/openssl/ssl/s23_clnt.c b/src/third_party/openssl/openssl/ssl/s23_clnt.c
index 9b0b0e8..745dca5 100644
--- a/src/third_party/openssl/openssl/ssl/s23_clnt.c
+++ b/src/third_party/openssl/openssl/ssl/s23_clnt.c
@@ -376,12 +376,13 @@
 
     buf = (unsigned char *)s->init_buf->data;
     if (s->state == SSL23_ST_CW_CLNT_HELLO_A) {
-#if 0
-        /* don't reuse session-id's */
+        /*
+         * Since we're sending s23 client hello, we're not reusing a session, as
+         * we'd be using the method from the saved session instead
+         */
         if (!ssl_get_new_session(s, 0)) {
-            return (-1);
+            return -1;
         }
-#endif
 
         p = s->s3->client_random;
         if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0)
@@ -442,9 +443,6 @@
             /*
              * put in the session-id length (zero since there is no reuse)
              */
-#if 0
-            s->session->session_id_length = 0;
-#endif
             s2n(0, d);
 
             if (s->options & SSL_OP_NETSCAPE_CHALLENGE_BUG)
@@ -732,6 +730,8 @@
             goto err;
         }
 
+        s->session->ssl_version = s->version;
+
         /* ensure that TLS_MAX_VERSION is up-to-date */
         OPENSSL_assert(s->version <= TLS_MAX_VERSION);
 
@@ -787,13 +787,6 @@
     }
     s->init_num = 0;
 
-    /*
-     * Since, if we are sending a ssl23 client hello, we are not reusing a
-     * session-id
-     */
-    if (!ssl_get_new_session(s, 0))
-        goto err;
-
     return (SSL_connect(s));
  err:
     return (-1);
diff --git a/src/third_party/openssl/openssl/ssl/s2_srvr.c b/src/third_party/openssl/openssl/ssl/s2_srvr.c
index a0be10c..b891f26 100644
--- a/src/third_party/openssl/openssl/ssl/s2_srvr.c
+++ b/src/third_party/openssl/openssl/ssl/s2_srvr.c
@@ -405,7 +405,7 @@
         }
 
         cp = ssl2_get_cipher_by_char(p);
-        if (cp == NULL) {
+        if (cp == NULL || sk_SSL_CIPHER_find(s->session->ciphers, cp) < 0) {
             ssl2_return_error(s, SSL2_PE_NO_CIPHER);
             SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_CIPHER_MATCH);
             return (-1);
@@ -601,6 +601,11 @@
         s->s2->tmp.cipher_spec_length = i;
         n2s(p, i);
         s->s2->tmp.session_id_length = i;
+        if ((i < 0) || (i > SSL_MAX_SSL_SESSION_ID_LENGTH)) {
+            ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR);
+            SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
+            return -1;
+        }
         n2s(p, i);
         s->s2->challenge_length = i;
         if ((i < SSL2_MIN_CHALLENGE_LENGTH) ||
@@ -690,8 +695,12 @@
             prio = cs;
             allow = cl;
         }
+
+        /* Generate list of SSLv2 ciphers shared between client and server */
         for (z = 0; z < sk_SSL_CIPHER_num(prio); z++) {
-            if (sk_SSL_CIPHER_find(allow, sk_SSL_CIPHER_value(prio, z)) < 0) {
+            const SSL_CIPHER *cp = sk_SSL_CIPHER_value(prio, z);
+            if ((cp->algorithm_ssl & SSL_SSLV2) == 0 ||
+                sk_SSL_CIPHER_find(allow, cp) < 0) {
                 (void)sk_SSL_CIPHER_delete(prio, z);
                 z--;
             }
@@ -700,6 +709,13 @@
             sk_SSL_CIPHER_free(s->session->ciphers);
             s->session->ciphers = prio;
         }
+
+        /* Make sure we have at least one cipher in common */
+        if (sk_SSL_CIPHER_num(s->session->ciphers) == 0) {
+            ssl2_return_error(s, SSL2_PE_NO_CIPHER);
+            SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_NO_CIPHER_MATCH);
+            return -1;
+        }
         /*
          * s->session->ciphers should now have a list of ciphers that are on
          * both the client and server. This list is ordered by the order the
diff --git a/src/third_party/openssl/openssl/ssl/s3_cbc.c b/src/third_party/openssl/openssl/ssl/s3_cbc.c
index 28ca50b..fd014b5 100644
--- a/src/third_party/openssl/openssl/ssl/s3_cbc.c
+++ b/src/third_party/openssl/openssl/ssl/s3_cbc.c
@@ -411,8 +411,9 @@
  * functions, above, we know that data_plus_mac_size is large enough to contain
  * a padding byte and MAC. (If the padding was invalid, it might contain the
  * padding too. )
+ * Returns 1 on success or 0 on error
  */
-void ssl3_cbc_digest_record(const EVP_MD_CTX *ctx,
+int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx,
                             unsigned char *md_out,
                             size_t *md_out_size,
                             const unsigned char header[13],
@@ -455,7 +456,8 @@
 
     switch (EVP_MD_CTX_type(ctx)) {
     case NID_md5:
-        MD5_Init((MD5_CTX *)md_state.c);
+        if (MD5_Init((MD5_CTX *)md_state.c) <= 0)
+            return 0;
         md_final_raw = tls1_md5_final_raw;
         md_transform =
             (void (*)(void *ctx, const unsigned char *block))MD5_Transform;
@@ -464,7 +466,8 @@
         length_is_big_endian = 0;
         break;
     case NID_sha1:
-        SHA1_Init((SHA_CTX *)md_state.c);
+        if (SHA1_Init((SHA_CTX *)md_state.c) <= 0)
+            return 0;
         md_final_raw = tls1_sha1_final_raw;
         md_transform =
             (void (*)(void *ctx, const unsigned char *block))SHA1_Transform;
@@ -472,14 +475,16 @@
         break;
 #ifndef OPENSSL_NO_SHA256
     case NID_sha224:
-        SHA224_Init((SHA256_CTX *)md_state.c);
+        if (SHA224_Init((SHA256_CTX *)md_state.c) <= 0)
+            return 0;
         md_final_raw = tls1_sha256_final_raw;
         md_transform =
             (void (*)(void *ctx, const unsigned char *block))SHA256_Transform;
         md_size = 224 / 8;
         break;
     case NID_sha256:
-        SHA256_Init((SHA256_CTX *)md_state.c);
+        if (SHA256_Init((SHA256_CTX *)md_state.c) <= 0)
+            return 0;
         md_final_raw = tls1_sha256_final_raw;
         md_transform =
             (void (*)(void *ctx, const unsigned char *block))SHA256_Transform;
@@ -488,7 +493,8 @@
 #endif
 #ifndef OPENSSL_NO_SHA512
     case NID_sha384:
-        SHA384_Init((SHA512_CTX *)md_state.c);
+        if (SHA384_Init((SHA512_CTX *)md_state.c) <= 0)
+            return 0;
         md_final_raw = tls1_sha512_final_raw;
         md_transform =
             (void (*)(void *ctx, const unsigned char *block))SHA512_Transform;
@@ -497,7 +503,8 @@
         md_length_size = 16;
         break;
     case NID_sha512:
-        SHA512_Init((SHA512_CTX *)md_state.c);
+        if (SHA512_Init((SHA512_CTX *)md_state.c) <= 0)
+            return 0;
         md_final_raw = tls1_sha512_final_raw;
         md_transform =
             (void (*)(void *ctx, const unsigned char *block))SHA512_Transform;
@@ -514,7 +521,7 @@
         OPENSSL_assert(0);
         if (md_out_size)
             *md_out_size = -1;
-        return;
+        return 0;
     }
 
     OPENSSL_assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES);
@@ -652,7 +659,7 @@
              */
             if (header_length <= md_block_size) {
                 /* Should never happen */
-                return;
+                return 0;
             }
             overhang = header_length - md_block_size;
             md_transform(md_state.c, header);
@@ -733,26 +740,34 @@
     }
 
     EVP_MD_CTX_init(&md_ctx);
-    EVP_DigestInit_ex(&md_ctx, ctx->digest, NULL /* engine */ );
+    if (EVP_DigestInit_ex(&md_ctx, ctx->digest, NULL /* engine */ ) <= 0)
+        goto err;
     if (is_sslv3) {
         /* We repurpose |hmac_pad| to contain the SSLv3 pad2 block. */
         OPENSSL_port_memset(hmac_pad, 0x5c, sslv3_pad_length);
 
-        EVP_DigestUpdate(&md_ctx, mac_secret, mac_secret_length);
-        EVP_DigestUpdate(&md_ctx, hmac_pad, sslv3_pad_length);
-        EVP_DigestUpdate(&md_ctx, mac_out, md_size);
+        if (EVP_DigestUpdate(&md_ctx, mac_secret, mac_secret_length) <= 0
+                || EVP_DigestUpdate(&md_ctx, hmac_pad, sslv3_pad_length) <= 0
+                || EVP_DigestUpdate(&md_ctx, mac_out, md_size) <= 0)
+            goto err;
     } else {
         /* Complete the HMAC in the standard manner. */
         for (i = 0; i < md_block_size; i++)
             hmac_pad[i] ^= 0x6a;
 
-        EVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size);
-        EVP_DigestUpdate(&md_ctx, mac_out, md_size);
+        if (EVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size) <= 0
+                || EVP_DigestUpdate(&md_ctx, mac_out, md_size) <= 0)
+            goto err;
     }
     EVP_DigestFinal(&md_ctx, md_out, &md_out_size_u);
     if (md_out_size)
         *md_out_size = md_out_size_u;
     EVP_MD_CTX_cleanup(&md_ctx);
+
+    return 1;
+err:
+    EVP_MD_CTX_cleanup(&md_ctx);
+    return 0;
 }
 
 #ifdef OPENSSL_FIPS
diff --git a/src/third_party/openssl/openssl/ssl/s3_clnt.c b/src/third_party/openssl/openssl/ssl/s3_clnt.c
index 4b5423c..0e772cb 100644
--- a/src/third_party/openssl/openssl/ssl/s3_clnt.c
+++ b/src/third_party/openssl/openssl/ssl/s3_clnt.c
@@ -1627,6 +1627,12 @@
         }
         p += i;
 
+        if (BN_is_zero(dh->p)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_P_VALUE);
+            goto f_err;
+        }
+
+
         if (2 > n - param_len) {
             SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
             goto f_err;
@@ -1647,6 +1653,11 @@
         }
         p += i;
 
+        if (BN_is_zero(dh->g)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_G_VALUE);
+            goto f_err;
+        }
+
         if (2 > n - param_len) {
             SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
             goto f_err;
@@ -1668,6 +1679,11 @@
         p += i;
         n -= param_len;
 
+        if (BN_is_zero(dh->pub_key)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_PUB_KEY_VALUE);
+            goto f_err;
+        }
+
 # ifndef OPENSSL_NO_RSA
         if (alg_a & SSL_aRSA)
             pkey =
@@ -1870,14 +1886,20 @@
             q = md_buf;
             for (num = 2; num > 0; num--) {
                 EVP_MD_CTX_set_flags(&md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-                EVP_DigestInit_ex(&md_ctx, (num == 2)
-                                  ? s->ctx->md5 : s->ctx->sha1, NULL);
-                EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
-                                 SSL3_RANDOM_SIZE);
-                EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
-                                 SSL3_RANDOM_SIZE);
-                EVP_DigestUpdate(&md_ctx, param, param_len);
-                EVP_DigestFinal_ex(&md_ctx, q, &size);
+                if (EVP_DigestInit_ex(&md_ctx,
+                                      (num == 2) ? s->ctx->md5 : s->ctx->sha1,
+                                      NULL) <= 0
+                        || EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
+                                            SSL3_RANDOM_SIZE) <= 0
+                        || EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
+                                            SSL3_RANDOM_SIZE) <= 0
+                        || EVP_DigestUpdate(&md_ctx, param, param_len) <= 0
+                        || EVP_DigestFinal_ex(&md_ctx, q, &size) <= 0) {
+                    SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
+                           ERR_R_INTERNAL_ERROR);
+                    al = SSL_AD_INTERNAL_ERROR;
+                    goto f_err;
+                }
                 q += size;
                 j += size;
             }
@@ -1896,12 +1918,16 @@
         } else
 #endif
         {
-            EVP_VerifyInit_ex(&md_ctx, md, NULL);
-            EVP_VerifyUpdate(&md_ctx, &(s->s3->client_random[0]),
-                             SSL3_RANDOM_SIZE);
-            EVP_VerifyUpdate(&md_ctx, &(s->s3->server_random[0]),
-                             SSL3_RANDOM_SIZE);
-            EVP_VerifyUpdate(&md_ctx, param, param_len);
+            if (EVP_VerifyInit_ex(&md_ctx, md, NULL) <= 0
+                    || EVP_VerifyUpdate(&md_ctx, &(s->s3->client_random[0]),
+                                        SSL3_RANDOM_SIZE) <= 0
+                    || EVP_VerifyUpdate(&md_ctx, &(s->s3->server_random[0]),
+                                        SSL3_RANDOM_SIZE) <= 0
+                    || EVP_VerifyUpdate(&md_ctx, param, param_len) <= 0) {
+                al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EVP_LIB);
+                goto f_err;
+            }
             if (EVP_VerifyFinal(&md_ctx, p, (int)n, pkey) <= 0) {
                 /* bad signature */
                 al = SSL_AD_DECRYPT_ERROR;
@@ -2121,6 +2147,7 @@
     long n;
     const unsigned char *p;
     unsigned char *d;
+    unsigned long ticket_lifetime_hint;
 
     n = s->method->ssl_get_message(s,
                                    SSL3_ST_CR_SESSION_TICKET_A,
@@ -2139,6 +2166,19 @@
 
     p = d = (unsigned char *)s->init_msg;
 
+    n2l(p, ticket_lifetime_hint);
+    n2s(p, ticklen);
+    /* ticket_lifetime_hint + ticket_length + ticket */
+    if (ticklen + 6 != n) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    /* Server is allowed to change its mind and send an empty ticket. */
+    if (ticklen == 0)
+        return 1;
+
     if (s->session->session_id_length > 0) {
         int i = s->session_ctx->session_cache_mode;
         SSL_SESSION *new_sess;
@@ -2170,14 +2210,6 @@
         s->session = new_sess;
     }
 
-    n2l(p, s->session->tlsext_tick_lifetime_hint);
-    n2s(p, ticklen);
-    /* ticket_lifetime_hint + ticket_length + ticket */
-    if (ticklen + 6 != n) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
     if (s->session->tlsext_tick) {
         OPENSSL_free(s->session->tlsext_tick);
         s->session->tlsext_ticklen = 0;
@@ -2188,6 +2220,7 @@
         goto err;
     }
     OPENSSL_port_memcpy(s->session->tlsext_tick, p, ticklen);
+    s->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint;
     s->session->tlsext_ticklen = ticklen;
     /*
      * There are two ways to detect a resumed ticket session. One is to set
@@ -2225,37 +2258,44 @@
     n = s->method->ssl_get_message(s,
                                    SSL3_ST_CR_CERT_STATUS_A,
                                    SSL3_ST_CR_CERT_STATUS_B,
-                                   SSL3_MT_CERTIFICATE_STATUS, 16384, &ok);
+                                   -1, 16384, &ok);
 
     if (!ok)
         return ((int)n);
-    if (n < 4) {
-        /* need at least status type + length */
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
+
+    if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) {
+        /*
+         * The CertificateStatus message is optional even if
+         * tlsext_status_expected is set
+         */
+        s->s3->tmp.reuse_message = 1;
+    } else {
+        if (n < 4) {
+            /* need at least status type + length */
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        p = (unsigned char *)s->init_msg;
+        if (*p++ != TLSEXT_STATUSTYPE_ocsp) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_UNSUPPORTED_STATUS_TYPE);
+            goto f_err;
+        }
+        n2l3(p, resplen);
+        if (resplen + 4 != n) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
+        if (s->tlsext_ocsp_resp == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CERT_STATUS, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+        s->tlsext_ocsp_resplen = resplen;
     }
-    p = (unsigned char *)s->init_msg;
-    if (*p++ != TLSEXT_STATUSTYPE_ocsp) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_UNSUPPORTED_STATUS_TYPE);
-        goto f_err;
-    }
-    n2l3(p, resplen);
-    if (resplen + 4 != n) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-    if (s->tlsext_ocsp_resp)
-        OPENSSL_free(s->tlsext_ocsp_resp);
-    s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
-    if (!s->tlsext_ocsp_resp) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CERT_STATUS, ERR_R_MALLOC_FAILURE);
-        goto f_err;
-    }
-    s->tlsext_ocsp_resplen = resplen;
     if (s->ctx->tlsext_status_cb) {
         int ret;
         ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
@@ -2357,6 +2397,7 @@
                     || (pkey->pkey.rsa == NULL)) {
                     SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
                            ERR_R_INTERNAL_ERROR);
+                    EVP_PKEY_free(pkey);
                     goto err;
                 }
                 rsa = pkey->pkey.rsa;
@@ -2804,6 +2845,11 @@
 
             pkey_ctx = EVP_PKEY_CTX_new(pub_key =
                                         X509_get_pubkey(peer_cert), NULL);
+            if (pkey_ctx == NULL) {
+                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                       ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
             /*
              * If we have send a certificate, and certificate key
              *
@@ -2813,10 +2859,13 @@
 
             /* Otherwise, generate ephemeral key pair */
 
-            EVP_PKEY_encrypt_init(pkey_ctx);
-            /* Generate session key */
-            if (RAND_bytes(premaster_secret, 32) <= 0) {
+            if (pkey_ctx == NULL
+                    || EVP_PKEY_encrypt_init(pkey_ctx) <= 0
+                    /* Generate session key */
+                    || RAND_bytes(premaster_secret, 32) <= 0) {
                 EVP_PKEY_CTX_free(pkey_ctx);
+                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
                 goto err;
             }
             /*
@@ -2837,13 +2886,18 @@
              * data
              */
             ukm_hash = EVP_MD_CTX_create();
-            EVP_DigestInit(ukm_hash,
-                           EVP_get_digestbynid(NID_id_GostR3411_94));
-            EVP_DigestUpdate(ukm_hash, s->s3->client_random,
-                             SSL3_RANDOM_SIZE);
-            EVP_DigestUpdate(ukm_hash, s->s3->server_random,
-                             SSL3_RANDOM_SIZE);
-            EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
+            if (EVP_DigestInit(ukm_hash,
+                               EVP_get_digestbynid(NID_id_GostR3411_94)) <= 0
+                    || EVP_DigestUpdate(ukm_hash, s->s3->client_random,
+                                        SSL3_RANDOM_SIZE) <= 0
+                    || EVP_DigestUpdate(ukm_hash, s->s3->server_random,
+                                        SSL3_RANDOM_SIZE) <= 0
+                    || EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len) <= 0) {
+                EVP_MD_CTX_destroy(ukm_hash);
+                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
             EVP_MD_CTX_destroy(ukm_hash);
             if (EVP_PKEY_CTX_ctrl
                 (pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_SET_IV, 8,
@@ -2859,7 +2913,7 @@
             *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
             msglen = 255;
             if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, premaster_secret, 32)
-                < 0) {
+                <= 0) {
                 SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
                        SSL_R_LIBRARY_BUG);
                 goto err;
@@ -3060,7 +3114,10 @@
         pkey = s->cert->key->privatekey;
 /* Create context from key and test if sha1 is allowed as digest */
         pctx = EVP_PKEY_CTX_new(pkey, NULL);
-        EVP_PKEY_sign_init(pctx);
+        if (pctx == NULL || EVP_PKEY_sign_init(pctx) <= 0) {
+            SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
         if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) {
             if (TLS1_get_version(s) < TLS1_2_VERSION)
                 s->method->ssl3_enc->cert_verify_mac(s,
@@ -3197,7 +3254,6 @@
          * If we get an error, we need to ssl->rwstate=SSL_X509_LOOKUP;
          * return(-1); We then get retied later
          */
-        i = 0;
         i = ssl_do_client_cert_cb(s, &x509, &pkey);
         if (i < 0) {
             s->rwstate = SSL_X509_LOOKUP;
@@ -3364,7 +3420,7 @@
     /* Check DHE only: static DH not implemented. */
     if (alg_k & SSL_kEDH) {
         int dh_size = BN_num_bits(dh->p);
-        if ((!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 768)
+        if ((!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 1024)
             || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 512)) {
             SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_DH_KEY_TOO_SMALL);
             goto f_err;
diff --git a/src/third_party/openssl/openssl/ssl/s3_enc.c b/src/third_party/openssl/openssl/ssl/s3_enc.c
index 1c800e1..597dbb9 100644
--- a/src/third_party/openssl/openssl/ssl/s3_enc.c
+++ b/src/third_party/openssl/openssl/ssl/s3_enc.c
@@ -256,7 +256,10 @@
             EVP_CIPHER_CTX_init(s->enc_read_ctx);
         dd = s->enc_read_ctx;
 
-        ssl_replace_hash(&s->read_hash, m);
+        if (ssl_replace_hash(&s->read_hash, m) == NULL) {
+                SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+                goto err2;
+        }
 #ifndef OPENSSL_NO_COMP
         /* COMPRESS */
         if (s->expand != NULL) {
@@ -291,7 +294,10 @@
              */
             EVP_CIPHER_CTX_init(s->enc_write_ctx);
         dd = s->enc_write_ctx;
-        ssl_replace_hash(&s->write_hash, m);
+        if (ssl_replace_hash(&s->write_hash, m) == NULL) {
+                SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+                goto err2;
+        }
 #ifndef OPENSSL_NO_COMP
         /* COMPRESS */
         if (s->compress != NULL) {
@@ -677,19 +683,21 @@
         return 0;
 
     npad = (48 / n) * n;
-    if (sender != NULL)
-        EVP_DigestUpdate(&ctx, sender, len);
-    EVP_DigestUpdate(&ctx, s->session->master_key,
-                     s->session->master_key_length);
-    EVP_DigestUpdate(&ctx, ssl3_pad_1, npad);
-    EVP_DigestFinal_ex(&ctx, md_buf, &i);
+    if ((sender != NULL && EVP_DigestUpdate(&ctx, sender, len) <= 0)
+            || EVP_DigestUpdate(&ctx, s->session->master_key,
+                                s->session->master_key_length) <= 0
+            || EVP_DigestUpdate(&ctx, ssl3_pad_1, npad) <= 0
+            || EVP_DigestFinal_ex(&ctx, md_buf, &i) <= 0
 
-    EVP_DigestInit_ex(&ctx, EVP_MD_CTX_md(&ctx), NULL);
-    EVP_DigestUpdate(&ctx, s->session->master_key,
-                     s->session->master_key_length);
-    EVP_DigestUpdate(&ctx, ssl3_pad_2, npad);
-    EVP_DigestUpdate(&ctx, md_buf, i);
-    EVP_DigestFinal_ex(&ctx, p, &ret);
+            || EVP_DigestInit_ex(&ctx, EVP_MD_CTX_md(&ctx), NULL) <= 0
+            || EVP_DigestUpdate(&ctx, s->session->master_key,
+                                s->session->master_key_length) <= 0
+            || EVP_DigestUpdate(&ctx, ssl3_pad_2, npad) <= 0
+            || EVP_DigestUpdate(&ctx, md_buf, i) <= 0
+            || EVP_DigestFinal_ex(&ctx, p, &ret) <= 0) {
+        SSLerr(SSL_F_SSL3_HANDSHAKE_MAC, ERR_R_INTERNAL_ERROR);
+        ret = 0;
+    }
 
     EVP_MD_CTX_cleanup(&ctx);
 
@@ -761,33 +769,36 @@
         header[j++] = rec->length & 0xff;
 
         /* Final param == is SSLv3 */
-        ssl3_cbc_digest_record(hash,
-                               md, &md_size,
-                               header, rec->input,
-                               rec->length + md_size, orig_len,
-                               mac_sec, md_size, 1);
+        if (ssl3_cbc_digest_record(hash,
+                                   md, &md_size,
+                                   header, rec->input,
+                                   rec->length + md_size, orig_len,
+                                   mac_sec, md_size, 1) <= 0)
+            return -1;
     } else {
         unsigned int md_size_u;
         /* Chop the digest off the end :-) */
         EVP_MD_CTX_init(&md_ctx);
 
-        EVP_MD_CTX_copy_ex(&md_ctx, hash);
-        EVP_DigestUpdate(&md_ctx, mac_sec, md_size);
-        EVP_DigestUpdate(&md_ctx, ssl3_pad_1, npad);
-        EVP_DigestUpdate(&md_ctx, seq, 8);
         rec_char = rec->type;
-        EVP_DigestUpdate(&md_ctx, &rec_char, 1);
         p = md;
         s2n(rec->length, p);
-        EVP_DigestUpdate(&md_ctx, md, 2);
-        EVP_DigestUpdate(&md_ctx, rec->input, rec->length);
-        EVP_DigestFinal_ex(&md_ctx, md, NULL);
-
-        EVP_MD_CTX_copy_ex(&md_ctx, hash);
-        EVP_DigestUpdate(&md_ctx, mac_sec, md_size);
-        EVP_DigestUpdate(&md_ctx, ssl3_pad_2, npad);
-        EVP_DigestUpdate(&md_ctx, md, md_size);
-        EVP_DigestFinal_ex(&md_ctx, md, &md_size_u);
+        if (EVP_MD_CTX_copy_ex(&md_ctx, hash) <= 0
+                || EVP_DigestUpdate(&md_ctx, mac_sec, md_size) <= 0
+                || EVP_DigestUpdate(&md_ctx, ssl3_pad_1, npad) <= 0
+                || EVP_DigestUpdate(&md_ctx, seq, 8) <= 0
+                || EVP_DigestUpdate(&md_ctx, &rec_char, 1) <= 0
+                || EVP_DigestUpdate(&md_ctx, md, 2) <= 0
+                || EVP_DigestUpdate(&md_ctx, rec->input, rec->length) <= 0
+                || EVP_DigestFinal_ex(&md_ctx, md, NULL) <= 0
+                || EVP_MD_CTX_copy_ex(&md_ctx, hash) <= 0
+                || EVP_DigestUpdate(&md_ctx, mac_sec, md_size) <= 0
+                || EVP_DigestUpdate(&md_ctx, ssl3_pad_2, npad) <= 0
+                || EVP_DigestUpdate(&md_ctx, md, md_size) <= 0
+                || EVP_DigestFinal_ex(&md_ctx, md, &md_size_u) <= 0) {
+            EVP_MD_CTX_cleanup(&md_ctx);
+            return -1;
+        }
         md_size = md_size_u;
 
         EVP_MD_CTX_cleanup(&md_ctx);
@@ -829,17 +840,24 @@
 
     EVP_MD_CTX_init(&ctx);
     for (i = 0; i < 3; i++) {
-        EVP_DigestInit_ex(&ctx, s->ctx->sha1, NULL);
-        EVP_DigestUpdate(&ctx, salt[i], OPENSSL_port_strlen((const char *)salt[i]));
-        EVP_DigestUpdate(&ctx, p, len);
-        EVP_DigestUpdate(&ctx, &(s->s3->client_random[0]), SSL3_RANDOM_SIZE);
-        EVP_DigestUpdate(&ctx, &(s->s3->server_random[0]), SSL3_RANDOM_SIZE);
-        EVP_DigestFinal_ex(&ctx, buf, &n);
+        if (EVP_DigestInit_ex(&ctx, s->ctx->sha1, NULL) <= 0
+                || EVP_DigestUpdate(&ctx, salt[i],
+                                    OPENSSL_port_strlen((const char *)salt[i])) <= 0
+                || EVP_DigestUpdate(&ctx, p, len) <= 0
+                || EVP_DigestUpdate(&ctx, &(s->s3->client_random[0]),
+                                    SSL3_RANDOM_SIZE) <= 0
+                || EVP_DigestUpdate(&ctx, &(s->s3->server_random[0]),
+                                    SSL3_RANDOM_SIZE) <= 0
+                || EVP_DigestFinal_ex(&ctx, buf, &n) <= 0
 
-        EVP_DigestInit_ex(&ctx, s->ctx->md5, NULL);
-        EVP_DigestUpdate(&ctx, p, len);
-        EVP_DigestUpdate(&ctx, buf, n);
-        EVP_DigestFinal_ex(&ctx, out, &n);
+                || EVP_DigestInit_ex(&ctx, s->ctx->md5, NULL) <= 0
+                || EVP_DigestUpdate(&ctx, p, len) <= 0
+                || EVP_DigestUpdate(&ctx, buf, n) <= 0
+                || EVP_DigestFinal_ex(&ctx, out, &n) <= 0) {
+            SSLerr(SSL_F_SSL3_GENERATE_MASTER_SECRET, ERR_R_INTERNAL_ERROR);
+            ret = 0;
+            break;
+        }
         out += n;
         ret += n;
     }
diff --git a/src/third_party/openssl/openssl/ssl/s3_lib.c b/src/third_party/openssl/openssl/ssl/s3_lib.c
index 73674fd..647d8da 100644
--- a/src/third_party/openssl/openssl/ssl/s3_lib.c
+++ b/src/third_party/openssl/openssl/ssl/s3_lib.c
@@ -2958,7 +2958,7 @@
 
 void ssl3_free(SSL *s)
 {
-    if (s == NULL)
+    if (s == NULL || s->s3 == NULL)
         return;
 
 #ifdef TLSEXT_TYPE_opaque_prf_input
@@ -3167,13 +3167,6 @@
                 SSLerr(SSL_F_SSL3_CTRL, ERR_R_DH_LIB);
                 return (ret);
             }
-            if (!(s->options & SSL_OP_SINGLE_DH_USE)) {
-                if (!DH_generate_key(dh)) {
-                    DH_free(dh);
-                    SSLerr(SSL_F_SSL3_CTRL, ERR_R_DH_LIB);
-                    return (ret);
-                }
-            }
             if (s->cert->dh_tmp != NULL)
                 DH_free(s->cert->dh_tmp);
             s->cert->dh_tmp = dh;
@@ -3224,6 +3217,8 @@
 #ifndef OPENSSL_NO_TLSEXT
     case SSL_CTRL_SET_TLSEXT_HOSTNAME:
         if (larg == TLSEXT_NAMETYPE_host_name) {
+            size_t len;
+
             if (s->tlsext_hostname != NULL)
                 OPENSSL_free(s->tlsext_hostname);
             s->tlsext_hostname = NULL;
@@ -3231,7 +3226,8 @@
             ret = 1;
             if (parg == NULL)
                 break;
-            if (OPENSSL_port_strlen((char *)parg) > TLSEXT_MAXLEN_host_name) {
+            len = OPENSSL_port_strlen((char *)parg);
+            if (len == 0 || len > TLSEXT_MAXLEN_host_name) {
                 SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
                 return 0;
             }
@@ -3482,13 +3478,6 @@
                 SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_DH_LIB);
                 return 0;
             }
-            if (!(ctx->options & SSL_OP_SINGLE_DH_USE)) {
-                if (!DH_generate_key(new)) {
-                    SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_DH_LIB);
-                    DH_free(new);
-                    return 0;
-                }
-            }
             if (cert->dh_tmp != NULL)
                 DH_free(cert->dh_tmp);
             cert->dh_tmp = new;
diff --git a/src/third_party/openssl/openssl/ssl/s3_srvr.c b/src/third_party/openssl/openssl/ssl/s3_srvr.c
index d4506a9..8c76895 100644
--- a/src/third_party/openssl/openssl/ssl/s3_srvr.c
+++ b/src/third_party/openssl/openssl/ssl/s3_srvr.c
@@ -1,4 +1,4 @@
-/* ssl/s3_srvr.c -*- mode:C; c-file-style: "eay" -*- */
+/* ssl/s3_srvr.c */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
@@ -386,7 +386,6 @@
                      */
                     if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY)
                         SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_CLIENTHELLO_TLSEXT);
-                    ret = SSL_TLSEXT_ERR_ALERT_FATAL;
                     ret = -1;
                     s->state = SSL_ST_ERR;
                     goto end;
@@ -970,7 +969,7 @@
 
 int ssl3_get_client_hello(SSL *s)
 {
-    int i, j, ok, al, ret = -1;
+    int i, j, ok, al, ret = -1, cookie_valid = 0;
     unsigned int cookie_len;
     long n;
     unsigned long id;
@@ -1068,6 +1067,12 @@
         goto f_err;
     }
 
+    if ((j < 0) || (j > SSL_MAX_SSL_SESSION_ID_LENGTH)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
     s->hit = 0;
     /*
      * Versions before 0.9.7 always allow clients to resume sessions in
@@ -1158,8 +1163,7 @@
                 SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
                 goto f_err;
             }
-
-            ret = 2;
+            cookie_valid = 1;
         }
 
         p += cookie_len;
@@ -1267,7 +1271,7 @@
 #ifndef OPENSSL_NO_TLSEXT
     /* TLS extensions */
     if (s->version >= SSL3_VERSION) {
-        if (!ssl_parse_clienthello_tlsext(s, &p, d, n, &al)) {
+        if (!ssl_parse_clienthello_tlsext(s, &p, d + n, &al)) {
             /* 'al' set by ssl_parse_clienthello_tlsext */
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
             goto f_err;
@@ -1495,8 +1499,7 @@
         }
     }
 
-    if (ret < 0)
-        ret = 1;
+    ret = cookie_valid ? 2 : 1;
     if (0) {
  f_err:
         ssl3_send_alert(s, SSL3_AL_FATAL, al);
@@ -1506,7 +1509,7 @@
 
     if (ciphers != NULL)
         sk_SSL_CIPHER_free(ciphers);
-    return (ret);
+    return ret;
 }
 
 int ssl3_send_server_hello(SSL *s)
@@ -1729,20 +1732,9 @@
             }
 
             s->s3->tmp.dh = dh;
-            if ((dhp->pub_key == NULL ||
-                 dhp->priv_key == NULL ||
-                 (s->options & SSL_OP_SINGLE_DH_USE))) {
-                if (!DH_generate_key(dh)) {
-                    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
-                    goto err;
-                }
-            } else {
-                dh->pub_key = BN_dup(dhp->pub_key);
-                dh->priv_key = BN_dup(dhp->priv_key);
-                if ((dh->pub_key == NULL) || (dh->priv_key == NULL)) {
-                    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
-                    goto err;
-                }
+            if (!DH_generate_key(dh)) {
+                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
+                goto err;
             }
             r[0] = dh->p;
             r[1] = dh->g;
@@ -1990,14 +1982,22 @@
                 for (num = 2; num > 0; num--) {
                     EVP_MD_CTX_set_flags(&md_ctx,
                                          EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-                    EVP_DigestInit_ex(&md_ctx, (num == 2)
-                                      ? s->ctx->md5 : s->ctx->sha1, NULL);
-                    EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
-                                     SSL3_RANDOM_SIZE);
-                    EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
-                                     SSL3_RANDOM_SIZE);
-                    EVP_DigestUpdate(&md_ctx, &(d[4]), n);
-                    EVP_DigestFinal_ex(&md_ctx, q, (unsigned int *)&i);
+                    if (EVP_DigestInit_ex(&md_ctx,
+                                          (num == 2) ? s->ctx->md5
+                                                     : s->ctx->sha1,
+                                          NULL) <= 0
+                        || EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
+                                            SSL3_RANDOM_SIZE) <= 0
+                        || EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
+                                            SSL3_RANDOM_SIZE) <= 0
+                        || EVP_DigestUpdate(&md_ctx, &(d[4]), n) <= 0
+                        || EVP_DigestFinal_ex(&md_ctx, q,
+                                              (unsigned int *)&i) <= 0) {
+                        SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
+                               ERR_LIB_EVP);
+                        al = SSL_AD_INTERNAL_ERROR;
+                        goto f_err;
+                    }
                     q += i;
                     j += i;
                 }
@@ -2027,16 +2027,17 @@
 #ifdef SSL_DEBUG
                 OPENSSL_port_printferr("Using hash %s\n", EVP_MD_name(md));
 #endif
-                EVP_SignInit_ex(&md_ctx, md, NULL);
-                EVP_SignUpdate(&md_ctx, &(s->s3->client_random[0]),
-                               SSL3_RANDOM_SIZE);
-                EVP_SignUpdate(&md_ctx, &(s->s3->server_random[0]),
-                               SSL3_RANDOM_SIZE);
-                EVP_SignUpdate(&md_ctx, &(d[4]), n);
-                if (!EVP_SignFinal(&md_ctx, &(p[2]),
-                                   (unsigned int *)&i, pkey)) {
+                if (EVP_SignInit_ex(&md_ctx, md, NULL) <= 0
+                        || EVP_SignUpdate(&md_ctx, &(s->s3->client_random[0]),
+                                          SSL3_RANDOM_SIZE) <= 0
+                        || EVP_SignUpdate(&md_ctx, &(s->s3->server_random[0]),
+                                          SSL3_RANDOM_SIZE) <= 0
+                        || EVP_SignUpdate(&md_ctx, &(d[4]), n) <= 0
+                        || EVP_SignFinal(&md_ctx, &(p[2]),
+                                         (unsigned int *)&i, pkey) <= 0) {
                     SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_LIB_EVP);
-                    goto err;
+                    al = SSL_AD_INTERNAL_ERROR;
+                    goto f_err;
                 }
                 s2n(i, p);
                 n += i + 2;
@@ -2882,7 +2883,15 @@
             pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
 
         pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
-        EVP_PKEY_decrypt_init(pkey_ctx);
+        if (pkey_ctx == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+        if (EVP_PKEY_decrypt_init(pkey_ctx) <= 0) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto gerr;
+        }
         /*
          * If client certificate is present and is of the same type, maybe
          * use it for key exchange.  Don't mind errors from
@@ -3126,7 +3135,17 @@
         unsigned char signature[64];
         int idx;
         EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL);
-        EVP_PKEY_verify_init(pctx);
+        if (pctx == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+        if (EVP_PKEY_verify_init(pctx) <= 0) {
+            EVP_PKEY_CTX_free(pctx);
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
         if (i != 64) {
             OPENSSL_port_printferr("GOST signature length is %d", i);
         }
diff --git a/src/third_party/openssl/openssl/ssl/ssl.h b/src/third_party/openssl/openssl/ssl/ssl.h
index d2ab0c0..105047e 100644
--- a/src/third_party/openssl/openssl/ssl/ssl.h
+++ b/src/third_party/openssl/openssl/ssl/ssl.h
@@ -602,7 +602,7 @@
 # define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION        0x00040000L
 /* If set, always create a new key when using tmp_ecdh parameters */
 # define SSL_OP_SINGLE_ECDH_USE                          0x00080000L
-/* If set, always create a new key when using tmp_dh parameters */
+/* Does nothing: retained for compatibility */
 # define SSL_OP_SINGLE_DH_USE                            0x00100000L
 /* Does nothing: retained for compatibiity */
 # define SSL_OP_EPHEMERAL_RSA                            0x0
@@ -2313,6 +2313,7 @@
 # define SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC                 292
 # define SSL_F_SSL3_ENC                                   134
 # define SSL_F_SSL3_GENERATE_KEY_BLOCK                    238
+# define SSL_F_SSL3_GENERATE_MASTER_SECRET                388
 # define SSL_F_SSL3_GET_CERTIFICATE_REQUEST               135
 # define SSL_F_SSL3_GET_CERT_STATUS                       289
 # define SSL_F_SSL3_GET_CERT_VERIFY                       136
@@ -2465,8 +2466,11 @@
 # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK              106
 # define SSL_R_BAD_DECOMPRESSION                          107
 # define SSL_R_BAD_DH_G_LENGTH                            108
+# define SSL_R_BAD_DH_G_VALUE                             375
 # define SSL_R_BAD_DH_PUB_KEY_LENGTH                      109
+# define SSL_R_BAD_DH_PUB_KEY_VALUE                       393
 # define SSL_R_BAD_DH_P_LENGTH                            110
+# define SSL_R_BAD_DH_P_VALUE                             395
 # define SSL_R_BAD_DIGEST_LENGTH                          111
 # define SSL_R_BAD_DSA_SIGNATURE                          112
 # define SSL_R_BAD_ECC_CERT                               304
diff --git a/src/third_party/openssl/openssl/ssl/ssl3.h b/src/third_party/openssl/openssl/ssl/ssl3.h
index df6f734..a5ed610 100644
--- a/src/third_party/openssl/openssl/ssl/ssl3.h
+++ b/src/third_party/openssl/openssl/ssl/ssl3.h
@@ -263,6 +263,8 @@
 # define SSL3_SESSION_ID_SIZE                    32
 # define SSL3_RT_HEADER_LENGTH                   5
 
+# define SSL3_HM_HEADER_LENGTH                   4
+
 # ifndef SSL3_ALIGN_PAYLOAD
  /*
   * Some will argue that this increases memory footprint, but it's not
diff --git a/src/third_party/openssl/openssl/ssl/ssl_asn1.c b/src/third_party/openssl/openssl/ssl/ssl_asn1.c
index 44652be..19de1a9 100644
--- a/src/third_party/openssl/openssl/ssl/ssl_asn1.c
+++ b/src/third_party/openssl/openssl/ssl/ssl_asn1.c
@@ -124,13 +124,16 @@
 int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
 {
 #define LSIZE2 (sizeof(long)*2)
-    int v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0, v7 = 0, v8 = 0;
+    int v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0;
     unsigned char buf[4], ibuf1[LSIZE2], ibuf2[LSIZE2];
     unsigned char ibuf3[LSIZE2], ibuf4[LSIZE2], ibuf5[LSIZE2];
 #ifndef OPENSSL_NO_TLSEXT
     int v6 = 0, v9 = 0, v10 = 0;
     unsigned char ibuf6[LSIZE2];
 #endif
+#ifndef OPENSSL_NO_PSK
+    int v7 = 0, v8 = 0;
+#endif
 #ifndef OPENSSL_NO_COMP
     unsigned char cbuf;
     int v11 = 0;
diff --git a/src/third_party/openssl/openssl/ssl/ssl_cert.c b/src/third_party/openssl/openssl/ssl/ssl_cert.c
index 7e9edd3..9ee8738 100644
--- a/src/third_party/openssl/openssl/ssl/ssl_cert.c
+++ b/src/third_party/openssl/openssl/ssl/ssl_cert.c
@@ -209,6 +209,7 @@
 
     OPENSSL_port_memset(ret, 0, sizeof(CERT));
 
+    ret->references = 1;
     ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]];
     /*
      * or ret->key = ret->pkeys + (cert->key - cert->pkeys), if you find that
@@ -285,7 +286,6 @@
      * chain is held inside SSL_CTX
      */
 
-    ret->references = 1;
     /*
      * Set digests to defaults. NB: we don't copy existing values as they
      * will be set during handshake.
diff --git a/src/third_party/openssl/openssl/ssl/ssl_ciph.c b/src/third_party/openssl/openssl/ssl/ssl_ciph.c
index 23c5c53..fef51c8 100644
--- a/src/third_party/openssl/openssl/ssl/ssl_ciph.c
+++ b/src/third_party/openssl/openssl/ssl/ssl_ciph.c
@@ -359,10 +359,11 @@
     const EVP_PKEY_ASN1_METHOD *ameth;
     int pkey_id = 0;
     ameth = EVP_PKEY_asn1_find_str(NULL, pkey_name, -1);
-    if (ameth) {
-        EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
+    if (ameth && EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL,
+                                         ameth) > 0) {
+        return pkey_id;
     }
-    return pkey_id;
+    return 0;
 }
 
 #else
@@ -374,7 +375,9 @@
     int pkey_id = 0;
     ameth = EVP_PKEY_asn1_find_str(&tmpeng, pkey_name, -1);
     if (ameth) {
-        EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
+        if (EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL,
+                                    ameth) <= 0)
+            pkey_id = 0;
     }
     if (tmpeng)
         ENGINE_finish(tmpeng);
diff --git a/src/third_party/openssl/openssl/ssl/ssl_err.c b/src/third_party/openssl/openssl/ssl/ssl_err.c
index def5aea..d4b1f39 100644
--- a/src/third_party/openssl/openssl/ssl/ssl_err.c
+++ b/src/third_party/openssl/openssl/ssl/ssl_err.c
@@ -165,6 +165,8 @@
     {ERR_FUNC(SSL_F_SSL3_ENC), "SSL3_ENC"},
     {ERR_FUNC(SSL_F_SSL3_CHECK_FINISHED), "SSL3_CHECK_FINISHED"},
     {ERR_FUNC(SSL_F_SSL3_GENERATE_KEY_BLOCK), "SSL3_GENERATE_KEY_BLOCK"},
+    {ERR_FUNC(SSL_F_SSL3_GENERATE_MASTER_SECRET),
+     "ssl3_generate_master_secret"},
     {ERR_FUNC(SSL_F_SSL3_GET_CERTIFICATE_REQUEST),
      "SSL3_GET_CERTIFICATE_REQUEST"},
     {ERR_FUNC(SSL_F_SSL3_GET_CERT_STATUS), "SSL3_GET_CERT_STATUS"},
@@ -372,8 +374,11 @@
      "bad data returned by callback"},
     {ERR_REASON(SSL_R_BAD_DECOMPRESSION), "bad decompression"},
     {ERR_REASON(SSL_R_BAD_DH_G_LENGTH), "bad dh g length"},
+    {ERR_REASON(SSL_R_BAD_DH_G_VALUE), "bad dh g value"},
     {ERR_REASON(SSL_R_BAD_DH_PUB_KEY_LENGTH), "bad dh pub key length"},
+    {ERR_REASON(SSL_R_BAD_DH_PUB_KEY_VALUE), "bad dh pub key value"},
     {ERR_REASON(SSL_R_BAD_DH_P_LENGTH), "bad dh p length"},
+    {ERR_REASON(SSL_R_BAD_DH_P_VALUE), "bad dh p value"},
     {ERR_REASON(SSL_R_BAD_DIGEST_LENGTH), "bad digest length"},
     {ERR_REASON(SSL_R_BAD_DSA_SIGNATURE), "bad dsa signature"},
     {ERR_REASON(SSL_R_BAD_ECC_CERT), "bad ecc cert"},
diff --git a/src/third_party/openssl/openssl/ssl/ssl_lib.c b/src/third_party/openssl/openssl/ssl/ssl_lib.c
index 797643f..db7529f 100644
--- a/src/third_party/openssl/openssl/ssl/ssl_lib.c
+++ b/src/third_party/openssl/openssl/ssl/ssl_lib.c
@@ -310,6 +310,7 @@
     s->options = ctx->options;
     s->mode = ctx->mode;
     s->max_cert_list = ctx->max_cert_list;
+    s->references = 1;
 
     if (ctx->cert != NULL) {
         /*
@@ -378,7 +379,6 @@
     if (!s->method->ssl_new(s))
         goto err;
 
-    s->references = 1;
     s->server = (ctx->method->ssl_accept == ssl_undefined_function) ? 0 : 1;
 
     SSL_clear(s);
@@ -3286,8 +3286,11 @@
 {
     ssl_clear_hash_ctx(hash);
     *hash = EVP_MD_CTX_create();
-    if (md)
-        EVP_DigestInit_ex(*hash, md, NULL);
+    if (*hash == NULL || (md && EVP_DigestInit_ex(*hash, md, NULL) <= 0)) {
+        EVP_MD_CTX_destroy(*hash);
+        *hash = NULL;
+        return NULL;
+    }
     return *hash;
 }
 
diff --git a/src/third_party/openssl/openssl/ssl/ssl_locl.h b/src/third_party/openssl/openssl/ssl/ssl_locl.h
index 55c4fdd..548f591 100644
--- a/src/third_party/openssl/openssl/ssl/ssl_locl.h
+++ b/src/third_party/openssl/openssl/ssl/ssl_locl.h
@@ -1157,7 +1157,7 @@
 unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
                                           unsigned char *limit);
 int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data,
-                                 unsigned char *d, int n, int *al);
+                                 unsigned char *limit, int *al);
 int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data,
                                  unsigned char *d, int n, int *al);
 int ssl_prepare_clienthello_tlsext(SSL *s);
@@ -1221,15 +1221,15 @@
                             SSL3_RECORD *rec,
                             unsigned block_size, unsigned mac_size);
 char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx);
-void ssl3_cbc_digest_record(const EVP_MD_CTX *ctx,
-                            unsigned char *md_out,
-                            size_t *md_out_size,
-                            const unsigned char header[13],
-                            const unsigned char *data,
-                            size_t data_plus_mac_size,
-                            size_t data_plus_mac_plus_padding_size,
-                            const unsigned char *mac_secret,
-                            unsigned mac_secret_length, char is_sslv3);
+int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx,
+                           unsigned char *md_out,
+                           size_t *md_out_size,
+                           const unsigned char header[13],
+                           const unsigned char *data,
+                           size_t data_plus_mac_size,
+                           size_t data_plus_mac_plus_padding_size,
+                           const unsigned char *mac_secret,
+                           unsigned mac_secret_length, char is_sslv3);
 
 void tls_fips_digest_extra(const EVP_CIPHER_CTX *cipher_ctx,
                            EVP_MD_CTX *mac_ctx, const unsigned char *data,
diff --git a/src/third_party/openssl/openssl/ssl/ssl_rsa.c b/src/third_party/openssl/openssl/ssl/ssl_rsa.c
index 0315adc..a33c2cc 100644
--- a/src/third_party/openssl/openssl/ssl/ssl_rsa.c
+++ b/src/third_party/openssl/openssl/ssl/ssl_rsa.c
@@ -163,7 +163,10 @@
     }
 
     RSA_up_ref(rsa);
-    EVP_PKEY_assign_RSA(pkey, rsa);
+    if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) {
+        RSA_free(rsa);
+        return 0;
+    }
 
     ret = ssl_set_pkey(ssl->cert, pkey);
     EVP_PKEY_free(pkey);
@@ -184,6 +187,15 @@
     if (c->pkeys[i].x509 != NULL) {
         EVP_PKEY *pktmp;
         pktmp = X509_get_pubkey(c->pkeys[i].x509);
+        if (pktmp == NULL) {
+            SSLerr(SSL_F_SSL_SET_PKEY, ERR_R_MALLOC_FAILURE);
+            EVP_PKEY_free(pktmp);
+            return 0;
+        }
+        /*
+         * The return code from EVP_PKEY_copy_parameters is deliberately
+         * ignored. Some EVP_PKEY types cannot do this.
+         */
         EVP_PKEY_copy_parameters(pktmp, pkey);
         EVP_PKEY_free(pktmp);
         ERR_clear_error();
@@ -385,6 +397,10 @@
     }
 
     if (c->pkeys[i].privatekey != NULL) {
+        /*
+         * The return code from EVP_PKEY_copy_parameters is deliberately
+         * ignored. Some EVP_PKEY types cannot do this.
+         */
         EVP_PKEY_copy_parameters(pkey, c->pkeys[i].privatekey);
         ERR_clear_error();
 
@@ -505,7 +521,10 @@
     }
 
     RSA_up_ref(rsa);
-    EVP_PKEY_assign_RSA(pkey, rsa);
+    if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) {
+        RSA_free(rsa);
+        return 0;
+    }
 
     ret = ssl_set_pkey(ctx->cert, pkey);
     EVP_PKEY_free(pkey);
diff --git a/src/third_party/openssl/openssl/ssl/ssl_sess.c b/src/third_party/openssl/openssl/ssl/ssl_sess.c
index be171b7..d8fb388 100644
--- a/src/third_party/openssl/openssl/ssl/ssl_sess.c
+++ b/src/third_party/openssl/openssl/ssl/ssl_sess.c
@@ -259,8 +259,8 @@
     dest->tlsext_ecpointformatlist = NULL;
     dest->tlsext_ellipticcurvelist = NULL;
 # endif
-#endif
     dest->tlsext_tick = NULL;
+#endif
 #ifndef OPENSSL_NO_SRP
     dest->srp_username = NULL;
 #endif
@@ -327,7 +327,6 @@
             goto err;
     }
 # endif
-#endif
 
     if (ticket != 0) {
         dest->tlsext_tick = BUF_memdup(src->tlsext_tick, src->tlsext_ticklen);
@@ -337,6 +336,7 @@
         dest->tlsext_tick_lifetime_hint = 0;
         dest->tlsext_ticklen = 0;
     }
+#endif
 
 #ifndef OPENSSL_NO_SRP
     if (src->srp_username) {
@@ -605,9 +605,6 @@
     int r;
 #endif
 
-    if (len < 0 || len > SSL_MAX_SSL_SESSION_ID_LENGTH)
-        goto err;
-
     if (session_id + len > limit) {
         fatal = 1;
         goto err;
diff --git a/src/third_party/openssl/openssl/ssl/ssltest.c b/src/third_party/openssl/openssl/ssl/ssltest.c
index 6a0c293..349ee1e 100644
--- a/src/third_party/openssl/openssl/ssl/ssltest.c
+++ b/src/third_party/openssl/openssl/ssl/ssltest.c
@@ -142,6 +142,7 @@
 
 /* Or gethostname won't be declared properly on Linux and GNU platforms. */
 #define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
 
 #include <assert.h>
 #include <errno.h>
diff --git a/src/third_party/openssl/openssl/ssl/t1_enc.c b/src/third_party/openssl/openssl/ssl/t1_enc.c
index 59d104d..fa1726b 100644
--- a/src/third_party/openssl/openssl/ssl/t1_enc.c
+++ b/src/third_party/openssl/openssl/ssl/t1_enc.c
@@ -388,6 +388,8 @@
             EVP_CIPHER_CTX_init(s->enc_read_ctx);
         dd = s->enc_read_ctx;
         mac_ctx = ssl_replace_hash(&s->read_hash, NULL);
+        if (mac_ctx == NULL)
+            goto err;
 #ifndef OPENSSL_NO_COMP
         if (s->expand != NULL) {
             COMP_CTX_free(s->expand);
@@ -426,11 +428,14 @@
         dd = s->enc_write_ctx;
         if (SSL_IS_DTLS(s)) {
             mac_ctx = EVP_MD_CTX_create();
-            if (!mac_ctx)
+            if (mac_ctx == NULL)
                 goto err;
             s->write_hash = mac_ctx;
-        } else
+        } else {
             mac_ctx = ssl_replace_hash(&s->write_hash, NULL);
+            if (mac_ctx == NULL)
+                goto err;
+        }
 #ifndef OPENSSL_NO_COMP
         if (s->compress != NULL) {
             COMP_CTX_free(s->compress);
@@ -503,7 +508,12 @@
     if (!(EVP_CIPHER_flags(c) & EVP_CIPH_FLAG_AEAD_CIPHER)) {
         mac_key = EVP_PKEY_new_mac_key(mac_type, NULL,
                                        mac_secret, *mac_secret_size);
-        EVP_DigestSignInit(mac_ctx, NULL, m, NULL, mac_key);
+        if (mac_key == NULL
+                || EVP_DigestSignInit(mac_ctx, NULL, m, NULL, mac_key) <= 0) {
+            EVP_PKEY_free(mac_key);
+            SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+            goto err2;
+        }
         EVP_PKEY_free(mac_key);
     }
 #ifdef TLS_DEBUG
@@ -916,8 +926,9 @@
     }
 
     EVP_MD_CTX_init(&ctx);
-    EVP_MD_CTX_copy_ex(&ctx, d);
-    EVP_DigestFinal_ex(&ctx, out, &ret);
+    if (EVP_MD_CTX_copy_ex(&ctx, d) <=0
+            || EVP_DigestFinal_ex(&ctx, out, &ret) <= 0)
+        ret = 0;
     EVP_MD_CTX_cleanup(&ctx);
     return ((int)ret);
 }
@@ -1044,17 +1055,24 @@
          * are hashing because that gives an attacker a timing-oracle.
          */
         /* Final param == not SSLv3 */
-        ssl3_cbc_digest_record(mac_ctx,
-                               md, &md_size,
-                               header, rec->input,
-                               rec->length + md_size, orig_len,
-                               ssl->s3->read_mac_secret,
-                               ssl->s3->read_mac_secret_size, 0);
+        if (ssl3_cbc_digest_record(mac_ctx,
+                                   md, &md_size,
+                                   header, rec->input,
+                                   rec->length + md_size, orig_len,
+                                   ssl->s3->read_mac_secret,
+                                   ssl->s3->read_mac_secret_size, 0) <= 0) {
+            if (!stream_mac)
+                EVP_MD_CTX_cleanup(&hmac);
+            return -1;
+        }
     } else {
-        EVP_DigestSignUpdate(mac_ctx, header, sizeof(header));
-        EVP_DigestSignUpdate(mac_ctx, rec->input, rec->length);
-        t = EVP_DigestSignFinal(mac_ctx, md, &md_size);
-        OPENSSL_assert(t > 0);
+        if (EVP_DigestSignUpdate(mac_ctx, header, sizeof(header)) <= 0
+                || EVP_DigestSignUpdate(mac_ctx, rec->input, rec->length) <= 0
+                || EVP_DigestSignFinal(mac_ctx, md, &md_size) <= 0) {
+            if (!stream_mac)
+                EVP_MD_CTX_cleanup(&hmac);
+            return -1;
+        }
 #ifdef OPENSSL_FIPS
         if (!send && FIPS_mode())
             tls_fips_digest_extra(ssl->enc_read_ctx,
@@ -1122,7 +1140,7 @@
         so = s->s3->server_opaque_prf_input;
         /*
          * must be same as col (see
-         * draft-resc-00.txts-opaque-prf-input-00.txt, section 3.1)
+         * draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1)
          */
         sol = s->s3->client_opaque_prf_input_len;
     }
diff --git a/src/third_party/openssl/openssl/ssl/t1_lib.c b/src/third_party/openssl/openssl/ssl/t1_lib.c
index 15f7aa8..9bd4e57 100644
--- a/src/third_party/openssl/openssl/ssl/t1_lib.c
+++ b/src/third_party/openssl/openssl/ssl/t1_lib.c
@@ -164,7 +164,7 @@
 {
 #ifndef OPENSSL_NO_TLSEXT
     if (s->tlsext_session_ticket) {
-        OPENSSL_free(s->tlsext_session_ticket);
+        OPENSSL_port_free(s->tlsext_session_ticket);
     }
 #endif                          /* OPENSSL_NO_TLSEXT */
     ssl3_free(s);
@@ -916,7 +916,7 @@
  * 10.8..10.8.3 (which don't work).
  */
 static void ssl_check_for_safari(SSL *s, const unsigned char *data,
-                                 const unsigned char *d, int n)
+                                 const unsigned char *limit)
 {
     unsigned short type, size;
     static const unsigned char kSafariExtensionsBlock[] = {
@@ -945,11 +945,11 @@
         0x02, 0x03,             /* SHA-1/ECDSA */
     };
 
-    if (data >= (d + n - 2))
+    if (data >= (limit - 2))
         return;
     data += 2;
 
-    if (data > (d + n - 4))
+    if (data > (limit - 4))
         return;
     n2s(data, type);
     n2s(data, size);
@@ -957,7 +957,7 @@
     if (type != TLSEXT_TYPE_server_name)
         return;
 
-    if (data + size > d + n)
+    if (data + size > limit)
         return;
     data += size;
 
@@ -965,7 +965,7 @@
         const size_t len1 = sizeof(kSafariExtensionsBlock);
         const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
 
-        if (data + len1 + len2 != d + n)
+        if (data + len1 + len2 != limit)
             return;
         if (OPENSSL_port_memcmp(data, kSafariExtensionsBlock, len1) != 0)
             return;
@@ -974,7 +974,7 @@
     } else {
         const size_t len = sizeof(kSafariExtensionsBlock);
 
-        if (data + len != d + n)
+        if (data + len != limit)
             return;
         if (OPENSSL_port_memcmp(data, kSafariExtensionsBlock, len) != 0)
             return;
@@ -984,8 +984,8 @@
 }
 # endif                         /* !OPENSSL_NO_EC */
 
-int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
-                                 int n, int *al)
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
+                                 unsigned char *limit, int *al)
 {
     unsigned short type;
     unsigned short size;
@@ -1007,34 +1007,34 @@
 
 # ifndef OPENSSL_NO_EC
     if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
-        ssl_check_for_safari(s, data, d, n);
+        ssl_check_for_safari(s, data, limit);
 # endif                         /* !OPENSSL_NO_EC */
 
 # ifndef OPENSSL_NO_SRP
     if (s->srp_ctx.login != NULL) {
-        OPENSSL_free(s->srp_ctx.login);
+        OPENSSL_port_free(s->srp_ctx.login);
         s->srp_ctx.login = NULL;
     }
 # endif
 
     s->srtp_profile = NULL;
 
-    if (data == d + n)
+    if (data == limit)
         goto ri_check;
 
-    if (data > (d + n - 2))
+    if (data > (limit - 2))
         goto err;
 
     n2s(data, len);
 
-    if (data > (d + n - len))
+    if (data + len != limit)
         goto err;
 
-    while (data <= (d + n - 4)) {
+    while (data <= (limit - 4)) {
         n2s(data, type);
         n2s(data, size);
 
-        if (data + size > (d + n))
+        if (data + size > (limit))
             goto err;
 # if 0
         OPENSSL_port_printferr("Received extension type %d size %d\n", type, size);
@@ -1106,7 +1106,7 @@
                             OPENSSL_port_memcpy(s->session->tlsext_hostname, sdata, len);
                             s->session->tlsext_hostname[len] = '\0';
                             if (OPENSSL_port_strlen(s->session->tlsext_hostname) != len) {
-                                OPENSSL_free(s->session->tlsext_hostname);
+                                OPENSSL_port_free(s->session->tlsext_hostname);
                                 s->session->tlsext_hostname = NULL;
                                 *al = TLS1_AD_UNRECOGNIZED_NAME;
                                 return 0;
@@ -1156,12 +1156,12 @@
                 goto err;
             if (!s->hit) {
                 if (s->session->tlsext_ecpointformatlist) {
-                    OPENSSL_free(s->session->tlsext_ecpointformatlist);
+                    OPENSSL_port_free(s->session->tlsext_ecpointformatlist);
                     s->session->tlsext_ecpointformatlist = NULL;
                 }
                 s->session->tlsext_ecpointformatlist_length = 0;
                 if ((s->session->tlsext_ecpointformatlist =
-                     OPENSSL_malloc(ecpointformatlist_length)) == NULL) {
+                     OPENSSL_port_malloc(ecpointformatlist_length)) == NULL) {
                     *al = TLS1_AD_INTERNAL_ERROR;
                     return 0;
                 }
@@ -1233,7 +1233,7 @@
 
             if (s->s3->client_opaque_prf_input != NULL) {
                 /* shouldn't really happen */
-                OPENSSL_free(s->s3->client_opaque_prf_input);
+                OPENSSL_port_free(s->s3->client_opaque_prf_input);
             }
 
             /* dummy byte just to get non-NULL */
@@ -1399,7 +1399,7 @@
     }
 
     /* Spurious data on the end */
-    if (data != d + n)
+    if (data != limit)
         goto err;
 
     *p = data;
@@ -1502,9 +1502,9 @@
             if (!s->hit) {
                 s->session->tlsext_ecpointformatlist_length = 0;
                 if (s->session->tlsext_ecpointformatlist != NULL)
-                    OPENSSL_free(s->session->tlsext_ecpointformatlist);
+                    OPENSSL_port_free(s->session->tlsext_ecpointformatlist);
                 if ((s->session->tlsext_ecpointformatlist =
-                     OPENSSL_malloc(ecpointformatlist_length)) == NULL) {
+                     OPENSSL_port_malloc(ecpointformatlist_length)) == NULL) {
                     *al = TLS1_AD_INTERNAL_ERROR;
                     return 0;
                 }
@@ -1556,7 +1556,7 @@
 
             if (s->s3->server_opaque_prf_input != NULL) {
                 /* shouldn't really happen */
-                OPENSSL_free(s->s3->server_opaque_prf_input);
+                OPENSSL_port_free(s->s3->server_opaque_prf_input);
             }
             if (s->s3->server_opaque_prf_input_len == 0) {
                 /* dummy byte just to get non-NULL */
@@ -1720,7 +1720,7 @@
     using_ecc = using_ecc && (s->version >= TLS1_VERSION);
     if (using_ecc) {
         if (s->tlsext_ecpointformatlist != NULL)
-            OPENSSL_free(s->tlsext_ecpointformatlist);
+            OPENSSL_port_free(s->tlsext_ecpointformatlist);
         if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) {
             SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,
                    ERR_R_MALLOC_FAILURE);
@@ -1735,11 +1735,11 @@
 
         /* we support all named elliptic curves in RFC 4492 */
         if (s->tlsext_ellipticcurvelist != NULL)
-            OPENSSL_free(s->tlsext_ellipticcurvelist);
+            OPENSSL_port_free(s->tlsext_ellipticcurvelist);
         s->tlsext_ellipticcurvelist_length =
             sizeof(pref_list) / sizeof(pref_list[0]) * 2;
         if ((s->tlsext_ellipticcurvelist =
-             OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL) {
+             OPENSSL_port_malloc(s->tlsext_ellipticcurvelist_length)) == NULL) {
             s->tlsext_ellipticcurvelist_length = 0;
             SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,
                    ERR_R_MALLOC_FAILURE);
@@ -1768,7 +1768,7 @@
         if (s->tlsext_opaque_prf_input != NULL) {
             if (s->s3->client_opaque_prf_input != NULL) {
                 /* shouldn't really happen */
-                OPENSSL_free(s->s3->client_opaque_prf_input);
+                OPENSSL_port_free(s->s3->client_opaque_prf_input);
             }
 
             if (s->tlsext_opaque_prf_input_len == 0) {
@@ -1818,7 +1818,7 @@
 
     if (using_ecc) {
         if (s->tlsext_ecpointformatlist != NULL)
-            OPENSSL_free(s->tlsext_ecpointformatlist);
+            OPENSSL_port_free(s->tlsext_ecpointformatlist);
         if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) {
             SSLerr(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT,
                    ERR_R_MALLOC_FAILURE);
@@ -1886,7 +1886,7 @@
 
         if (s->s3->server_opaque_prf_input != NULL) {
             /* shouldn't really happen */
-            OPENSSL_free(s->s3->server_opaque_prf_input);
+            OPENSSL_port_free(s->s3->server_opaque_prf_input);
         }
         s->s3->server_opaque_prf_input = NULL;
 
@@ -2084,22 +2084,20 @@
     }
 # endif
 
+    OPENSSL_port_free(s->tlsext_ocsp_resp);
+    s->tlsext_ocsp_resp = NULL;
+    s->tlsext_ocsp_resplen = -1;
     /*
      * If we've requested certificate status and we wont get one tell the
      * callback
      */
     if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
-        && s->ctx && s->ctx->tlsext_status_cb) {
+        && !(s->hit) && s->ctx && s->ctx->tlsext_status_cb) {
         int r;
         /*
-         * Set resp to NULL, resplen to -1 so callback knows there is no
-         * response.
+         * Call callback with resp == NULL and resplen == -1 so callback
+         * knows there is no response
          */
-        if (s->tlsext_ocsp_resp) {
-            OPENSSL_free(s->tlsext_ocsp_resp);
-            s->tlsext_ocsp_resp = NULL;
-        }
-        s->tlsext_ocsp_resplen = -1;
         r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
         if (r == 0) {
             al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
@@ -2294,10 +2292,13 @@
         /* Check key name matches */
         if (OPENSSL_port_memcmp(etick, tctx->tlsext_tick_key_name, 16))
             return 2;
-        HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
-                     tlsext_tick_md(), NULL);
-        EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
-                           tctx->tlsext_tick_aes_key, etick + 16);
+        if (HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+                         tlsext_tick_md(), NULL) <= 0
+                || EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+                                      tctx->tlsext_tick_aes_key,
+                                      etick + 16) <= 0) {
+            goto err;
+       }
     }
     /*
      * Attempt to process session ticket, first conduct sanity and integrity
@@ -2305,13 +2306,14 @@
      */
     mlen = HMAC_size(&hctx);
     if (mlen < 0) {
-        EVP_CIPHER_CTX_cleanup(&ctx);
-        return -1;
+        goto err;
     }
     eticklen -= mlen;
     /* Check HMAC of encrypted ticket */
-    HMAC_Update(&hctx, etick, eticklen);
-    HMAC_Final(&hctx, tick_hmac, NULL);
+    if (HMAC_Update(&hctx, etick, eticklen) <= 0
+            || HMAC_Final(&hctx, tick_hmac, NULL) <= 0) {
+        goto err;
+    }
     HMAC_CTX_cleanup(&hctx);
     if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) {
         EVP_CIPHER_CTX_cleanup(&ctx);
@@ -2322,14 +2324,13 @@
     p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
     eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
     sdec = OPENSSL_malloc(eticklen);
-    if (!sdec) {
+    if (!sdec || EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen) <= 0) {
         EVP_CIPHER_CTX_cleanup(&ctx);
         return -1;
     }
-    EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
     if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0) {
         EVP_CIPHER_CTX_cleanup(&ctx);
-        OPENSSL_free(sdec);
+        OPENSSL_port_free(sdec);
         return 2;
     }
     slen += mlen;
@@ -2337,7 +2338,7 @@
     p = sdec;
 
     sess = d2i_SSL_SESSION(NULL, &p, slen);
-    OPENSSL_free(sdec);
+    OPENSSL_port_free(sdec);
     if (sess) {
         /*
          * The session ID, if non-empty, is used by some clients to detect
@@ -2359,6 +2360,10 @@
      * For session parse failure, indicate that we need to send a new ticket.
      */
     return 2;
+err:
+    EVP_CIPHER_CTX_cleanup(&ctx);
+    HMAC_CTX_cleanup(&hctx);
+    return -1;
 }
 
 /* Tables to translate from NIDs to TLS v1.2 ids */
@@ -2586,7 +2591,7 @@
         bp += payload;
         /* Random padding */
         if (RAND_pseudo_bytes(bp, padding) < 0) {
-            OPENSSL_free(buffer);
+            OPENSSL_port_free(buffer);
             return -1;
         }
 
@@ -2598,7 +2603,7 @@
                             buffer, 3 + payload + padding,
                             s, s->msg_callback_arg);
 
-        OPENSSL_free(buffer);
+        OPENSSL_port_free(buffer);
 
         if (r < 0)
             return r;
@@ -2693,7 +2698,7 @@
     }
 
 err:
-    OPENSSL_free(buf);
+    OPENSSL_port_free(buf);
 
     return ret;
 }
diff --git a/src/third_party/openssl/openssl/ssl/tls1.h b/src/third_party/openssl/openssl/ssl/tls1.h
index 69d8186..91504b1 100644
--- a/src/third_party/openssl/openssl/ssl/tls1.h
+++ b/src/third_party/openssl/openssl/ssl/tls1.h
@@ -235,8 +235,7 @@
 
 /*
  * ExtensionType value for TLS padding extension.
- * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
- * http://tools.ietf.org/html/draft-agl-tls-padding-03
+ * http://tools.ietf.org/html/draft-agl-tls-padding
  */
 # define TLSEXT_TYPE_padding     21
 
@@ -261,20 +260,19 @@
 #  define TLSEXT_TYPE_next_proto_neg              13172
 # endif
 
-/* NameType value from RFC 3546 */
+/* NameType value from RFC3546 */
 # define TLSEXT_NAMETYPE_host_name 0
-/* status request value from RFC 3546 */
+/* status request value from RFC3546 */
 # define TLSEXT_STATUSTYPE_ocsp 1
 
-/* ECPointFormat values from draft-ietf-tls-ecc-12 */
+/* ECPointFormat values from RFC4492 */
 # define TLSEXT_ECPOINTFORMAT_first                      0
 # define TLSEXT_ECPOINTFORMAT_uncompressed               0
 # define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime  1
 # define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2  2
 # define TLSEXT_ECPOINTFORMAT_last                       2
 
-/* Signature and hash algorithms from RFC 5246 */
-
+/* Signature and hash algorithms from RFC5246 */
 # define TLSEXT_signature_anonymous                      0
 # define TLSEXT_signature_rsa                            1
 # define TLSEXT_signature_dsa                            2
@@ -404,7 +402,6 @@
 # define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA                0x03000066
 
 /* AES ciphersuites from RFC3268 */
-
 # define TLS1_CK_RSA_WITH_AES_128_SHA                    0x0300002F
 # define TLS1_CK_DH_DSS_WITH_AES_128_SHA                 0x03000030
 # define TLS1_CK_DH_RSA_WITH_AES_128_SHA                 0x03000031
@@ -570,7 +567,7 @@
 # define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA               "DHE-RSA-AES256-SHA"
 # define TLS1_TXT_ADH_WITH_AES_256_SHA                   "ADH-AES256-SHA"
 
-/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */
+/* ECC ciphersuites from RFC4492 */
 # define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA               "ECDH-ECDSA-NULL-SHA"
 # define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA            "ECDH-ECDSA-RC4-SHA"
 # define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA       "ECDH-ECDSA-DES-CBC3-SHA"
diff --git a/src/third_party/openssl/openssl/test/Makefile b/src/third_party/openssl/openssl/test/Makefile
index eca1400..0afae14 100644
--- a/src/third_party/openssl/openssl/test/Makefile
+++ b/src/third_party/openssl/openssl/test/Makefile
@@ -67,6 +67,7 @@
 HEARTBEATTEST=  heartbeat_test
 CONSTTIMETEST=  constant_time_test
 VERIFYEXTRATEST=	verify_extra_test
+CLIENTHELLOTEST=	clienthellotest
 
 TESTS=		alltests
 
@@ -78,7 +79,8 @@
 	$(RANDTEST)$(EXE_EXT) $(DHTEST)$(EXE_EXT) $(ENGINETEST)$(EXE_EXT) \
 	$(BFTEST)$(EXE_EXT) $(CASTTEST)$(EXE_EXT) $(SSLTEST)$(EXE_EXT) $(EXPTEST)$(EXE_EXT) $(DSATEST)$(EXE_EXT) $(RSATEST)$(EXE_EXT) \
 	$(EVPTEST)$(EXE_EXT) $(EVPEXTRATEST)$(EXE_EXT) $(IGETEST)$(EXE_EXT) $(JPAKETEST)$(EXE_EXT) $(SRPTEST)$(EXE_EXT) \
-	$(ASN1TEST)$(EXE_EXT) $(HEARTBEATTEST)$(EXE_EXT) $(CONSTTIMETEST)$(EXE_EXT) $(VERIFYEXTRATEST)$(EXE_EXT)
+	$(ASN1TEST)$(EXE_EXT) $(HEARTBEATTEST)$(EXE_EXT) $(CONSTTIMETEST)$(EXE_EXT) $(VERIFYEXTRATEST)$(EXE_EXT) \
+	$(CLIENTHELLOTEST)$(EXE_EXT)
 
 # $(METHTEST)$(EXE_EXT)
 
@@ -91,7 +93,8 @@
 	$(RANDTEST).o $(DHTEST).o $(ENGINETEST).o $(CASTTEST).o \
 	$(BFTEST).o  $(SSLTEST).o  $(DSATEST).o  $(EXPTEST).o $(RSATEST).o \
 	$(EVPTEST).o $(EVPEXTRATEST).o $(IGETEST).o $(JPAKETEST).o $(ASN1TEST).o \
-	$(HEARTBEATTEST).o $(CONSTTIMETEST).o $(VERIFYEXTRATEST).o
+	$(HEARTBEATTEST).o $(CONSTTIMETEST).o $(VERIFYEXTRATEST).o \
+	$(CLIENTHELLOTEST).o
 
 SRC=	$(BNTEST).c $(ECTEST).c  $(ECDSATEST).c $(ECDHTEST).c $(IDEATEST).c \
 	$(MD2TEST).c  $(MD4TEST).c $(MD5TEST).c \
@@ -101,7 +104,8 @@
 	$(RANDTEST).c $(DHTEST).c $(ENGINETEST).c $(CASTTEST).c \
 	$(BFTEST).c  $(SSLTEST).c $(DSATEST).c   $(EXPTEST).c $(RSATEST).c \
 	$(EVPTEST).c $(EVPEXTRATEST).c $(IGETEST).c $(JPAKETEST).c $(SRPTEST).c $(ASN1TEST).c \
-	$(HEARTBEATTEST).c $(CONSTTIMETEST).c $(VERIFYEXTRATEST).c
+	$(HEARTBEATTEST).c $(CONSTTIMETEST).c $(VERIFYEXTRATEST).c \
+	$(CLIENTHELLOTEST).c
 
 EXHEADER= 
 HEADER=	$(EXHEADER)
@@ -144,7 +148,8 @@
 	test_enc test_x509 test_rsa test_crl test_sid \
 	test_gen test_req test_pkcs7 test_verify test_dh test_dsa \
 	test_ss test_ca test_engine test_evp test_evp_extra test_ssl test_tsa test_ige \
-	test_jpake test_srp test_cms test_heartbeat test_constant_time test_verify_extra
+	test_jpake test_srp test_cms test_heartbeat test_constant_time test_verify_extra \
+	test_clienthello
 
 test_evp:
 	../util/shlib_wrap.sh ./$(EVPTEST) evptests.txt
@@ -339,6 +344,10 @@
 	@echo $(START) $@
 	../util/shlib_wrap.sh ./$(VERIFYEXTRATEST)
 
+test_clienthello: $(CLIENTHELLOTEST)$(EXE_EXT)
+	@echo $(START) $@
+	../util/shlib_wrap.sh ./$(CLIENTHELLOTEST)
+
 lint:
 	lint -DLINT $(INCLUDES) $(SRC)>fluff
 
@@ -510,6 +519,9 @@
 $(VERIFYEXTRATEST)$(EXE_EXT): $(VERIFYEXTRATEST).o
 	@target=$(VERIFYEXTRATEST) $(BUILD_CMD)
 
+$(CLIENTHELLOTEST)$(EXE_EXT): $(CLIENTHELLOTEST).o
+	@target=$(CLIENTHELLOTEST) $(BUILD_CMD)
+
 #$(AESTEST).o: $(AESTEST).c
 #	$(CC) -c $(CFLAGS) -DINTERMEDIATE_VALUE_KAT -DTRACE_KAT_MCT $(AESTEST).c
 
@@ -555,6 +567,26 @@
 bntest.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h bntest.c
 casttest.o: ../e_os.h ../include/openssl/cast.h ../include/openssl/e_os2.h
 casttest.o: ../include/openssl/opensslconf.h casttest.c
+clienthellotest.o: ../include/openssl/asn1.h ../include/openssl/bio.h
+clienthellotest.o: ../include/openssl/buffer.h ../include/openssl/comp.h
+clienthellotest.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
+clienthellotest.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
+clienthellotest.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
+clienthellotest.o: ../include/openssl/err.h ../include/openssl/evp.h
+clienthellotest.o: ../include/openssl/hmac.h ../include/openssl/kssl.h
+clienthellotest.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
+clienthellotest.o: ../include/openssl/objects.h
+clienthellotest.o: ../include/openssl/opensslconf.h
+clienthellotest.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
+clienthellotest.o: ../include/openssl/pem.h ../include/openssl/pem2.h
+clienthellotest.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
+clienthellotest.o: ../include/openssl/safestack.h ../include/openssl/sha.h
+clienthellotest.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
+clienthellotest.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
+clienthellotest.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+clienthellotest.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+clienthellotest.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+clienthellotest.o: clienthellotest.c
 constant_time_test.o: ../crypto/constant_time_locl.h ../e_os.h
 constant_time_test.o: ../include/openssl/e_os2.h
 constant_time_test.o: ../include/openssl/opensslconf.h constant_time_test.c
diff --git a/src/third_party/openssl/openssl/test/igetest.c b/src/third_party/openssl/openssl/test/igetest.c
index 0c7b357..08f361a 100644
--- a/src/third_party/openssl/openssl/test/igetest.c
+++ b/src/third_party/openssl/openssl/test/igetest.c
@@ -1,4 +1,4 @@
-/* test/igetest.c -*- mode:C; c-file-style: "eay" -*- */
+/* test/igetest.c */
 /* ====================================================================
  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
  *
diff --git a/src/third_party/openssl/openssl/util/indent.pro b/src/third_party/openssl/openssl/util/indent.pro
index e871431..4dcda5d 100644
--- a/src/third_party/openssl/openssl/util/indent.pro
+++ b/src/third_party/openssl/openssl/util/indent.pro
@@ -749,3 +749,19 @@
 -T ssl_trace_tbl
 -T _stdcall
 -T tls12_lookup
+-T OPTIONS
+-T OPT_PAIR
+-T uint64_t
+-T int64_t
+-T uint32_t
+-T int32_t
+-T uint16_t
+-T int16_t
+-T uint8_t
+-T int8_t
+-T STRINT_PAIR
+-T felem
+-T felem_bytearray
+-T SH_LIST
+-T PACKET
+-T RECORD_LAYER
diff --git a/src/third_party/openssl/openssl/util/mk1mf.pl b/src/third_party/openssl/openssl/util/mk1mf.pl
index 1eee7aa..5b86aa7 100755
--- a/src/third_party/openssl/openssl/util/mk1mf.pl
+++ b/src/third_party/openssl/openssl/util/mk1mf.pl
@@ -424,7 +424,7 @@
 $defs= <<"EOF";
 # This makefile has been automatically generated from the OpenSSL distribution.
 # This single makefile will build the complete OpenSSL distribution and
-# by default leave the 'intertesting' output files in .${o}out and the stuff
+# by default leave the 'interesting' output files in .${o}out and the stuff
 # that needs deleting in .${o}tmp.
 # The file was generated by running 'make makefile.one', which
 # does a 'make files', which writes all the environment variables from all
diff --git a/src/third_party/openssl/openssl/util/mkrc.pl b/src/third_party/openssl/openssl/util/mkrc.pl
old mode 100644
new mode 100755
index 0ceadcf..83ee6a4
--- a/src/third_party/openssl/openssl/util/mkrc.pl
+++ b/src/third_party/openssl/openssl/util/mkrc.pl
@@ -57,7 +57,7 @@
             VALUE "ProductVersion", "$version\\0"
             // Optional:
             //VALUE "Comments", "\\0"
-            VALUE "LegalCopyright", "Copyright © 1998-2006 The OpenSSL Project. Copyright © 1995-1998 Eric A. Young, Tim J. Hudson. All rights reserved.\\0"
+            VALUE "LegalCopyright", "Copyright © 1998-2006 The OpenSSL Project. Copyright © 1995-1998 Eric A. Young, Tim J. Hudson. All rights reserved.\\0"
             //VALUE "LegalTrademarks", "\\0"
             //VALUE "PrivateBuild", "\\0"
             //VALUE "SpecialBuild", "\\0"
diff --git a/src/third_party/openssl/openssl/util/mkstack.pl b/src/third_party/openssl/openssl/util/mkstack.pl
index f708610..a86d91f 100755
--- a/src/third_party/openssl/openssl/util/mkstack.pl
+++ b/src/third_party/openssl/openssl/util/mkstack.pl
@@ -97,7 +97,7 @@
 EOF
 	}
 
-	foreach $type_thing (sort @sstacklst) {
+    foreach $type_thing (sort { $a->[0] cmp $b->[0]} @sstacklst) {
 	    my $t1 = $type_thing->[0];
 	    my $t2 = $type_thing->[1];
 	    $new_stackfile .= <<EOF;
diff --git a/src/third_party/openssl/openssl/util/pl/VC-32.pl b/src/third_party/openssl/openssl/util/pl/VC-32.pl
index b597998..88f0f7a 100644
--- a/src/third_party/openssl/openssl/util/pl/VC-32.pl
+++ b/src/third_party/openssl/openssl/util/pl/VC-32.pl
@@ -342,15 +342,21 @@
 	local($ret,$_);
 	$file =~ s/\//$o/g if $o ne '/';
 	$n=&bname($target);
-	$ret.="$target: $files $dep_libs\n";
+	$ret.="$target: $files $dep_libs";
 	if ($standalone == 1)
 		{
+		$ret.=" \$(OBJ_D)${o}applink.obj" if $shlib;
+		$ret.="\n";
 		$ret.="  \$(LINK) \$(LFLAGS) $efile$target @<<\n\t";
-		$ret.= "\$(EX_LIBS) " if ($files =~ /O_FIPSCANISTER/ && !$fipscanisterbuild);
+		if ($files =~ /O_FIPSCANISTER/ && !$fipscanisterbuild) {
+			$ret.= "\$(EX_LIBS) ";
+			$ret.= "\$(OBJ_D)${o}applink.obj " if $shlib;
+		}
 		$ret.="$files $libs\n<<\n";
 		}
 	elsif ($standalone == 2)
 		{
+		$ret.="\n";
 		$ret.="\tSET FIPS_LINK=\$(LINK)\n";
 		$ret.="\tSET FIPS_CC=\$(CC)\n";
 		$ret.="\tSET FIPS_CC_ARGS=/Fo\$(OBJ_D)${o}fips_premain.obj \$(SHLIB_CFLAGS) -c\n";
@@ -363,6 +369,7 @@
 		}
 	else
 		{
+		$ret.="\n";
 		$ret.="\t\$(LINK) \$(LFLAGS) $efile$target @<<\n";
 		$ret.="\t\$(APP_EX_OBJ) $files $libs\n<<\n";
 		}
diff --git a/src/third_party/openssl/openssl/util/selftest.pl b/src/third_party/openssl/openssl/util/selftest.pl
old mode 100755
new mode 100644
index 7b32e9f..59842ef
--- a/src/third_party/openssl/openssl/util/selftest.pl
+++ b/src/third_party/openssl/openssl/util/selftest.pl
@@ -199,3 +199,4 @@
 }
 print "\nTest report in file $report\n";
 
+die if $ok != 2;
diff --git a/src/third_party/openssl/openssl/util/toutf8.sh b/src/third_party/openssl/openssl/util/toutf8.sh
new file mode 100644
index 0000000..8a4254b
--- /dev/null
+++ b/src/third_party/openssl/openssl/util/toutf8.sh
@@ -0,0 +1,17 @@
+#! /bin/sh
+#
+# Very simple script to detect and convert files that we want to re-encode to UTF8
+
+git ls-tree -r --name-only HEAD | \
+    while read F; do
+	charset=`file -bi "$F" | sed -e 's|.*charset=||'`
+	if [ "$charset" != "utf-8" -a "$charset" != "binary" -a "$charset" != "us-ascii" ]; then
+	    iconv -f ISO-8859-1 -t UTF8 < "$F" > "$F.utf8" && \
+		( cmp -s "$F" "$F.utf8" || \
+			( echo "$F"
+			  mv "$F" "$F.iso-8859-1"
+			  mv "$F.utf8" "$F"
+			)
+		)
+	fi
+    done
diff --git a/src/tools/clang/scripts/update.py b/src/tools/clang/scripts/update.py
index ddd9098..785a0d8 100755
--- a/src/tools/clang/scripts/update.py
+++ b/src/tools/clang/scripts/update.py
@@ -421,7 +421,7 @@
 
 
 # Clobber the out/ folder for configs that use clang.
-def ClobberOutFolderForClang():
+def ClobberOutFolderForClang(toolchain_timestamp):
   should_wipe_out_folder = None
 
   directory_name_of_current_file = os.path.dirname(os.path.abspath(__file__))
@@ -435,19 +435,12 @@
   out_subdirs = [os.path.join(out_dir, d)
                  for d in os.listdir(out_dir)]
   for build_folder in filter(os.path.isdir, out_subdirs):
-    if not os.path.exists(os.path.join(build_folder, 'build.ninja')):
+    build_file = os.path.join(build_folder, 'build.ninja')
+
+    if not os.path.exists(build_file):
       continue
 
-    package_version_filename = os.path.join(build_folder, 'cr_build_revision')
-    package_version = None
-    try:
-      with open(package_version_filename, 'r') as f:
-        package_version = f.read()
-    except IOError:
-      # File does not exist
-      pass
-
-    if package_version == PACKAGE_VERSION:
+    if os.path.getmtime(build_file) >= toolchain_timestamp:
       continue
 
     if should_wipe_out_folder is None:
@@ -458,8 +451,10 @@
 
     RunCommand(['ninja', '-C', build_folder, '-t', 'clean'])
 
-    with open(package_version_filename, 'w') as f:
-      f.write(PACKAGE_VERSION)
+    # Update the build file's timestamp to signal that this folder is now
+    # up-to-date. The gyp step will write new build files anyway, but this may
+    # be a config which is NOT being gyp'd.
+    os.utime(build_file, (toolchain_timestamp, toolchain_timestamp))
 
 
 def UpdateClang(args):
@@ -467,12 +462,12 @@
   # Required for LTO, which is used when is_official_build = true.
   need_gold_plugin = sys.platform.startswith('linux')
 
-  ClobberOutFolderForClang()
-
   if ReadStampFile(
       STAMP_FILE) == PACKAGE_VERSION and not args.force_local_build:
     if not need_gold_plugin or os.path.exists(
         os.path.join(LLVM_BUILD_DIR, "lib/LLVMgold.so")):
+      # Always check to clobber stale builds.
+      ClobberOutFolderForClang(os.path.getmtime(STAMP_FILE))
       return 0
 
   print 'Updating Clang to %s...' % PACKAGE_VERSION
@@ -506,6 +501,7 @@
             LLVM_BUILD_DIR, PACKAGE_VERSION
         ])
       WriteStampFile(PACKAGE_VERSION, STAMP_FILE)
+      ClobberOutFolderForClang(os.path.getmtime(STAMP_FILE))
       return 0
     except urllib2.URLError:
       print 'Failed to download prebuilt clang %s' % cds_file
@@ -906,6 +902,7 @@
     RunCommand(['ninja', 'check-all'], msvc_arch='x64')
 
   WriteStampFile(PACKAGE_VERSION, STAMP_FILE)
+  ClobberOutFolderForClang(os.path.getmtime(STAMP_FILE))
   print 'Clang update was successful.'
   return 0
 
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py
index e4eaa84..53a0081 100755
--- a/src/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -76,6 +76,10 @@
 is_linux = platform.system() == 'Linux'
 is_windows = platform.system() == 'Windows'
 
+microsoft_flavors = ['win', 'xb1', 'xb1-future']
+sony_flavors = ['ps3', 'ps4']
+windows_host_flavors = microsoft_flavors + sony_flavors
+
 def StripPrefix(arg, prefix):
   if arg.startswith(prefix):
     return arg[len(prefix):]
@@ -89,9 +93,9 @@
   # whitelist common OK ones and quote anything else.
   if re.match(r'^[a-zA-Z0-9_=.\\/-]+$', arg):
     return arg  # No quoting necessary.
-  if flavor in ['win', 'xb1']:
+  if flavor in microsoft_flavors:
     return gyp.msvs_emulation.QuoteForRspFile(arg)
-  elif flavor in ['ps3', 'ps4'] :
+  elif flavor in sony_flavors :
     # Escape double quotes.
     return '"' + arg.replace('\"', '\\\"') + '"'
   return "'" + arg.replace("'", "'" + '"\'"' + "'")  + "'"
@@ -100,7 +104,7 @@
 def Define(d, flavor):
   """Takes a preprocessor define and returns a -D parameter that's ninja- and
   shell-escaped."""
-  if flavor in ['win', 'xb1']:
+  if flavor in microsoft_flavors:
     # cl.exe replaces literal # characters with = in preprocesor definitions for
     # some reason. Octal-encode to work around that.
     d = d.replace('#', '\\%03o' % ord('#'))
@@ -183,7 +187,7 @@
     # For bundles, the .TOC should be produced for the binary, not for
     # FinalOutput(). But the naive approach would put the TOC file into the
     # bundle, so don't do this for bundles for now.
-    if flavor in ['win', 'xb1', 'ps3', 'ps4'] or self.bundle:
+    if flavor in windows_host_flavors or self.bundle:
       return False
     return self.type in ('shared_library', 'loadable_module')
 
@@ -251,7 +255,7 @@
 
     self.abs_build_dir = abs_build_dir
     self.obj_ext = '.obj' if flavor == 'win' else '.o'
-    if flavor in ['win', 'ps3', 'xb1', 'ps4']:
+    if flavor in windows_host_flavors:
       # See docstring of msvs_emulation.GenerateEnvironmentFiles().
       self.win_env = {}
       for arch in ('x86', 'x64'):
@@ -322,7 +326,7 @@
     if env:
       if self.flavor == 'mac':
         path = gyp.xcode_emulation.ExpandEnvVars(path, env)
-      elif self.flavor in ['win', 'xb1']:
+      elif self.flavor in microsoft_flavors:
         path = gyp.msvs_emulation.ExpandMacros(path, env)
     if path.startswith('$!'):
       expanded = self.ExpandSpecial(path)
@@ -411,7 +415,7 @@
     self.xcode_settings = self.msvs_settings = None
     if self.flavor == 'mac':
       self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec)
-    if (self.flavor in ['win', 'ps3', 'xb1', 'ps4']
+    if (self.flavor in windows_host_flavors
         and is_windows):
       self.msvs_settings = gyp.msvs_emulation.MsvsSettings(spec,
                                                            generator_flags)
@@ -461,7 +465,7 @@
     sources = spec.get('sources', []) + extra_sources
     if sources:
       pch = None
-      if self.flavor in ['win', 'xb1']:
+      if self.flavor in microsoft_flavors:
         gyp.msvs_emulation.VerifyMissingSources(
             sources, self.abs_build_dir, generator_flags, self.GypPathToNinja)
         pch = gyp.msvs_emulation.PrecompiledHeader(
@@ -477,7 +481,7 @@
       link_deps += [self.GypPathToNinja(f)
           for f in sources if f.endswith(self.obj_ext)]
 
-    if self.flavor in ['win', 'xb1'] and self.target.type == 'static_library':
+    if self.flavor in microsoft_flavors and self.target.type == 'static_library':
       self.target.component_objs = link_deps
 
     # Write out a link step, if needed.
@@ -524,7 +528,7 @@
 
   def WriteWinIdlFiles(self, spec, prebuild):
     """Writes rules to match MSVS's implicit idl handling."""
-    assert self.flavor in ('win', 'xb1')
+    assert self.flavor in microsoft_flavors
     if self.msvs_settings.HasExplicitIdlRules(spec):
       return []
     outputs = []
@@ -573,7 +577,7 @@
       return '%s %s: %s' % (verb, self.name, fallback)
 
   def IsCygwinRule(self, action):
-    if self.flavor in ['ps3', 'ps4']:
+    if self.flavor in sony_flavors:
       return str(action.get('msvs_cygwin_shell', 1)) != '0'
     return False
 
@@ -806,7 +810,7 @@
                     self.xcode_settings.GetCflagsObjC(config_name)
       cflags_objcc = ['$cflags_cc'] + \
                      self.xcode_settings.GetCflagsObjCC(config_name)
-    elif self.flavor in ['win', 'xb1']:
+    elif self.flavor in microsoft_flavors:
       cflags = self.msvs_settings.GetCflags(config_name)
       cflags_c = self.msvs_settings.GetCflagsC(config_name)
       cflags_cc = self.msvs_settings.GetCflagsCC(config_name)
@@ -829,7 +833,7 @@
 
     defines = config.get('defines', []) + extra_defines
     self.WriteVariableList('defines', [Define(d, self.flavor) for d in defines])
-    if self.flavor in ['win', 'xb1']:
+    if self.flavor in microsoft_flavors:
       self.WriteVariableList('rcflags',
           [QuoteShellArgument(self.ExpandSpecial(f), self.flavor)
            for f in self.msvs_settings.GetRcflags(config_name,
@@ -838,7 +842,7 @@
     include_dirs = config.get('include_dirs', [])
     include_dirs += config.get('include_dirs_' + self.toolset, [])
 
-    if self.flavor in ['win', 'xb1']:
+    if self.flavor in microsoft_flavors:
       include_dirs = self.msvs_settings.AdjustIncludeDirs(include_dirs,
                                                           config_name)
       self.WriteVariableList('includes',
@@ -897,7 +901,7 @@
         command = 'objc'
       elif self.flavor == 'mac' and ext == 'mm':
         command = 'objcxx'
-      elif self.flavor in ['win', 'xb1'] and ext == 'rc':
+      elif self.flavor in microsoft_flavors and ext == 'rc':
         command = 'rc'
         obj_ext = '.res'
       else:
@@ -910,7 +914,7 @@
       output = self.GypPathToUniqueOutput(filename + obj_ext)
       implicit = precompiled_header.GetObjDependencies([input], [output])
       variables = []
-      if self.flavor in ['win', 'xb1']:
+      if self.flavor in microsoft_flavors:
         variables, output, implicit = precompiled_header.GetFlagsModifications(
             input, output, implicit, command, cflags_c, cflags_cc,
             self.ExpandSpecial)
@@ -966,10 +970,10 @@
           continue
         linkable = target.Linkable()
         if linkable:
-          if (self.flavor in ['win', 'xb1'] and target.component_objs and
+          if (self.flavor in microsoft_flavors and target.component_objs and
               self.msvs_settings.IsUseLibraryDependencyInputs(config_name)):
             extra_link_deps.extend(target.component_objs)
-          elif (self.flavor in ['win', 'xb1', 'ps3'] and
+          elif (self.flavor in (microsoft_flavors + ['ps3']) and
                 target.import_lib):
             extra_link_deps.append(target.import_lib)
           elif target.UsesToc(self.flavor):
@@ -1000,7 +1004,7 @@
       ldflags = self.xcode_settings.GetLdflags(config_name,
           self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
           self.GypPathToNinja)
-    elif self.flavor in ['win', 'xb1']:
+    elif self.flavor in microsoft_flavors:
       libflags = self.msvs_settings.GetLibFlags(config_name,
                                                 self.GypPathToNinja)
       self.WriteVariableList(
@@ -1034,7 +1038,7 @@
 
     if self.flavor == 'mac':
       libraries = self.xcode_settings.AdjustLibraries(libraries)
-    elif self.flavor in ['win', 'xb1']:
+    elif self.flavor in microsoft_flavors:
       libraries = self.msvs_settings.AdjustLibraries(libraries)
     self.WriteVariableList('libs', libraries)
 
@@ -1044,7 +1048,7 @@
       extra_bindings.append(('soname', os.path.split(output)[1]))
       extra_bindings.append(('lib',
                             gyp.common.EncodePOSIXShellArgument(output)))
-      if self.flavor in ['win', 'xb1']:
+      if self.flavor in microsoft_flavors:
         extra_bindings.append(('dll', output))
         if '/NOENTRY' not in ldflags:
           self.target.import_lib = output + '.lib'
@@ -1110,7 +1114,7 @@
     elif spec['type'] == 'static_library':
       self.target.binary = self.ComputeOutput(spec)
       variables = []
-      if self.flavor in ('win', 'xb1'):
+      if self.flavor in microsoft_flavors:
         libflags = self.msvs_settings.GetLibFlags(config_name,
                                                   self.GypPathToNinja)
         variables.append(('libflags', ' '.join(libflags)))
@@ -1121,7 +1125,7 @@
       if self.xcode_settings:
         variables.append(('libtool_flags',
                           self.xcode_settings.GetLibtoolflags(config_name)))
-      if (self.flavor not in ('mac', 'win', 'xb1') and not
+      if (self.flavor not in (['mac'] + microsoft_flavors) and not
           self.is_standalone_static_library):
         command = 'alink_thin'
       else:
@@ -1373,7 +1377,7 @@
     rspfile = None
     rspfile_content = None
     args = [self.ExpandSpecial(arg, self.base_to_build) for arg in args]
-    if (self.flavor in ['win', 'ps3', 'xb1', 'ps4']
+    if (self.flavor in windows_host_flavors
         and is_windows):
       rspfile = rule_name + '.$unique_name.rsp'
       # The cygwin case handles this inside the bash sub-shell.
@@ -1424,7 +1428,7 @@
     global generator_extra_sources_for_rules
     generator_extra_sources_for_rules = getattr(xcode_generator,
         'generator_extra_sources_for_rules', [])
-  elif flavor in ['win', 'xb1']:
+  elif flavor in microsoft_flavors:
     default_variables.setdefault('OS', 'win')
     default_variables['EXECUTABLE_SUFFIX'] = '.exe'
     default_variables['STATIC_LIB_PREFIX'] = ''
@@ -1600,14 +1604,14 @@
   # - If there is no 'make_global_settings' for CC.host/CXX.host or
   #   'CC_host'/'CXX_host' enviroment variable, cc_host/cxx_host should be set
   #   to cc/cxx.
-  if (flavor == 'win' or (flavor in ['ps3', 'ps4'] and is_windows)):
+  if (flavor == 'win' or (flavor in sony_flavors and is_windows)):
     cc = 'cl.exe'
     cxx = 'cl.exe'
     ld = 'link.exe'
     gyp.msvs_emulation.GenerateEnvironmentFiles(
         toplevel_build, generator_flags, OpenOutput)
     ld_host = '$ld'
-  elif flavor == 'xb1':
+  elif flavor in ['xb1', 'xb1-future']:
     cc = 'cl.exe'
     cxx = 'cl.exe'
     ld = 'link.exe'
@@ -1665,14 +1669,14 @@
     python_exec = sys.executable
 
   ar_flags = ''
-  if flavor in ['win', 'xb1']:
+  if flavor in microsoft_flavors:
     master_ninja.variable('ld', ld)
     master_ninja.variable('ar', os.environ.get('AR', 'ar'))
     master_ninja.variable('rc', 'rc.exe')
     master_ninja.variable('asm', 'ml.exe')
     master_ninja.variable('mt', 'mt.exe')
     master_ninja.variable('use_dep_database', '1')
-  elif flavor in ['ps3', 'ps4']:
+  elif flavor in sony_flavors:
     # Require LD to be set.
     master_ninja.variable('ld', os.environ.get('LD'))
     master_ninja.variable('ar', os.environ.get('AR', 'ar'))
@@ -1728,8 +1732,8 @@
   master_ninja.pool('link_pool', depth=GetDefaultConcurrentLinks())
   master_ninja.newline()
 
-  if flavor not in ['win', 'xb1']:
-    if flavor in ['ps3', 'ps4'] :
+  if flavor not in microsoft_flavors:
+    if flavor in sony_flavors :
       # uca := Unnamed Console A
       dep_format = 'snc' if (flavor in ['ps3']) else 'uca'
       master_ninja.rule(
@@ -1809,14 +1813,14 @@
                '$arch $asm $defines $includes /c /Fo $out $in' %
                python_exec))
 
-  if flavor not in ['mac', 'win', 'xb1']:
+  if flavor not in (['mac'] + microsoft_flavors):
     alink_command = 'rm -f $out && $ar $arFlags $out @$out.rsp'
     # TODO: Use rcsT on Linux only.
     alink_thin_command = 'rm -f $out && $ar $arThinFlags $out @$out.rsp'
 
     ld_cmd = '$ld'
 
-    if flavor in ['ps3', 'ps4'] and is_windows:
+    if flavor in sony_flavors and is_windows:
       alink_command = 'cmd.exe /c ' + alink_command
       alink_thin_command = 'cmd.exe /c ' + alink_thin_command
       ld_cmd = '%s gyp-win-tool link-wrapper $arch $ld' % python_exec
@@ -1889,7 +1893,7 @@
         command=(mtime_preserving_solink_base % {
             'suffix': '-Wl,--start-group $in $solibs -Wl,--end-group $libs'}))
 
-    if flavor in ['ps3', 'ps4']:
+    if flavor in sony_flavors:
       # PS3 and PS4 linkers don't know about rpath.
       rpath = ''
     else:
@@ -1903,7 +1907,7 @@
       rspfile_content=('$ldflags -o $out %s -Wl,--start-group $in $solibs '
                        '-Wl,--end-group $libs' % rpath),
       pool='link_pool')
-  elif flavor in ['win', 'xb1']:
+  elif flavor in microsoft_flavors:
     master_ninja.rule(
         'alink',
         description='LIB $out',
@@ -1916,7 +1920,7 @@
     dllcmd = ('%s gyp-win-tool link-wrapper $arch '
               '$ld /nologo $implibflag /DLL /OUT:$dll '
               '/PDB:$dll.pdb @$dll.rsp' % python_exec)
-    if flavor != 'xb1':
+    if not flavor in ['xb1', 'xb1-future']:
       # XB1 doesn't need a manifest.
       dllcmd += (' && %s gyp-win-tool manifest-wrapper $arch '
                  '$mt -nologo -manifest $manifests -out:$dll.manifest' %
@@ -1938,7 +1942,7 @@
                    '$mt -nologo -manifest $manifests -out:$out.manifest' %
                    (python_exec, python_exec))
     else:
-      assert flavor == 'xb1'
+      assert flavor in ['xb1', 'xb1-future']
       # XB1 doesn't need a manifest.
       link_command=('%s gyp-win-tool link-wrapper $arch '
                    '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp' %
@@ -2027,7 +2031,7 @@
       description='PACKAGE FRAMEWORK $out, POSTBUILDS',
       command='./gyp-mac-tool package-framework $out $version$postbuilds '
               '&& touch $out')
-  if flavor in ['win', 'xb1']:
+  if flavor in microsoft_flavors:
     master_ninja.rule(
       'stamp',
       description='STAMP $out',
@@ -2256,7 +2260,7 @@
 
 def GenerateOutput(target_list, target_dicts, data, params):
   user_config = params.get('generator_flags', {}).get('config', None)
-  if gyp.common.GetFlavor(params) in ['win', 'xb1']:
+  if gyp.common.GetFlavor(params) in microsoft_flavors:
     target_list, target_dicts = MSVSUtil.ShardTargets(target_list, target_dicts)
   if user_config:
     GenerateOutputForConfig(target_list, target_dicts, data, params,
diff --git a/src/tools/gyp/pylib/gyp/generator/qtcreator_ninja.py b/src/tools/gyp/pylib/gyp/generator/qtcreator_ninja.py
index f0f955d..24c0990 100644
--- a/src/tools/gyp/pylib/gyp/generator/qtcreator_ninja.py
+++ b/src/tools/gyp/pylib/gyp/generator/qtcreator_ninja.py
@@ -14,6 +14,7 @@
 """Gyp generator for QT Creator projects that invoke ninja."""
 
 import os
+import re
 
 PROJECT_DIR_RELATIVE_TO_OUTPUT_DIR = 'qtcreator_projects'
 
@@ -28,6 +29,14 @@
   return ret
 
 
+def SplitAssignmentDefine(line):
+  matched = re.match(r'([^=\b]+)=(.*)', line)
+  if matched:
+    return matched.group(1) + ' ' + matched.group(2)
+  else:
+    return line
+
+
 def GenProject(project_def, proj_dir):
   """Generates QT Creator project (.creator) and supporting files.
 
@@ -53,7 +62,7 @@
 
   with open(basefilename + '.config', 'w') as f:
     for define in configuration['defines']:
-      f.write('#define %s\n' % define)
+      f.write('#define %s\n' % SplitAssignmentDefine(define))
 
   with open(basefilename + '.files', 'w') as f:
     for source in project_def['sources']: