Version 1.13.0-dev.7.3

Cherry-pick f80bd4203de33faecad89983ec8d3fd35ceba4a4 to dev
Cherry-pick efc1d4b224821d4cbc64796c0348a6f019fa0649 to dev
Cherry-pick 4653701a7656136d2725b76497cf1a67a15dd4f4 to dev
Cherry-pick e562934defd630f77755d77c6f9108552977e4a0 to dev
Cherry-pick 1a1820bbe3bf3b393105a342b414730f9ba105d3 to dev
Cherry-pick 208e3f981a3e724dce8510332e1c0a576d89e3be to dev
Cherry-pick a9362610ee429a0b69653635039696f86976f564 to dev
Cherry-pick f145f89ccb4b807641914a0631e9c77995a29b20 to dev
Cherry-pick 58937b50ef2f81f441318f1dcdadf5a107b33533 to dev
Cherry-pick be1fcb944176bed2bf1294c78cd39844df67dda6 to dev
Cherry-pick cc0a9c3e7eb32588c219f7f16a1a806e88a397d3 to dev
Cherry-pick f9551da8e3f55734442be679369c00b234c19fa5 to dev
Cherry-pick 10915a849b324e3a9f3e2a37fc245709d0eda370 to dev
Cherry-pick b519e4c0001a0e84a7b45634057d0b4b51f0dd57 to dev
Cherry-pick 6bb8ce37391f0609bc26ead96f35badff9dd2840 to dev
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index d085d03..3c6eea7 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -1232,7 +1232,7 @@
                       null,
                       dartUnit,
                       errorInfo.errors);
-                  scheduleIndexOperation(this, file, context, dartUnit);
+                  scheduleIndexOperation(this, file, dartUnit);
                 }
               } else {
                 schedulePerformAnalysisOperation(context);
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 3e72ad5..6e9af6d 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -623,7 +623,7 @@
   }
 
   /**
-   * Resursively adds all Dart and HTML files to the [changeSet].
+   * Recursively adds all Dart and HTML files to the [changeSet].
    */
   void _addPreviouslyExcludedSources(ContextInfo info, ChangeSet changeSet,
       Folder folder, List<String> oldExcludedPaths) {
@@ -670,7 +670,7 @@
   }
 
   /**
-   * Resursively adds all Dart and HTML files to the [changeSet].
+   * Recursively adds all Dart and HTML files to the [changeSet].
    */
   void _addSourceFiles(ChangeSet changeSet, Folder folder, ContextInfo info) {
     if (info.excludesResource(folder) || folder.shortName.startsWith('.')) {
@@ -877,13 +877,16 @@
    */
   void _createContexts(
       ContextInfo parent, Folder folder, bool withPackageSpecOnly) {
+    if (folder.shortName.startsWith('.') || folder.shortName == 'packages') {
+      return;
+    }
     // Decide whether a context needs to be created for [folder] here, and if
     // so, create it.
     File packageSpec = _findPackageSpecFile(folder);
     bool createContext = packageSpec.exists || !withPackageSpecOnly;
     if (withPackageSpecOnly &&
         packageSpec.exists &&
-        (parent != null) &&
+        parent != null &&
         parent.ignored(packageSpec.path)) {
       // Don't create a context if the package spec is required and ignored.
       createContext = false;
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 973b831..1e430d5 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -64,9 +64,10 @@
 /**
  * Schedules indexing of the given [file] using the resolved [dartUnit].
  */
-void scheduleIndexOperation(AnalysisServer server, String file,
-    AnalysisContext context, CompilationUnit dartUnit) {
+void scheduleIndexOperation(
+    AnalysisServer server, String file, CompilationUnit dartUnit) {
   if (server.index != null) {
+    AnalysisContext context = dartUnit.element.context;
     server.addOperation(new _DartIndexOperation(context, file, dartUnit));
   }
 }
@@ -414,7 +415,7 @@
       try {
         CompilationUnit dartUnit = notice.resolvedDartUnit;
         if (dartUnit != null) {
-          server.addOperation(new _DartIndexOperation(context, file, dartUnit));
+          scheduleIndexOperation(server, file, dartUnit);
         }
       } catch (exception, stackTrace) {
         server.sendServerErrorNotification(exception, stackTrace);
@@ -459,6 +460,7 @@
     ServerPerformanceStatistics.indexOperation.makeCurrentWhile(() {
       try {
         Index index = server.index;
+        AnalysisContext context = unit.element.context;
         index.index(context, unit);
       } catch (exception, stackTrace) {
         server.sendServerErrorNotification(exception, stackTrace);
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index dc41509..0a43e34 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -942,6 +942,26 @@
     _checkPackageMap(projPath, equals(packageMapProvider.packageMap));
   }
 
+  void test_setRoots_noContext_inDotFolder() {
+    String pubspecPath = posix.join(projPath, '.pub', 'pubspec.yaml');
+    resourceProvider.newFile(pubspecPath, 'name: test');
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    // verify
+    expect(callbacks.currentContextPaths, hasLength(1));
+    expect(callbacks.currentContextPaths, contains(projPath));
+    expect(callbacks.currentContextFilePaths[projPath], hasLength(0));
+  }
+
+  void test_setRoots_noContext_inPackagesFolder() {
+    String pubspecPath = posix.join(projPath, 'packages', 'pubspec.yaml');
+    resourceProvider.newFile(pubspecPath, 'name: test');
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    // verify
+    expect(callbacks.currentContextPaths, hasLength(1));
+    expect(callbacks.currentContextPaths, contains(projPath));
+    expect(callbacks.currentContextFilePaths[projPath], hasLength(0));
+  }
+
   void test_setRoots_packageResolver() {
     Uri uri = Uri.parse('package:foo/foo.dart');
     Source source = new TestSource();
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index b2c2471..6f7aeb7 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -656,6 +656,9 @@
   @override
   Object /*V*/ computeResult(
       AnalysisTarget target, ResultDescriptor /*<V>*/ descriptor) {
+    // Make sure we are not trying to invoke the task model in a reentrant
+    // fashion.
+    assert(!driver.isTaskRunning);
     CacheEntry entry = getCacheEntry(target);
     CacheState state = entry.getState(descriptor);
     if (state == CacheState.FLUSHED || state == CacheState.INVALID) {
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 9e7aeb4..de92b6a 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -7492,6 +7492,57 @@
     this._imports = imports;
   }
 
+  /** Given an update to this library which may have added or deleted edges
+   * in the import/export graph originating from this node only, remove any
+   * cached library cycles in the element model which may have been invalidated.
+   */
+  void invalidateLibraryCycles() {
+    if (_libraryCycle == null) {
+      // We have already invalidated this node, or we have never computed
+      // library cycle information for it.  In the former case, we're done. In
+      // the latter case, this node cannot be reachable from any node for which
+      // we have computed library cycle information.  Therefore, any edges added
+      // or deleted in the update causing this invalidation can only be edges to
+      // nodes which either have no library cycle information (and hence do not
+      // need invalidation), or which do not reach this node by any path.
+      // In either case, no further invalidation is needed.
+      return;
+    }
+    // If we have pre-computed library cycle information, then we must
+    // invalidate the information both on this element, and on certain
+    // other elements.  Edges originating at this node may have been
+    // added or deleted.  A deleted edge that points outside of this cycle
+    // cannot change the cycle information for anything outside of this cycle,
+    // and so it is sufficient to delete the cached library information on this
+    // cycle.  An added edge which points to another node within the cycle
+    // only invalidates the cycle.  An added edge which points to a node earlier
+    // in the topological sort of cycles induces no invalidation (since there
+    // are by definition no back edges from earlier cycles in the topological
+    // order, and hence no possible cycle can have been introduced.  The only
+    // remaining case is that we have added an edge to a node which is later
+    // in the topological sort of cycles.  This can induce cycles, since it
+    // represents a new back edge.  It would be sufficient to invalidate the
+    // cycle information for all nodes that are between the target and the
+    // node in the topological order.  For simplicity, we simply invalidate
+    // all nodes which are reachable from the the source node.
+    // Note that in the invalidation phase, we do not cut off when we encounter
+    // a node with no library cycle information, since we do not know whether
+    // we are in the case where invalidation has already been performed, or we
+    // are in the case where library cycles have simply never been computed from
+    // a newly reachable node.
+    Set<LibraryElementImpl> active = new HashSet();
+    void invalidate(LibraryElementImpl library) {
+      if (!active.add(library)) return;
+      if (library._libraryCycle != null) {
+        library._libraryCycle.forEach(invalidate);
+        library._libraryCycle = null;
+      }
+      library.exportedLibraries.forEach(invalidate);
+      library.importedLibraries.forEach(invalidate);
+    }
+    invalidate(this);
+  }
+
   @override
   bool get isBrowserApplication =>
       entryPoint != null && isOrImportsBrowserLibrary;
@@ -7602,52 +7653,10 @@
 
   @override
   FunctionElement get loadLibraryFunction {
-    if (_loadLibraryFunction == null) {
-      FunctionElementImpl function =
-          new FunctionElementImpl(FunctionElement.LOAD_LIBRARY_NAME, -1);
-      function.synthetic = true;
-      function.enclosingElement = this;
-      function.returnType = loadLibraryReturnType;
-      function.type = new FunctionTypeImpl(function);
-      _loadLibraryFunction = function;
-    }
+    assert(_loadLibraryFunction != null);
     return _loadLibraryFunction;
   }
 
-  /**
-   * Return the object representing the type 'Future' from the 'dart:async'
-   * library, or the type 'void' if the type 'Future' cannot be accessed.
-   */
-  DartType get loadLibraryReturnType {
-    try {
-      Source asyncSource = context.sourceFactory.forUri(DartSdk.DART_ASYNC);
-      if (asyncSource == null) {
-        AnalysisEngine.instance.logger
-            .logError("Could not create a source for dart:async");
-        return VoidTypeImpl.instance;
-      }
-      LibraryElement asyncElement = context.computeLibraryElement(asyncSource);
-      if (asyncElement == null) {
-        AnalysisEngine.instance.logger
-            .logError("Could not build the element model for dart:async");
-        return VoidTypeImpl.instance;
-      }
-      ClassElement futureElement = asyncElement.getType("Future");
-      if (futureElement == null) {
-        AnalysisEngine.instance.logger
-            .logError("Could not find type Future in dart:async");
-        return VoidTypeImpl.instance;
-      }
-      InterfaceType futureType = futureElement.type;
-      return futureType.substitute4(<DartType>[DynamicTypeImpl.instance]);
-    } on AnalysisException catch (exception, stackTrace) {
-      AnalysisEngine.instance.logger.logError(
-          "Could not build the element model for dart:async",
-          new CaughtException(exception, stackTrace));
-      return VoidTypeImpl.instance;
-    }
-  }
-
   @override
   List<CompilationUnitElement> get parts => _parts;
 
@@ -7706,6 +7715,20 @@
   @override
   accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
 
+  /**
+   * Create the [FunctionElement] to be returned by [loadLibraryFunction],
+   * using types provided by [typeProvider].
+   */
+  void createLoadLibraryFunction(TypeProvider typeProvider) {
+    FunctionElementImpl function =
+        new FunctionElementImpl(FunctionElement.LOAD_LIBRARY_NAME, -1);
+    function.synthetic = true;
+    function.enclosingElement = this;
+    function.returnType = typeProvider.futureDynamicType;
+    function.type = new FunctionTypeImpl(function);
+    _loadLibraryFunction = function;
+  }
+
   @override
   ElementImpl getChild(String identifier) {
     if ((_definingCompilationUnit as CompilationUnitElementImpl).identifier ==
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 84f0f6b..e52fd11 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -8171,6 +8171,7 @@
               : typeResolverVisitorFactory(library, source, _typeProvider);
           library.getAST(source).accept(visitor);
         }
+        library.libraryElement.createLoadLibraryFunction(_typeProvider);
       }
     });
   }
@@ -8857,6 +8858,7 @@
               nameScope: library.libraryScope);
           ast.accept(visitor);
         }
+        library.libraryElement.createLoadLibraryFunction(_typeProvider);
       }
     });
   }
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index dc484ed..aff5bca 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -834,6 +834,9 @@
     //
     libraryElement.imports = imports;
     libraryElement.exports = exports;
+    // See commentary in the computation of the LIBRARY_CYCLE result
+    // for details on library cycle invalidation.
+    libraryElement.invalidateLibraryCycles();
     //
     // Record outputs.
     //
@@ -1842,6 +1845,33 @@
 
   @override
   void internalPerform() {
+    // The computation of library cycles is necessarily non-local, since we
+    // in general have to look at all of the reachable libraries
+    // in order to find the strongly connected components.  Repeating this
+    // computation for every node would be quadratic.  The libraryCycle getter
+    // will avoid this by computing the library cycles for every reachable
+    // library and recording it in the element model.  This means that this
+    // task implicitly produces the output for many other targets.  This
+    // can't be expressed in the task model right now: instead, we just
+    // run tasks for those other targets, and they pick up the recorded
+    // version off of the element model.  Unfortunately, this means that
+    // the task model will not handle the invalidation of the recorded
+    // results for us.  Instead, we must explicitly invalidate the recorded
+    // library cycle information when we add or subtract edges from the
+    // import/export graph.  Any update that changes the
+    // import/export graph will induce a recomputation of the LIBRARY_ELEMENT2
+    // result for the changed node. This recomputation is responsible for
+    // conservatively invalidating the library cycle information recorded
+    // in the element model.  The LIBRARY_CYCLE results that have been cached
+    // by the task model are conservatively invalidated by the
+    // IMPORT_EXPORT_SOURCE_CLOSURE dependency below.  If anything reachable
+    // from a node is changed, its LIBRARY_CYCLE results will be re-computed
+    // here (possibly re-using the result from the element model if invalidation
+    // did not cause it to be erased).  In summary, task model dependencies
+    // on the import/export source closure ensure that this method will be
+    // re-run if anything reachable from this target has been invalidated,
+    // and the invalidation code (invalidateLibraryCycles) will ensure that
+    // element model results will be re-used here only if they are still valid.
     if (context.analysisOptions.strongMode) {
       LibraryElementImpl library = getRequiredInput(LIBRARY_ELEMENT_INPUT);
       List<LibraryElement> component = library.libraryCycle;
@@ -1856,7 +1886,6 @@
         l.importedLibraries.forEach(addLibrary);
         l.exportedLibraries.forEach(addLibrary);
       }
-
       //
       // Record outputs.
       //
@@ -3783,6 +3812,11 @@
   static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
 
   /**
+   * The name of the [TYPE_PROVIDER] input.
+   */
+  static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+  /**
    * The task descriptor describing this kind of task.
    */
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
@@ -3800,7 +3834,18 @@
 
   @override
   void internalPerform() {
+    //
+    // Prepare inputs.
+    //
     LibraryElement library = getRequiredInput(LIBRARY_INPUT);
+    TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+    //
+    // Create the synthetic element for `loadLibrary`.
+    //
+    (library as LibraryElementImpl).createLoadLibraryFunction(typeProvider);
+    //
+    // Record outputs.
+    //
     outputs[LIBRARY_ELEMENT5] = library;
   }
 
@@ -3814,7 +3859,8 @@
     return <String, TaskInput>{
       'resolvedUnit': UNITS.of(source).toList((Source unit) =>
           RESOLVED_UNIT3.of(new LibrarySpecificUnit(source, unit))),
-      LIBRARY_INPUT: LIBRARY_ELEMENT4.of(source)
+      LIBRARY_INPUT: LIBRARY_ELEMENT4.of(source),
+      TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
     };
   }
 
diff --git a/pkg/analyzer/lib/src/task/dart_work_manager.dart b/pkg/analyzer/lib/src/task/dart_work_manager.dart
index 61f92e5..62a25ea 100644
--- a/pkg/analyzer/lib/src/task/dart_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/dart_work_manager.dart
@@ -400,7 +400,7 @@
     unitTargets.forEach(partition.remove);
     for (Source dartSource in dartSources) {
       CacheEntry entry = partition.get(dartSource);
-      if (dartSource != null) {
+      if (entry != null) {
         // TODO(scheglov) we invalidate too much.
         // Would be nice to invalidate just URLs resolution.
         entry.setState(PARSED_UNIT, CacheState.INVALID);
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index 3231454..b725042 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -473,6 +473,14 @@
  */
 class InfiniteTaskLoopException extends AnalysisException {
   /**
+   * A concrete cyclic path of [TargetedResults] within the [dependencyCycle],
+   * `null` if no such path exists.  All nodes in the path are in the
+   * dependencyCycle, but the path is not guaranteed to cover the
+   * entire cycle.
+   */
+  final List<TargetedResult> cyclicPath;
+
+  /**
    * If a dependency cycle was found while computing the inputs for the task,
    * the set of [WorkItem]s contained in the cycle (if there are overlapping
    * cycles, this is the set of all [WorkItem]s in the entire strongly
@@ -484,7 +492,8 @@
    * Initialize a newly created exception to represent a failed attempt to
    * perform the given [task] due to the given [dependencyCycle].
    */
-  InfiniteTaskLoopException(AnalysisTask task, this.dependencyCycle)
+  InfiniteTaskLoopException(AnalysisTask task, this.dependencyCycle,
+      [this.cyclicPath])
       : super(
             'Infinite loop while performing task ${task.descriptor.name} for ${task.target}');
 }
diff --git a/pkg/analyzer/lib/src/task/html_work_manager.dart b/pkg/analyzer/lib/src/task/html_work_manager.dart
index 218b48a..b0e52bb 100644
--- a/pkg/analyzer/lib/src/task/html_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/html_work_manager.dart
@@ -231,7 +231,7 @@
     scriptTargets.forEach(partition.remove);
     for (Source htmlSource in htmlSources) {
       CacheEntry entry = partition.get(htmlSource);
-      if (htmlSource != null) {
+      if (entry != null) {
         entry.setState(HTML_ERRORS, CacheState.INVALID);
         if (invalidateUris) {
           entry.setState(REFERENCED_LIBRARIES, CacheState.INVALID);
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index 9d949c3..cf3cce8 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -214,6 +214,50 @@
   String toString() => description;
 
   /**
+   * Given a strongly connected component, find and return a list of
+   * [TargetedResult]s that describes a cyclic path within the cycle.  Returns
+   * null if no cyclic path is found.
+   */
+  List<TargetedResult> _findCyclicPath(List<WorkItem> cycle) {
+    WorkItem findInCycle(AnalysisTarget target, ResultDescriptor descriptor) {
+      for (WorkItem item in cycle) {
+        if (target == item.target && descriptor == item.spawningResult) {
+          return item;
+        }
+      }
+      return null;
+    }
+
+    HashSet<WorkItem> active = new HashSet<WorkItem>();
+    List<TargetedResult> path = null;
+    bool traverse(WorkItem item) {
+      if (!active.add(item)) {
+        // We've found a cycle
+        path = <TargetedResult>[];
+        return true;
+      }
+      for (TargetedResult result in item.inputTargetedResults) {
+        WorkItem item = findInCycle(result.target, result.result);
+        // Ignore edges that leave the cycle.
+        if (item != null) {
+          if (traverse(item)) {
+            // This edge is in a cycle (or leads to a cycle) so add it to the
+            // path
+            path.add(result);
+            return true;
+          }
+        }
+      }
+      // There was no cycle.
+      return false;
+    }
+    if (cycle.length > 0) {
+      traverse(cycle[0]);
+    }
+    return path;
+  }
+
+  /**
    * Perform this analysis task, ensuring that all exceptions are wrapped in an
    * [AnalysisException].
    *
@@ -250,7 +294,8 @@
       //
       try {
         if (dependencyCycle != null && !handlesDependencyCycles) {
-          throw new InfiniteTaskLoopException(this, dependencyCycle);
+          throw new InfiniteTaskLoopException(
+              this, dependencyCycle, _findCyclicPath(dependencyCycle));
         }
         internalPerform();
       } finally {
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index e3615fe..5c4f251 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -1471,6 +1471,109 @@
     enableStrongMode();
   }
 
+  void test_library_cycle_incremental() {
+    enableStrongMode();
+    Source lib1Source = newSource(
+        '/my_lib1.dart',
+        '''
+library my_lib1;
+''');
+    Source lib2Source = newSource(
+        '/my_lib2.dart',
+        '''
+library my_lib2;
+import 'my_lib1.dart';
+''');
+    Source lib3Source = newSource(
+        '/my_lib3.dart',
+        '''
+library my_lib3;
+import 'my_lib2.dart';
+''');
+    AnalysisTarget lib1Target = new LibrarySpecificUnit(lib1Source, lib1Source);
+    AnalysisTarget lib2Target = new LibrarySpecificUnit(lib2Source, lib2Source);
+    AnalysisTarget lib3Target = new LibrarySpecificUnit(lib3Source, lib3Source);
+    computeResult(lib1Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(1));
+    computeResult(lib2Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(1));
+    computeResult(lib3Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(1));
+
+    // complete the cycle
+    context.setContents(
+        lib1Source,
+        '''
+library my_lib1;
+import 'my_lib3.dart';
+''');
+    computeResult(lib1Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(3));
+    computeResult(lib2Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(3));
+    computeResult(lib3Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(3));
+
+    // break the cycle again
+    context.setContents(
+        lib1Source,
+        '''
+library my_lib1;
+''');
+    computeResult(lib1Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(1));
+    computeResult(lib2Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(1));
+    computeResult(lib3Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(1));
+  }
+
+  void test_library_cycle_incremental_partial() {
+    enableStrongMode();
+    Source lib1Source = newSource(
+        '/my_lib1.dart',
+        '''
+library my_lib1;
+''');
+    Source lib2Source = newSource(
+        '/my_lib2.dart',
+        '''
+library my_lib2;
+import 'my_lib1.dart';
+''');
+    Source lib3Source = newSource(
+        '/my_lib3.dart',
+        '''
+library my_lib3;
+import 'my_lib2.dart';
+''');
+    AnalysisTarget lib1Target = new LibrarySpecificUnit(lib1Source, lib1Source);
+    AnalysisTarget lib2Target = new LibrarySpecificUnit(lib2Source, lib2Source);
+    AnalysisTarget lib3Target = new LibrarySpecificUnit(lib3Source, lib3Source);
+    computeResult(lib1Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(1));
+    computeResult(lib2Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(1));
+    // lib3 is not reachable, so we have not yet computed its library
+    // cycles
+
+    // complete the cycle, via lib3
+    context.setContents(
+        lib1Source,
+        '''
+library my_lib1;
+import 'my_lib3.dart';
+''');
+    // Ensure that invalidation correctly invalidated everything reachable
+    // through lib3
+    computeResult(lib1Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(3));
+    computeResult(lib2Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(3));
+    computeResult(lib3Target, LIBRARY_CYCLE);
+    expect(outputs[LIBRARY_CYCLE], hasLength(3));
+  }
+
   void test_library_cycle_linear() {
     List<Source> sources = newSources({
       '/a.dart': '''
@@ -3208,6 +3311,7 @@
       ClassElement classC = library.getType('C');
       expect(classC.supertype.displayName, 'A');
     }
+    expect(library.loadLibraryFunction, isNotNull);
   }
 
   test_perform_external() {
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index edaf69c..ce8b6a7 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -2137,14 +2137,14 @@
           MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS,
           "Js-interop class '#{cls}' cannot extend from the non js-interop "
           "class '#{superclass}'.",
-          howToFix: "Annotate the superclass with @Js.",
+          howToFix: "Annotate the superclass with @JS.",
           examples: const [
               """
               import 'package:js/js.dart';
 
               class Foo { }
 
-              @Js()
+              @JS()
               class Bar extends Foo { }
 
               main() {
@@ -2161,7 +2161,7 @@
               """
               import 'package:js/js.dart';
 
-              @Js()
+              @JS()
               class Foo {
                 bar() {}
               }
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 8370d13..1e4e925 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -2065,7 +2065,7 @@
         typedArrayClass = findClass('NativeTypedArray');
         typedArrayOfIntClass = findClass('NativeTypedArrayOfInt');
       } else if (uri == PACKAGE_JS) {
-        jsAnnotationClass = find(library, 'Js');
+        jsAnnotationClass = find(library, 'JS');
       }
       annotations.onLibraryScanned(library);
     });
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index a0ad4d9..1b9e8f3 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -465,13 +465,13 @@
   }
 }
 
-/// Annotation handler for pre-resolution detection of `@Js(...)`
+/// Annotation handler for pre-resolution detection of `@JS(...)`
 /// annotations.
 class JsInteropAnnotationHandler implements EagerAnnotationHandler<bool> {
   const JsInteropAnnotationHandler();
 
   bool hasJsNameAnnotation(MetadataAnnotation annotation) =>
-      annotation.beginToken != null && annotation.beginToken.next.value == 'Js';
+      annotation.beginToken != null && annotation.beginToken.next.value == 'JS';
 
   bool apply(Compiler compiler,
              Element element,
@@ -493,7 +493,7 @@
     JavaScriptBackend backend = compiler.backend;
     if (constant.getType(compiler.coreTypes).element !=
         backend.jsAnnotationClass) {
-      compiler.reporter.internalError(annotation, 'Invalid @Js(...) annotation.');
+      compiler.reporter.internalError(annotation, 'Invalid @JS(...) annotation.');
     }
   }
 }
diff --git a/pkg/js/lib/js.dart b/pkg/js/lib/js.dart
index c31794b..4cb53c5 100644
--- a/pkg/js/lib/js.dart
+++ b/pkg/js/lib/js.dart
@@ -1,11 +1,8 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-/**
- * The js library allows Dart library authors to export their APIs to JavaScript
- * and to define Dart interfaces for JavaScript objects.
- */
+/// Allows interoperability with Javascript APIs.
 library js;
 
 export 'dart:js' show allowInterop, allowInteropCaptureThis;
@@ -17,52 +14,7 @@
 /// Specifying [name] customizes the JavaScript name to use. By default the
 /// dart name is used. It is not valid to specify a custom [name] for class
 /// instance members.
-///
-/// Example 1:
-///
-///     @Js('google.maps')
-///     library maps;
-///
-///     external Map get map;
-///
-///     @Js("LatLng")
-///     class Location {
-///       external Location(num lat, num lng);
-///     }
-///
-///     @Js()
-///     class Map {
-///       external Map(Location location);
-///       external Location getLocation();
-///     }
-///
-/// In this example the top level map getter will invoke the JavaScript getter
-///     google.maps.map
-/// Calls to the Map constructor will be translated to calls to the JavaScript
-///     new google.maps.Map(location)
-/// Calls to the Location constructor willbe translated to calls to the
-/// JavaScript
-///     new google.maps.LatLng(lat, lng)
-/// because a custom JavaScript name for the Location class.
-/// In general, we recommend against using custom JavaScript names whenever
-/// possible as it is easier for users if the JavaScript names and Dart names
-/// are consistent.
-///
-/// Example 2:
-///     library utils;
-///
-///     @Js("JSON.stringify")
-///     external String stringify(obj);
-///
-///     @Js()
-///     void debugger();
-///
-/// In this example no custom JavaScript namespace is specified.
-/// Calls to debugger map to calls to JavaScript
-///     self.debugger()
-/// Calls to stringify map to calls to
-///     JSON.stringify(obj)
-class Js {
+class JS {
   final String name;
-  const Js([this.name]);
+  const JS([this.name]);
 }
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index d29e7cf..4d3c679 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -433,7 +433,7 @@
     directory = NULL;
   } else {
     Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "Directory argument to SecurityContext.usePrivateKey is not "
+        "Directory argument to SecurityContext.setTrustedCertificates is not "
         "a String or null"));
   }
 
@@ -910,9 +910,12 @@
   SSL_set_ex_data(ssl_, filter_ssl_index, this);
 
   if (is_server_) {
-    // Do not request a client certificate.
-    // TODO(24069): Allow server to request a client certificate, when desired.
-    SSL_set_verify(ssl_, SSL_VERIFY_NONE, NULL);
+    int certificate_mode =
+      request_client_certificate ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
+    if (require_client_certificate) {
+      certificate_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+    }
+    SSL_set_verify(ssl_, certificate_mode, NULL);
   } else {
     SetAlpnProtocolList(protocols_handle, ssl_, NULL, false);
     status = SSL_set_tlsext_host_name(ssl_, hostname);
@@ -948,19 +951,6 @@
       if (SSL_LOG_STATUS) Log::Print("SSL_connect error: %d\n", error);
     }
   }
-  if (is_server_) {
-    if (request_client_certificate) {
-      // TODO(24069): Handle client certificates on server side.
-      Dart_ThrowException(DartUtils::NewDartArgumentError(
-          "requestClientCertificate not implemented."));
-    }
-  } else {  // Client.
-    if (send_client_certificate) {
-      // TODO(24070): Handle client certificates on client side.
-      Dart_ThrowException(DartUtils::NewDartArgumentError(
-          "sendClientCertificate not implemented."));
-    }
-  }
   Handshake();
 }
 
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index 8cbb03e..fa87896 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -167,7 +167,8 @@
 
 
 void OSThread::Join(ThreadJoinId id) {
-  ASSERT(pthread_join(id, NULL) == 0);
+  int result = pthread_join(id, NULL);
+  ASSERT(result == 0);
 }
 
 
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index 4955cb4..9fb0b23 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -169,7 +169,8 @@
 
 
 void OSThread::Join(ThreadJoinId id) {
-  ASSERT(pthread_join(id, NULL) == 0);
+  int result = pthread_join(id, NULL);
+  ASSERT(result == 0);
 }
 
 
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 827f749..e7c7c90 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -161,7 +161,8 @@
 
 
 void OSThread::Join(ThreadJoinId id) {
-  ASSERT(pthread_join(id, NULL) == 0);
+  int result = pthread_join(id, NULL);
+  ASSERT(result == 0);
 }
 
 
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index e8b0a6b..8b3020a 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -3179,8 +3179,9 @@
  */
 interceptedTypeCheck(value, property) {
   if (value == null) return value;
-  if ((identical(JS('String', 'typeof #', value), 'object'))
-      && JS('bool', '#[#]', getInterceptor(value), property)) {
+  if ((JS('bool', 'typeof # === "object"', value) ||
+              JS('bool', 'typeof # === "function"', value)) &&
+      JS('bool', '#[#]', getInterceptor(value), property)) {
     return value;
   }
   propertyTypeError(value, property);
@@ -3192,9 +3193,10 @@
  * prototype at load time.
  */
 interceptedTypeCast(value, property) {
-  if (value == null
-      || ((JS('bool', 'typeof # === "object"', value))
-          && JS('bool', '#[#]', getInterceptor(value), property))) {
+  if (value == null ||
+      ((JS('bool', 'typeof # === "object"', value) ||
+              JS('bool', 'typeof # === "function"', value)) &&
+          JS('bool', '#[#]', getInterceptor(value), property))) {
     return value;
   }
   propertyTypeCastError(value, property);
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 6d84226..73e0a05 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -1107,32 +1107,14 @@
  **********                                                          **********
  ******************************************************************************/
 
-// List of known tagName to DartClass for custom elements, used for upgrade.
-var _knownCustomElements = new Map<String, Map<Type, String>>();
-
-void _addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
-  _knownCustomElements[tagName] = 
-      {'type': dartClass, 'extends': extendTag != null ? extendTag : "" };
-}
-
-Type _getCustomElementType(object) {
-  var entry = _knownCustomElements[_getCustomElementName(object)];
-  if (entry != null) {
-    return entry['type'];
-  }
-  return null;
-}
-
 String _getCustomElementExtends(object) {
-  var entry = _knownCustomElements[_getCustomElementName(object)];
+  var entry = getCustomElementEntry(object);
   if (entry != null) {
     return entry['extends'];
   }
   return null;
 }
 
-_getCustomElement(object) => _knownCustomElements[_getCustomElementName(object)];
-
 // Return the tag name or is attribute of the custom element or data binding.
 String _getCustomElementName(element) {
   var jsObject;
@@ -1162,13 +1144,6 @@
   return tag;
 }
 
-Rectangle make_dart_rectangle(r) =>
-    r == null ? null : new Rectangle(
-    js.JsNative.getProperty(r, 'left'),
-    js.JsNative.getProperty(r, 'top'),
-    js.JsNative.getProperty(r, 'width'),
-    js.JsNative.getProperty(r, 'height'));
-
 /// An abstract class for all DOM objects we wrap in dart:html and related
 ///  libraries.
 class DartHtmlDomObject {
@@ -1178,247 +1153,14 @@
 
 }
 
-// Flag to disable JS interop asserts.  Setting to false will speed up the
-// wrap_jso calls.
-bool __interop_checks = true;
-
-/** Expando for JsObject, used by every Dart class associated with a Javascript
- *  class (e.g., DOM, WebAudio, etc.).
- */
-
-/**
- * Return the JsObject associated with a Dart class [dartClass_instance].
- */
-unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
-
-/**
- * Create Dart class that maps to the JS Type, add the JsObject as an expando
- * on the Dart class and return the created Dart class.
- */
-wrap_jso(jsObject) {
-  try {
-    if (jsObject is! js.JsObject || jsObject == null) {
-      // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
-      // or it's a simple type.
-      return jsObject;
-    }
-
-    var wrapper = js.getDartHtmlWrapperFor(jsObject);
-    // if we have a wrapper return the Dart instance.
-    if (wrapper != null) {
-      if (wrapper.runtimeType == HtmlElement && !wrapper._isBadUpgrade) {
-        // We're a Dart instance but we need to upgrade.
-        var customElementClass = _getCustomElementType(wrapper);
-        if (customElementClass != null) {
-          var dartClass_instance;
-          try {
-            dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
-          } finally {
-            dartClass_instance.blink_jsObject = jsObject;
-            jsObject['dart_class'] = dartClass_instance;
-            js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
-            return dartClass_instance;
-          }
-        }
-      }
-
-      return wrapper;
-    }
-
-    if (jsObject is js.JsArray) {
-      var wrappingList = new _DartHtmlWrappingList(jsObject);
-      js.setDartHtmlWrapperFor(jsObject, wrappingList);
-      return wrappingList;
-    }
-
-    // Try the most general type conversions on it.
-    // TODO(alanknight): We may be able to do better. This maintains identity,
-    // which is useful, but expensive. And if we nest something that only
-    // this conversion handles, how does that work? e.g. a list of maps of elements.
-    var converted = convertNativeToDart_SerializedScriptValue(jsObject);
-    if (!identical(converted, jsObject)) {
-      return converted;
-    }
-
-    var constructor = js.JsNative.getProperty(jsObject, 'constructor');
-    if (constructor == null) {
-      // Perfectly valid case for JavaScript objects where __proto__ has
-      // intentionally been set to null.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
-    }
-    var jsTypeName = js.JsNative.getProperty(constructor, 'name');
-    if (jsTypeName is! String || jsTypeName.length == 0) {
-      // Not an html type.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
-    }
-
-    var dartClass_instance;
-    if (jsObject.hasProperty('dart_class')) {
-      // Got a dart_class (it's a custom element) use it it's already set up
-      // make sure it's upgraded.
-      dartClass_instance = _upgradeHtmlElement(jsObject['dart_class']);
-    } else {
-      var customElementClass = null;
-      var extendsTag = "";
-      var custom = _getCustomElement(jsObject);
-      if (custom != null) {
-        customElementClass = custom['type'];
-        extendsTag = custom['extends'];
-      }
-      // Custom Element to upgrade.
-      if (jsTypeName == 'HTMLElement' && customElementClass != null && extendsTag == "") {
-        try {
-          dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
-        } finally {
-          dartClass_instance.blink_jsObject = jsObject;
-          jsObject['dart_class'] = dartClass_instance;
-          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
-       }
-      } else {
-        // TODO(terry): Verify with jakemacd that this is right?
-        // If we every get an auto-binding we're matching previous non-JS Interop
-        // did to return a TemplateElement.
-        if (jsTypeName == 'auto-binding') {
-          jsTypeName = "HTMLTemplateElement";
-        }
-
-        var func = getHtmlCreateFunction(jsTypeName);
-        if (func == null) {
-          // One last ditch effort could be a JS custom element.
-          if (jsObject.toString() == "[object HTMLElement]") {
-            func = getHtmlCreateFunction("HTMLElement");
-          }
-        }
-        if (func != null) {
-          dartClass_instance = func();
-          dartClass_instance.blink_jsObject = jsObject;
-          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
-        }
-      }
-    }
-    // TODO(jacobr): cache that this is not a dart:html JS class.
-    return dartClass_instance;
-  } catch(e, stacktrace){
-    if (__interop_checks) {
-      if (e is DebugAssertException)
-        window.console.log("${e.message}\n ${stacktrace}");
-      else
-        window.console.log("${stacktrace}");
-    }
-  }
-
-  return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type, add the JsObject as an expando
- * on the Dart class and return the created Dart class.
- */
-wrap_jso_no_SerializedScriptvalue(jsObject) {
-  try {
-    if (jsObject is! js.JsObject || jsObject == null) {
-      // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
-      // or it's a simple type.
-      return jsObject;
-    }
-
-    // TODO(alanknight): With upgraded custom elements this causes a failure because
-    // we need a new wrapper after the type changes. We could possibly invalidate this
-    // if the constructor name didn't match?
-    var wrapper = js.getDartHtmlWrapperFor(jsObject);
-    if (wrapper != null) {
-      return wrapper;
-    }
-
-    if (jsObject is js.JsArray) {
-      var wrappingList = new _DartHtmlWrappingList(jsObject);
-      js.setDartHtmlWrapperFor(jsObject, wrappingList);
-      return wrappingList;
-    }
-
-    var constructor = js.JsNative.getProperty(jsObject, 'constructor');
-    if (constructor == null) {
-      // Perfectly valid case for JavaScript objects where __proto__ has
-      // intentionally been set to null.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
-    }
-    var jsTypeName = js.JsNative.getProperty(constructor, 'name');
-    if (jsTypeName is! String || jsTypeName.length == 0) {
-      // Not an html type.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
-    }
-
-    var func = getHtmlCreateFunction(jsTypeName);
-    if (func != null) {
-      var dartClass_instance = func();
-      dartClass_instance.blink_jsObject = jsObject;
-      js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
-      return dartClass_instance;
-    }
-    return jsObject;
-  } catch(e, stacktrace){
-    if (__interop_checks) {
-      if (e is DebugAssertException)
-        window.console.log("${e.message}\n ${stacktrace}");
-      else
-        window.console.log("${stacktrace}");
-    }
-  }
-
-  return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type that is the JS type being
- * extended using JS interop createCallback (we need the base type of the
- * custom element) not the Dart created constructor.
- */
-wrap_jso_custom_element(jsObject) {
-  try {
-    if (jsObject is! js.JsObject) {
-      // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
-      return jsObject;
-    }
-
-    // Find out what object we're extending.
-    var objectName = jsObject.toString();
-    // Expect to see something like '[object HTMLElement]'.
-    if (!objectName.startsWith('[object ')) {
-      return jsObject;
-    }
-
-    var extendsClass = objectName.substring(8, objectName.length - 1);
-    var func = getHtmlCreateFunction(extendsClass);
-    if (__interop_checks)
-      debug_or_assert("func != null name = ${extendsClass}", func != null);
-    var dartClass_instance = func();
-    dartClass_instance.blink_jsObject = jsObject;
-    return dartClass_instance;
-  } catch(e, stacktrace){
-    if (__interop_checks) {
-      if (e is DebugAssertException)
-        window.console.log("${e.message}\n ${stacktrace}");
-      else
-        window.console.log("${stacktrace}");
-    }
-
-    // Problem?
-    return null;
-  }
-}
-
-// Upgrade a Dart HtmlElement to the user's Dart custom element class.
+/// Upgrade a Dart HtmlElement to the user's Dart custom element class.
 _upgradeHtmlElement(dartInstance) {
   // Only try upgrading HtmlElement (Dart class) if there is a failure then
   // don't try it again - one failure is enough.
-  if (dartInstance.runtimeType == HtmlElement && !dartInstance._isBadUpgrade) {
+  if (dartInstance.runtimeType == HtmlElement && !dartInstance.isBadUpgrade) {
     // Must be exactly HtmlElement not something derived from it.
 
-    var customElementClass = _getCustomElementType(dartInstance);
+    var customElementClass = getCustomElementType(dartInstance);
 
     // Custom Element to upgrade.
     if (customElementClass != null) {
@@ -1429,7 +1171,6 @@
         dartInstance._badUpgrade();
       } finally {
         dartInstance.blink_jsObject = jsObject;
-        jsObject['dart_class'] = dartInstance;
         js.setDartHtmlWrapperFor(jsObject, dartInstance);
      }
    }
@@ -1475,53 +1216,10 @@
   return result;
 }
 
-// Converts a flat Dart map into a JavaScript object with properties this is
-// is the Dartium only version it uses dart:js.
-// TODO(alanknight): This could probably be unified with the dart2js conversions
-// code in html_common and be more general.
-convertDartToNative_Dictionary(Map dict) {
-  if (dict == null) return null;
-  var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object'));
-  dict.forEach((String key, value) {
-    if (value is List) {
-      var jsArray = new js.JsArray();
-      value.forEach((elem) {
-        jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
-      });
-      jsObject[key] = jsArray;
-    } else {
-      jsObject[key] = value;
-    }
-  });
-  return jsObject;
-}
-
-// Converts a Dart list into a JsArray. For the Dartium version only.
-convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
-
-// Conversion function place holder (currently not used in dart2js or dartium).
-List convertDartToNative_StringArray(List<String> input) => input;
-
-/**
- * Wraps a JsArray and will call wrap_jso on its entries.
- */
-class _DartHtmlWrappingList extends ListBase implements NativeFieldWrapperClass2 {
-  _DartHtmlWrappingList(this.blink_jsObject);
-
-  final js.JsArray blink_jsObject;
-
-  operator [](int index) => wrap_jso(js.JsNative.getArrayIndex(blink_jsObject, index));
-
-  operator []=(int index, value) => blink_jsObject[index] = value;
-
-  int get length => blink_jsObject.length;
-  int set length(int newLength) => blink_jsObject.length = newLength;
-}
-
 /**
  * Upgrade the JS HTMLElement to the Dart class.  Used by Dart's Polymer.
  */
-createCustomUpgrader(Type customElementClass, $this) {
+_createCustomUpgrader(Type customElementClass, $this) {
   var dartClass;
   try {
     dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
@@ -9327,7 +9025,7 @@
     }
 
     // Need for identity.
-    e.blink_jsObject['dart_class'] = e;
+    js.setDartHtmlWrapperFor(e.blink_jsObject, e);
 
     return e;
   }
@@ -20322,12 +20020,28 @@
     return isElement ? jsClassName : null;
   }
 
+  // Get the first class that's a super of a dart.dom library.
+  ClassMirror _getDartHtmlClassName(ClassMirror classMirror) {
+    while (classMirror.superclass != null) {
+      var fullName = classMirror.superclass.qualifiedName;
+      var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
+      if (domLibrary) {
+        return classMirror.superclass;
+      }
+
+      classMirror = classMirror.superclass;
+    }
+
+    return null;
+  }
+
   /**
    * Get the class that immediately derived from a class in dart:html or
    * dart:svg (has an attribute DomName of either HTML* or SVG*).
    */
   ClassMirror _getDomSuperClass(ClassMirror classMirror) {
     var isElement = false;
+    var foundSuperElement = null;
 
     while (classMirror.superclass != null) {
       var fullName = classMirror.superclass.qualifiedName;
@@ -20335,6 +20049,9 @@
 
       var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
       if (domLibrary) {
+        if (foundSuperElement == null) {
+          foundSuperElement = classMirror.superclass;
+        }
         // Lookup JS class (if not found).
         var metadatas = classMirror.metadata;
         for (var metadata in metadatas) {
@@ -20342,7 +20059,7 @@
           var metaType = reflectClass(metaDataMirror.runtimeType);
           if (MirrorSystem.getName(metaType.simpleName) == 'DomName' &&
               (metaDataMirror.name.startsWith('HTML') || metaDataMirror.name.startsWith('SVG'))) {
-            if (isElement) return classMirror;
+            if (isElement) return foundSuperElement;
           }
         }
       }
@@ -20463,6 +20180,25 @@
       throw new DomException.jsInterop("HierarchyRequestError: Only HTML elements can be customized.");
     }
 
+    var customClassType = _getDartHtmlClassName(classMirror);
+
+    if (extendsTag != null) {
+      var nativeElement = document.createElement(extendsTag);
+
+      // Trying to extend a native element is it the Dart class consistent with the
+      // extendsTag?
+      if (nativeElement.runtimeType != customClassType.reflectedType) {
+        var nativeElementClassMirror = reflectClass(nativeElement.runtimeType);
+        var customClassNativeElement = MirrorSystem.getName(customClassType.simpleName);
+        var extendsNativeElement = MirrorSystem.getName(nativeElementClassMirror.simpleName);
+        throw new DomException.jsInterop("HierarchyRequestError: Custom class type ($customClassNativeElement) and extendsTag class ($extendsNativeElement) don't match .");
+      }
+    } else if (customClassType.reflectedType != HtmlElement && customClassType.reflectedType != svg.SvgElement) {
+      var customClassName = MirrorSystem.getName(classMirror.simpleName);
+      var customClassElement = MirrorSystem.getName(customClassType.simpleName);
+      throw new DomException.jsInterop("HierarchyRequestError: Custom element $customClassName is a native $customClassElement should be derived from HtmlElement or SvgElement.");
+    }
+
     if (_hasCreatedConstructor(classMirror)) {
       // Start the hookup the JS way create an <x-foo> element that extends the
       // <x-base> custom element. Inherit its prototype and signal what tag is
@@ -20478,7 +20214,7 @@
       var elemProto = js.JsNative.callMethod(js.JsNative.getProperty(js.context, 'Object'), "create", [js.JsNative.getProperty(baseElement, 'prototype')]);
 
       // Remember for any upgrading done in wrap_jso.
-      _addCustomElementType(tag, customElementClass, extendsTag);
+      addCustomElementType(tag, customElementClass, extendsTag);
 
       // TODO(terry): Hack to stop recursion re-creating custom element when the
       //              created() constructor of the custom element does e.g.,
@@ -20499,9 +20235,26 @@
 
           var dartClass;
           try {
+            if (extendsTag != null) {
+              // If we're extending a native element then create that element.
+              // Then upgrade that element to the customElementClass through
+              // normal flow.
+              dartClass = document.createElement(extendsTag);
+              js.setDartHtmlWrapperFor($this, dartClass);
+              dartClass.blink_jsObject = $this;
+            }
+
+            // Upgrade to the CustomElement Dart class.
             dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
           } catch (e) {
+            // Got a problem make it an HtmlElement and rethrow the error.
             dartClass = HtmlElement.internalCreateHtmlElement();
+            // We need to remember the JS object (because constructElement failed
+            // it normally sets up the blink_jsObject.
+            dartClass.blink_jsObject = $this;
+
+            // Mark to only try this once don't try upgrading from HtmlElement
+            // to the user's Dart class - we had a problem.
             dartClass._badUpgrade();
             throw e;
           } finally {
@@ -21239,10 +20992,17 @@
   @Experimental() // untriaged
   ElementStream<Event> get onWaiting => waitingEvent.forElement(this);
 
-  // Flags to only try upgrading once if there's a failure don't try upgrading
+  // Flags to only try upgrading once. If there's a failure don't try upgrading
   // anymore.
   bool _badUpgradeOccurred = false;
-  bool get _isBadUpgrade => _badUpgradeOccurred;
+
+  /// Required for SDK Infrastructure. Internal use only.
+  ///
+  /// Did this encounter a failure attempting to upgrade to
+  /// a custom element.
+  @Deprecated("Required for SDK Infrastructure. Internal use only.")
+  bool get isBadUpgrade => _badUpgradeOccurred;
+
   void _badUpgrade() { _badUpgradeOccurred = true; }
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -37202,10 +36962,10 @@
     if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(unwrap_jso(blob_OR_source_OR_stream));
     }
-    if ((blob_OR_source_OR_stream is MediaStream)) {
+    if ((blob_OR_source_OR_stream is MediaSource)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(unwrap_jso(blob_OR_source_OR_stream));
     }
-    if ((blob_OR_source_OR_stream is MediaSource)) {
+    if ((blob_OR_source_OR_stream is MediaStream)) {
       return _blink.BlinkURL.instance.createObjectURL_Callback_1_(unwrap_jso(blob_OR_source_OR_stream));
     }
     throw new ArgumentError("Incorrect number or type of arguments");
@@ -47163,9 +46923,11 @@
 class _VMElementUpgrader implements ElementUpgrader {
   final Type _type;
   final Type _nativeType;
+  final String _extendsTag;
 
   _VMElementUpgrader(Document document, Type type, String extendsTag) :
       _type = type,
+      _extendsTag = extendsTag,
       _nativeType = _validateCustomType(type).reflectedType {
 
     if (extendsTag == null) {
@@ -47183,20 +46945,39 @@
 
   Element upgrade(element) {
     var jsObject;
-    var tag = _getCustomElementName(element);
+    var tag;
+    var isNativeElementExtension = false;
+
+    try {
+      tag = _getCustomElementName(element);
+    } catch (e) {
+      isNativeElementExtension = element.localName == _extendsTag;
+    }
+
     if (element.runtimeType == HtmlElement || element.runtimeType == TemplateElement) {
+      if (tag != _extendsTag) {
+        throw new UnsupportedError('$tag is not registered.');
+      }
       jsObject = unwrap_jso(element);
     } else if (element.runtimeType == js.JsObjectImpl) {
       // It's a Polymer core element (written in JS).
       jsObject = element;
-    } else {
+    } else if (isNativeElementExtension) {
+      // Extending a native element.
+      jsObject = element.blink_jsObject;
+
+      // Element to extend is the real tag.
+      tag = element.localName;
+    } else if (tag != null && element.localName != tag) {
+      throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
+    } else if (tag == null) {
       throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
     }
 
     // Remember Dart class to tagName for any upgrading done in wrap_jso.
-    _addCustomElementType(tag, _type);
+    addCustomElementType(tag, _type, _extendsTag);
 
-    return createCustomUpgrader(_nativeType, jsObject);
+    return _createCustomUpgrader(_type, jsObject);
   }
 }
 
diff --git a/sdk/lib/html/html_common/conversions_dart2js.dart b/sdk/lib/html/html_common/conversions_dart2js.dart
index ac5b755..3b3a8ad 100644
--- a/sdk/lib/html/html_common/conversions_dart2js.dart
+++ b/sdk/lib/html/html_common/conversions_dart2js.dart
@@ -91,3 +91,9 @@
   var newPromise = JS('', '#.then(#).catch(#)', promise, then, error);
   return completer.future;
 }
+
+/// Wrap a JS object with an instance of the matching dart:html class. Used only in Dartium.
+wrap_jso(jsObject) => jsObject;
+
+/// Find the underlying JS object for a dart:html Dart object.
+unwrap_jso(dartClass_instance) => dartClass_instance;
diff --git a/sdk/lib/html/html_common/conversions_dartium.dart b/sdk/lib/html/html_common/conversions_dartium.dart
index d6e6064..1ed1e13 100644
--- a/sdk/lib/html/html_common/conversions_dartium.dart
+++ b/sdk/lib/html/html_common/conversions_dartium.dart
@@ -66,3 +66,331 @@
 convertDartToNative_DateTime(DateTime date) {
   return new js.JsObject(js.context["Date"], [date.millisecondsSinceEpoch]);
 }
+
+/// Creates a Dart Rectangle from a Javascript object with properties
+/// left, top, width and height. Used internally in Dartium.
+Rectangle make_dart_rectangle(r) =>
+    r == null ? null : new Rectangle(
+    js.JsNative.getProperty(r, 'left'),
+    js.JsNative.getProperty(r, 'top'),
+    js.JsNative.getProperty(r, 'width'),
+    js.JsNative.getProperty(r, 'height'));
+
+// Converts a flat Dart map into a JavaScript object with properties this is
+// is the Dartium only version it uses dart:js.
+// TODO(alanknight): This could probably be unified with the dart2js conversions
+// code in html_common and be more general.
+convertDartToNative_Dictionary(Map dict) {
+  if (dict == null) return null;
+  var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object'));
+  dict.forEach((String key, value) {
+    if (value is List) {
+      var jsArray = new js.JsArray();
+      value.forEach((elem) {
+        jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
+      });
+      jsObject[key] = jsArray;
+    } else {
+      jsObject[key] = value;
+    }
+  });
+  return jsObject;
+}
+
+// Conversion function place holder (currently not used in dart2js or dartium).
+List convertDartToNative_StringArray(List<String> input) => input;
+
+// Converts a Dart list into a JsArray. For the Dartium version only.
+convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
+
+/// Find the underlying JS object for a dart:html Dart object.
+unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
+
+// Flag to disable JS interop asserts.  Setting to false will speed up the
+// wrap_jso calls.
+bool interop_checks = false;
+
+/// Wrap a JS object with an instance of the matching dart:html class. Used only in Dartium.
+wrap_jso(jsObject) {
+  try {
+    if (jsObject is! js.JsObject || jsObject == null) {
+      // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+      // or it's a simple type.
+      return jsObject;
+    }
+
+    var wrapper = js.getDartHtmlWrapperFor(jsObject);
+    // if we have a wrapper return the Dart instance.
+    if (wrapper != null) {
+      var customElementClass = getCustomElementType(wrapper.blink_jsObject);
+      if (wrapper.runtimeType != customElementClass && customElementClass != null) {
+        if (wrapper.runtimeType == HtmlElement && !wrapper.isBadUpgrade) {
+          // We're a Dart instance if it's HtmlElement and we have a customElement
+          // class then we need to upgrade.
+          if (customElementClass != null) {
+            var dartClass_instance;
+            try {
+              dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
+            } finally {
+              dartClass_instance.blink_jsObject = jsObject;
+              return dartClass_instance;
+            }
+          }
+        }
+      }
+
+      return wrapper;
+    }
+
+    if (jsObject is js.JsArray) {
+      var wrappingList = new DartHtmlWrappingList(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrappingList);
+      return wrappingList;
+    }
+
+    // Try the most general type conversions on it.
+    // TODO(alanknight): We may be able to do better. This maintains identity,
+    // which is useful, but expensive. And if we nest something that only
+    // this conversion handles, how does that work? e.g. a list of maps of elements.
+    var converted = convertNativeToDart_SerializedScriptValue(jsObject);
+    if (!identical(converted, jsObject)) {
+      return converted;
+    }
+
+    var constructor = js.JsNative.getProperty(jsObject, 'constructor');
+    if (constructor == null) {
+      // Perfectly valid case for JavaScript objects where __proto__ has
+      // intentionally been set to null.
+      js.setDartHtmlWrapperFor(jsObject, jsObject);
+      return jsObject;
+    }
+    var jsTypeName = js.JsNative.getProperty(constructor, 'name');
+    if (jsTypeName is! String || jsTypeName.length == 0) {
+      // Not an html type.
+      js.setDartHtmlWrapperFor(jsObject, jsObject);
+      return jsObject;
+    }
+
+    var dartClass_instance;
+    var customElementClass = null;
+    var extendsTag = "";
+    var custom = getCustomElementEntry(jsObject);
+    if (custom != null) {
+      customElementClass = custom['type'];
+      extendsTag = custom['extends'];
+    }
+
+    // Custom Element to upgrade.
+    // Only allow custome elements to be created in the html or svg default
+    // namespace.
+    var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' ||
+        jsObject['namespaceURI'] ==  'http://www.w3.org/2000/svg';
+    if (customElementClass != null && extendsTag == "" && defaultNS) {
+      try {
+        dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
+      } finally {
+        dartClass_instance.blink_jsObject = jsObject;
+        js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+     }
+    } else {
+      var func = getHtmlCreateFunction(jsTypeName);
+      if (func == null) {
+        if (jsTypeName == 'auto-binding') {
+          func = getHtmlCreateFunction("HTMLTemplateElement");
+        } else if (jsObject.toString() == "[object HTMLElement]") {
+          // One last ditch effort could be a JS custom element.
+          func = getHtmlCreateFunction("HTMLElement");
+        }
+      }
+      if (func != null) {
+        dartClass_instance = func();
+        dartClass_instance.blink_jsObject = jsObject;
+        js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+      }
+    }
+
+    // TODO(jacobr): cache that this is not a dart:html JS class.
+    return dartClass_instance;
+  } catch(e, stacktrace){
+    if (interop_checks) {
+      if (e is DebugAssertException)
+        window.console.log("${e.message}\n ${stacktrace}");
+      else
+        window.console.log("${stacktrace}");
+    }
+  }
+
+  return null;
+}
+
+/**
+ * Create Dart class that maps to the JS Type, add the JsObject as an expando
+ * on the Dart class and return the created Dart class.
+ */
+wrap_jso_no_SerializedScriptvalue(jsObject) {
+  try {
+    if (jsObject is! js.JsObject || jsObject == null) {
+      // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+      // or it's a simple type.
+      return jsObject;
+    }
+
+    // TODO(alanknight): With upgraded custom elements this causes a failure because
+    // we need a new wrapper after the type changes. We could possibly invalidate this
+    // if the constructor name didn't match?
+    var wrapper = js.getDartHtmlWrapperFor(jsObject);
+    if (wrapper != null) {
+      return wrapper;
+    }
+
+    if (jsObject is js.JsArray) {
+      var wrappingList = new DartHtmlWrappingList(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrappingList);
+      return wrappingList;
+    }
+
+    var constructor = js.JsNative.getProperty(jsObject, 'constructor');
+    if (constructor == null) {
+      // Perfectly valid case for JavaScript objects where __proto__ has
+      // intentionally been set to null.
+      js.setDartHtmlWrapperFor(jsObject, jsObject);
+      return jsObject;
+    }
+    var jsTypeName = js.JsNative.getProperty(constructor, 'name');
+    if (jsTypeName is! String || jsTypeName.length == 0) {
+      // Not an html type.
+      js.setDartHtmlWrapperFor(jsObject, jsObject);
+      return jsObject;
+    }
+
+    var func = getHtmlCreateFunction(jsTypeName);
+    if (func != null) {
+      var dartClass_instance = func();
+      dartClass_instance.blink_jsObject = jsObject;
+      js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
+      return dartClass_instance;
+    }
+    return jsObject;
+  } catch(e, stacktrace){
+    if (interop_checks) {
+      if (e is DebugAssertException)
+        window.console.log("${e.message}\n ${stacktrace}");
+      else
+        window.console.log("${stacktrace}");
+    }
+  }
+
+  return null;
+}
+
+/**
+ * Create Dart class that maps to the JS Type that is the JS type being
+ * extended using JS interop createCallback (we need the base type of the
+ * custom element) not the Dart created constructor.
+ */
+wrap_jso_custom_element(jsObject) {
+  try {
+    if (jsObject is! js.JsObject) {
+      // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
+      return jsObject;
+    }
+
+    // Find out what object we're extending.
+    var objectName = jsObject.toString();
+    // Expect to see something like '[object HTMLElement]'.
+    if (!objectName.startsWith('[object ')) {
+      return jsObject;
+    }
+
+    var extendsClass = objectName.substring(8, objectName.length - 1);
+    var func = getHtmlCreateFunction(extendsClass);
+    if (interop_checks)
+      debug_or_assert("func != null name = ${extendsClass}", func != null);
+    var dartClass_instance = func();
+    dartClass_instance.blink_jsObject = jsObject;
+    return dartClass_instance;
+  } catch(e, stacktrace){
+    if (interop_checks) {
+      if (e is DebugAssertException)
+        window.console.log("${e.message}\n ${stacktrace}");
+      else
+        window.console.log("${stacktrace}");
+    }
+
+    // Problem?
+    return null;
+  }
+}
+
+getCustomElementEntry(element) {
+  var hasAttribute = false;
+
+  var jsObject;
+  var tag = "";
+  var runtimeType = element.runtimeType;
+  if (runtimeType == HtmlElement) {
+    tag = element.localName;
+  } else if (runtimeType == TemplateElement) {
+    // Data binding with a Dart class.
+    tag = element.attributes['is'];
+  } else if (runtimeType == js.JsObjectImpl) {
+    // It's a Polymer core element (written in JS).
+    // Make sure it's an element anything else we can ignore.
+    if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
+      if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) {
+        hasAttribute = true;
+        // It's data binding use the is attribute.
+        tag = js.JsNative.callMethod(element, 'getAttribute', ['is']);
+      } else {
+        // It's a custom element we want the local name.
+        tag = element['localName'];
+      }
+    }
+  } else {
+    throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
+  }
+
+  var entry = _knownCustomElements[tag];
+  if (entry != null) {
+    // If there's an 'is' attribute then check if the extends tag registered
+    // matches the tag if so then return the entry that's registered for this
+    // extendsTag or if there's no 'is' tag then return the entry found.
+    if ((hasAttribute && entry['extends'] == tag) || !hasAttribute) {
+      return entry;
+    }
+  }
+
+  return null;
+}
+
+// List of known tagName to DartClass for custom elements, used for upgrade.
+var _knownCustomElements = new Map<String, Map<Type, String>>();
+
+void addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
+  _knownCustomElements[tagName] =
+      {'type': dartClass, 'extends': extendTag != null ? extendTag : "" };
+}
+
+Type getCustomElementType(object) {
+  var entry = getCustomElementEntry(object);
+  if (entry != null) {
+    return entry['type'];
+  }
+  return null;
+}
+
+/**
+ * Wraps a JsArray and will call wrap_jso on its entries.
+ */
+class DartHtmlWrappingList extends ListBase implements NativeFieldWrapperClass2 {
+  DartHtmlWrappingList(this.blink_jsObject);
+
+  final js.JsArray blink_jsObject;
+
+  operator [](int index) => wrap_jso(js.JsNative.getArrayIndex(blink_jsObject, index));
+
+  operator []=(int index, value) => blink_jsObject[index] = value;
+
+  int get length => blink_jsObject.length;
+  int set length(int newLength) => blink_jsObject.length = newLength;
+}
diff --git a/sdk/lib/html/html_common/html_common.dart b/sdk/lib/html/html_common/html_common.dart
index dfdfa27..c2e1644 100644
--- a/sdk/lib/html/html_common/html_common.dart
+++ b/sdk/lib/html/html_common/html_common.dart
@@ -9,6 +9,7 @@
 import 'dart:html';
 import 'dart:js' as js;
 import 'dart:_internal' show WhereIterable;
+import 'dart:nativewrappers';
 import 'dart:typed_data';
 import 'dart:web_gl' as gl;
 
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index 13e7012..f2ab9c4 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -92,6 +92,7 @@
 import 'dart:math' as math;
 import 'dart:mirrors' as mirrors;
 import 'dart:html' as html;
+import 'dart:html_common' as html_common;
 import 'dart:indexed_db' as indexed_db;
 import 'dart:typed_data';
 
@@ -258,7 +259,7 @@
 
 String _getJsName(mirrors.DeclarationMirror mirror) {
   for (var annotation in mirror.metadata) {
-    if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "Js") {
+    if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "JS") {
       mirrors.LibraryMirror library = annotation.type.owner;
       var uri = library.uri;
       // make sure the annotation is from package://js
@@ -700,7 +701,7 @@
 }
 
 _maybeWrap(o) {
-  var wrapped = html.wrap_jso_no_SerializedScriptvalue(o);
+  var wrapped = html_common.wrap_jso_no_SerializedScriptvalue(o);
   if (identical(wrapped, o)) return o;
   return (wrapped is html.Blob
       || wrapped is html.Event
@@ -819,7 +820,7 @@
 
   static JsObject _jsify(object) native "JsObject_jsify";
 
-  static JsObject _fromBrowserObject(object) => html.unwrap_jso(object);
+  static JsObject _fromBrowserObject(object) => html_common.unwrap_jso(object);
 
   /**
    * Returns the value associated with [property] from the proxied JavaScript
@@ -858,7 +859,7 @@
   operator ==(other) {
     var is_JsObject = other is JsObject;
     if (!is_JsObject) {
-      other = html.unwrap_jso(other);
+      other = html_common.unwrap_jso(other);
       is_JsObject = other is JsObject;
     }
     return is_JsObject && _identityEquality(this, other);
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 26d20f4..b9ce88a 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -24,15 +24,13 @@
 LayoutTests/fast/xpath/attr-namespace_t01: RuntimeError # Dartium JsInterop failure
 LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Dartium JSInterop failure
 LayoutTests/fast/xpath/py-dom-xpath/axes_t01: RuntimeError # Dartium JSInterop failure
-WebPlatformTest/custom-elements/instantiating/isAttribute_A02_t01: RuntimeError # Dartium JSInterop failure
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t01: Pass, RuntimeError # Flaky with Dartium JsInterop. Seems like timing issues in the test.
 LibTest/html/IFrameElement/IFrameElement.created_A01_t01: RuntimeError # Issue 24568
 LibTest/html/Window/document_A01_t01: RuntimeError # Issue 24585
+LibTest/html/Window/requestFileSystem_A02_t01: Skip # Issue 24585.
 
 [ $compiler == none && $runtime == dartium && $checked ]
 LayoutTests/fast/css/style-scoped/style-scoped-scoping-nodes-different-order_t01: RuntimeError # Dartium JSInterop failure
-LibTest/html/Window/requestFileSystem_A02_t01: Skip # Times out. Issue 24585.  This also has an untriaged dartium failure, in the section below.
-WebPlatformTest/html/browsers/browsing-the-web/read-text/load-text-plain_t01: RuntimeError # Issue 24585
 
 [ $compiler == none && ($runtime == dartium || $runtime == ContentShellOnAndroid) ]
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba4444_t01: Skip # Issue 20540
@@ -241,7 +239,6 @@
 LibTest/html/Window/moveTo_A01_t01: RuntimeError, Pass # co19-roll r706.  Please triage this failure.
 LibTest/html/Window/moveTo_A02_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/Window/postMessage_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
-LibTest/html/Window/requestFileSystem_A02_t01: RuntimeError, Pass # co19-roll r706.  Please triage this failure.
 LibTest/html/Window/resizeBy_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/Window/resizeTo_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/isolate/SendPort/send_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
diff --git a/tests/html/html.status b/tests/html/html.status
index 0741675..893d8ee 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -13,8 +13,6 @@
 mirrors_js_typed_interop_test: Skip # Dartium JSInterop failure
 
 cross_domain_iframe_test: RuntimeError # Dartium JSInterop failure
-custom/document_register_type_extensions_test/registration: RuntimeError # Dartium JSInterop failure
-custom/element_upgrade_test: RuntimeError # Dartium JSInterop failure
 indexeddb_2_test: Fail # Dartium JSInterop failure. Identity preservation on array deferred copy.
 js_test/transferrables: RuntimeError # Dartium JSInterop failure
 js_test/JsArray: RuntimeError # Dartium JSInterop failure
@@ -24,7 +22,6 @@
 [ $compiler == none && ($runtime == drt || $runtime == dartium ) ]
 worker_api_test: Fail # Issue 10223
 resource_http_test: Fail # Issue 24203
-js_dart_to_string_test: RuntimeError # 24584
 
 [ $compiler == none && $mode == debug && ($runtime == drt || $runtime == dartium ) ]
 datalistelement_test: Skip # Issue 20540
diff --git a/tests/html/js_array_test.dart b/tests/html/js_array_test.dart
index 58d42db..598cadf 100644
--- a/tests/html/js_array_test.dart
+++ b/tests/html/js_array_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-@Js("ArrayTest.Util")
+@JS("ArrayTest.Util")
 library js_array_test;
 
 import 'dart:html';
@@ -159,7 +159,7 @@
 """);
 }
 
-@Js()
+@JS()
 class PropertyDescriptor {
   external get value;
   external bool get writable;
@@ -167,14 +167,14 @@
   external bool get configurable;
 }
 
-@Js()
+@JS()
 class SimpleJsLiteralClass {
   external get foo;
 }
 
 class Foo {}
 
-@Js()
+@JS()
 external callJsMethod(List array, String methodName, List args);
 
 callIndexOf(List array, value) => callJsMethod(array, "indexOf", [value]);
@@ -189,73 +189,73 @@
 callListMethodOnObject(object, String methodName, List args) =>
     callListMethodOnTarget([], object, methodName, args);
 
-@Js()
+@JS()
 external jsEnumerateIndices(obj);
-@Js()
+@JS()
 external bool checkIsArray(obj);
-@Js()
+@JS()
 external concatValues(obj);
 
-@Js()
+@JS()
 external concatOntoArray(obj);
 
-@Js()
+@JS()
 external repeatedConcatOntoArray(obj);
-@Js()
+@JS()
 external bool everyGreaterThanZero(obj);
-@Js()
+@JS()
 external bool everyGreaterThanZeroCheckThisArg(obj);
 
-@Js()
+@JS()
 external filterGreater42(obj);
 
-@Js()
+@JS()
 external forEachCollectResult(List array);
-@Js()
+@JS()
 external someEqual42(List array);
-@Js()
+@JS()
 external sortNumbersBackwards(List array);
 
-@Js()
+@JS()
 external List spliceDummyItems(List array);
 
-@Js()
+@JS()
 external List spliceTestStringArgs(List array);
 
-@Js()
+@JS()
 external List splicePastEnd(List array);
 
-@Js()
+@JS()
 external String callJsToString(List array);
 
-@Js()
+@JS()
 external mapAddIndexToEachElement(List array);
-@Js()
+@JS()
 external reduceSumDoubledElements(List array);
 
 // TODO(jacobr): add a test that distinguishes reduce from reduceRight.
-@Js()
+@JS()
 external reduceRightSumDoubledElements(List array);
 
-@Js()
+@JS()
 external PropertyDescriptor getOwnPropertyDescriptor(obj, property);
 
-@Js("setLength")
+@JS("setLength")
 external callSetLength(List array, length);
 
-@Js()
+@JS()
 external getValue(obj, index);
 
-@Js()
+@JS()
 external setValue(obj, index, value);
 
-@Js()
+@JS()
 external callListMethodOnTarget(List target, object, String methodName, List args);
 
-@Js()
+@JS()
 external newArray();
 
-@Js()
+@JS()
 external newLiteral();
 
 main() {
diff --git a/tests/html/js_dart_to_string_test.dart b/tests/html/js_dart_to_string_test.dart
index f702d6b..5293053 100644
--- a/tests/html/js_dart_to_string_test.dart
+++ b/tests/html/js_dart_to_string_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-@Js()
+@JS()
 library js_typed_interop_test;
 
 import 'dart:html';
@@ -22,7 +22,7 @@
 """);
 }
 
-@Js()
+@JS()
 external String jsToStringViaCoercion(obj);
 
 class ExampleClassWithCustomToString {
diff --git a/tests/html/js_typed_interop_test.dart b/tests/html/js_typed_interop_test.dart
index fb69069..04915d2 100644
--- a/tests/html/js_typed_interop_test.dart
+++ b/tests/html/js_typed_interop_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-@Js()
+@JS()
 library js_typed_interop_test;
 
 import 'dart:html';
@@ -92,7 +92,7 @@
   var a;
 }
 
-@Js()
+@JS()
 class ClassWithConstructor {
   external ClassWithConstructor(aParam, bParam);
   external getA();
@@ -100,7 +100,7 @@
   external get b;
 }
 
-@Js()
+@JS()
 class Foo {
   external int get x;
   external set x(int v);
@@ -114,7 +114,7 @@
 
 }
 
-@Js()
+@JS()
 class ExampleLiteral {
   external factory ExampleLiteral({int x, String y, num z});
 
@@ -123,12 +123,12 @@
   external num get z;
 }
 
-@Js('Foob')
+@JS('Foob')
 class Foob extends Foo {
   external String get y;
 }
 
-@Js('Bar')
+@JS('Bar')
 class Bar
  {
   external String get x;
@@ -136,7 +136,7 @@
   external Foo getFoo();
 }
 
-// No @Js is required for these external methods as the library is
+// No @JS is required for these external methods as the library is
 // annotated with Js.
 external Foo get foo;
 external Foob get foob;
@@ -149,17 +149,17 @@
 external Function get returnLastArg;
 
 const STRINGIFY_LOCATION = "JSON.stringify";
-@Js(STRINGIFY_LOCATION)
+@JS(STRINGIFY_LOCATION)
 external String stringify(obj);
 
-@Js()
+@JS()
 class StringWrapper {
   external StringWrapper(String str);
   external int charCodeAt(int i);
 }
 
 // Defeat JS type inference by calling through JavaScript interop.
-@Js()
+@JS()
 external confuse(obj);
 
 main() {
diff --git a/tests/html/json_helper.dart b/tests/html/json_helper.dart
index 15f92c0..7d037ae 100644
--- a/tests/html/json_helper.dart
+++ b/tests/html/json_helper.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-@Js("JSON")
+@JS("JSON")
 library json_helper;
 
 import 'package:js/js.dart';
diff --git a/tests/html/mirrors_js_typed_interop_test.dart b/tests/html/mirrors_js_typed_interop_test.dart
index 1989ba9..a34bf1b 100644
--- a/tests/html/mirrors_js_typed_interop_test.dart
+++ b/tests/html/mirrors_js_typed_interop_test.dart
@@ -23,10 +23,10 @@
 """);
 }
 
-@Js()
+@JS()
 external Foo get foo;
 
-@Js()
+@JS()
 class Foo {
   external int get x;
   external set x(v);
diff --git a/tests/html/wrapping_collections_test.dart b/tests/html/wrapping_collections_test.dart
index dc84508..176bcad 100644
--- a/tests/html/wrapping_collections_test.dart
+++ b/tests/html/wrapping_collections_test.dart
@@ -1,6 +1,7 @@
 library wrapping_collection_test;
 
 import 'dart:html';
+import 'dart:html_common';
 import 'dart:js' as js;
 import 'package:unittest/unittest.dart';
 import 'package:unittest/html_config.dart';
diff --git a/tests/standalone/io/certificates/client1.pem b/tests/standalone/io/certificates/client1.pem
new file mode 100644
index 0000000..9b4601d
--- /dev/null
+++ b/tests/standalone/io/certificates/client1.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBzCCAe+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9jbGll
+bnRhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEzWhcNMjUxMDE2MTE1NTEzWjAQMQ4w
+DAYDVQQDDAV1c2VyMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTH
+xIsQGP4MxyAt8Jv4TgOXEvWAEBjMglmw0xULTUDXZ+tj9+1M6kwU11E/DNXjnPep
+zEgq6nX2BgQWCba6TBilOqjU/hiiz1Gm5+9jaW82SByMj+9FpsVyp3Gu3ujwYFYz
+wU5PmRUCR4WTFhy06cdq4F0+ci7q0s1gIJ6UHKS41/39srKkdmNiPeIai6ZIuv8v
+lgBxMv3HShxde4w7yDkJ7mzuchSHgGyH3EpjycbqfZOLeuGqdWfVOPsM/38y+NeC
+DwowrqA5SrdWGtJhpsN5GGmVYO0qQZZtCu1oruwduqTx6nMBWkyFCQCMJ8HwShpG
+q2X0DSfT5BQNrGyTHqECAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUpiY9
+3N5Ylof6MW814xa/CyDxokswHwYDVR0jBBgwFoAU/ZBUqBvh6hb/ZNWYS43nch78
+vz8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAJDBCztQ
+xGY+QGycWrIEPC66ss2WgjPp9cU/56IggfX5YN0YG03vItYlFqm4wufL9PF5YJ2y
+hd5by0tzUmL+Y6ZKYAdzffBjHk//8hdGxsNy/6KLLDbwRycWXq0Ywo5BnGTwJcpV
+m4VTaddYUk8nDTWCf6JYQMdFfF0LUziVUsyJF21CDiAXPCTSA4aSAy5/OhRTUzXn
+1MX8yZRgY//7sNz2nqEvuHD3uJWmDHm6//qzVI9fPlwh8++0NM7WKUmDf4Ehx1ix
+Fen2k/uWJUDqb95T3IeF/COJ9FAsO3pd+cpqwzYcd2H5ZMGZI63Za0r3ypSTzSGc
+tO8Mp8b4fDVltvc=
+-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/client1_key.pem b/tests/standalone/io/certificates/client1_key.pem
new file mode 100644
index 0000000..d319a72
--- /dev/null
+++ b/tests/standalone/io/certificates/client1_key.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE5TAcBgoqhkiG9w0BDAEBMA4ECGrn0qDVIUHAAgIIAASCBMNOid1sDMpZtXY5
+hySSdhyUB0Q+GEJZCJQoNIQBvlStUX3rUqUyWy+8Mb0igbUQznLALrmfDCFrPAbe
+lY9hiJKO5R4vhwWUOckT6LcejgG1U91EZF8s4iu0Be9haCHeu1gbhGNZw4exXIHZ
+aL/o0r+A6uQTGY4pTWcMajWu3cx9XiQ/dUDNBZjjUZg5qBYzQgNcNwzIxcD5M/qT
+C7Is3ngJWyEFESwo8PiZ0PsiudNXk2aRYdKSU+ncugUCvyYArxRgysLTJX+eP4ak
+s1za71JxXBpqNHSEHyexeJODf7V1NT16aHXuAzz/Tszdy8vv/SqrrV04NeQmJd8K
+2SPOfRAU8Kh8OvdSor9SWujwlEuawCxn7rCyjAA/brR2SQHvMkbkkwO80X1gLvGI
+haF06C/mVcV5xaa9I2UiTb8VBgEEodANIjbeYq+DyWOLXKkcJhdqG3DTljnebp+9
+7/P9m/VnvfZz7//2y+U9HOrpPQs0+FsUD2S1/XdjRozOPY2+knTtwvX+tmnooll8
+dGFRPYnWl/4AzgGp0KzbfGnCiwtGCJNbLzgH0jAR3Znu5xPrOtU3rCPy+rskuNQB
+JVcjdudPiGT/aABs4QWZauqAiaUE7BKhperORAhoFFkvboyvIjSLCOTn8f2+YEaW
+bIGS7EYCVdSRchOMubf7EM1CYugCZw4gN2NifP1PBfnSJoZrbAWK5ZqK++THGP8l
+uIIDdelIsZ5lB1OVTfVrdRC2LA6kUdus8a+ATcHhmgHOAaGH5Sj6hEJjtBSVF4Tm
+JdI6PIIS6MFWrIEP1AHU1zXztpOZkm4f5poyuFfWROiFQbua6y6H1tBiqh8xEs6x
+2pDFlSmGdswC9ejvokea5tOMC86U4syRfkE3Mw3kmAOTdNvZsWGv/C6yBcbMw8UO
+aLWjZI3Uwh+Lh1PMayckk2sxm+bnfsa75ITJc8E4fZC8UYF+dUjgpQU8Tb61lo+J
+sZaGQTYmai8p0FKcKvikQbEKOsmQQAAGuvNgaWlP/gSMzR3JjOf4ULVBfFIaW9qA
+UwvgbUEh3YQlQW4aHs5tGWyUjkHOEPCv9V1zDeEfNQ/f76xK826jVg2EEFahUNAI
+ZP+Isl0QVjPPMVo61U4FHWYo4NdRaHD27tVh25wAjXe/7sCPHrgn4A6qtSWbVuFw
+CJUGiC1zt9qCe3M801hQOJc1Re/hjcZ7sk08dYp3GGP0+ixGzwtAaStOVKLnCq79
+Uv+BWcu/NxUqDpynoO3uh+yGx5WChySXkhY+m9zgXrZelwErGuOYUG58Z4zRKkiz
+Qxnp9yxl9iBabpoPbR+4VjJbIO2cKKtWfaDtf35z6bbsddrKS2BPKtsFTCn06b80
+eCJpn9ewF4MASyCgQjSFVTMvNZWB1fLTb6Jl6/+deh8Sd2AF1Ks45j+ckxWMGF4L
+KIn8hK6Bi9KdgqJna8pKKB4h0U2s9K3IFB11YXQ5uDHO4TXmXz2LXLQNgjriF0RM
+ZUSphNRNC5JX/2uwmiO3HqrBjoiDDWWkt0TALDGjspaiYGSjfOnuI0SSM28RP/NZ
+f4KPRO8QhMBo8Mg5LrK7uHu+vVeIeC3qEeTBtiy33QypxKZpd0k1UwBDeGOZPgM6
+dwOrZv5D4qob
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/standalone/io/certificates/client2.pem b/tests/standalone/io/certificates/client2.pem
new file mode 100644
index 0000000..2898b7a
--- /dev/null
+++ b/tests/standalone/io/certificates/client2.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBzCCAe+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9jbGll
+bnRhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEzWhcNMjUxMDE2MTE1NTEzWjAQMQ4w
+DAYDVQQDDAV1c2VyMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXU
+3aFyhBspz7k2QfrykxkMR07uC7uulmXgRJvNjNcJ6GrA5d+oRGqXH+czO6Wd2KdV
+mrwxCR3mpzNViwUC8DeG22+QagkVG/MY3lq2oxADpCNEXUdWnieG6bZ7/bk1xGU9
+Kees4Dac0evBZoZINTulat28pwms/+k4hCEqIh9ikR5hOwyVTVXryTrpnUwrRKWc
+LDrtOhcTnsKD0ooJLl4X/OGkjTGmDlppLgiumF+gJC0fG0ztScFC/m+u3dlMNNTq
+tLFV7jpuknY9mZeIVHHNLGZG2ndWHpzAHj+suvQxYwiUs5zY90ZsDbdYms4GIF8V
+Bf26/nns7MkD9+yl8WcCAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUAuH/
+tf79clRyfVDepfCubNTGudwwHwYDVR0jBBgwFoAU/ZBUqBvh6hb/ZNWYS43nch78
+vz8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAEbWKUUT
+U6nK4ZfRo2x8vOHLK802aKHaiCjtG2JGH5iEl1hHwS1Qtf33Sv86V4SqpM+gwN1k
+2eWd5Yb2WsVmOsoxGwazYcH/G2G43/WImUk4oyeDKEW/ZSyXhyovHADkeI5nfJKL
+hcjLApVtw2RRVbG7qlGEOMS1FbDdbY0D8lFeX137Kqrbb4iV2+PQYM9TBrm/Tb6k
+2t4VS+0+QOkYH5vehUJAxOrJgIelcM4XsdKdVdhOZBPoxv+wptsBh+XhfxyHo8ff
+hcx+AbjxAxBo/uffngQW7ae5LbZIEUG7ERPmnuuFtJ1GgITA3Se0wJnPE8pEnbIc
+HJJsyEEspfKp09w=
+-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/client2_key.pem b/tests/standalone/io/certificates/client2_key.pem
new file mode 100644
index 0000000..029ee6e
--- /dev/null
+++ b/tests/standalone/io/certificates/client2_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIGKwU47HxW3UCAggA
+MBQGCCqGSIb3DQMHBAg92EmnGIvChwSCBMindKIgxnxh823tDdWq1TkjJg82SFNs
+4SX2T/TIuSEwZTTfDLxStdFfu/O88x4ZfOc1H1u4ph7geJgHadf8+oCQLXcofzPS
+86iNvaaJLoycWAUkgGKS3PqtvZ+QJYnKnOs0YlocZUk1C/gfWB+xApoWDzHUgsVC
+HQcAako8scbj15dofplgUSiN2a79WfZqbxupLkky9Kz97dC4cgcSOmPA2eSQ4Kct
+exRyR8M8tv6d5l4avmzONf7T++zFkM4EiG5+F8+skDZchuYrEYAsej5hKDAIMnFB
+rwZPxcyYTABuS4zoobAAts5S0f2Vy/OoaxsFNu6pvUncZ7Kmqkkopn9+5W1PeYyO
+p0d8607AbLCLcr16qnda87gpcaXX7rZ2WROgZrZcubg1N3jjYM44ZlsZYr4gHIdY
+kUwrgJqjdjJ0EZp9RQCkdnC50H24aMG4oq0LuuhLRbgwDny5T+NNVvfgVxCgNg+4
+hCTGBud3PCfDUoFGq1M6J2e1kfgw0FikJL41LGGOpvIo22MDR0lPHOkl6ZeO2ARt
+hlhtMl7wGKJE/ToxhbfRCLz9lSsG2wbGgB1wSAXAZcDlVN4QB9/Xtn71LObs6zE3
+kG8MfRzqiFZWAsLgTiprJagq4ylFvrGLW+pptnaI8A4IVeNy8nYe4I/UslvaXYrZ
+qh4U1rx2HuOUQQo4KtKnLN2zEW86bOEFHb284TW+aavFf2lq3zU31MboSEB7X/xd
+kRDKSqrVmZbnZRSVhhqtush1vAnETbSjGxZrUvHcaHU3RcIg1pAnBFGDWosNH7MD
+Sd2pDnGrJp8P04ftR+B97CNIBmgG+5SKt196oCO0gq+ROyspSYknlcnvGruQBANk
+qMzEBsjKgcDKc0XbnSM8gB6Rwv1/mxsZy+xd27DwdEfxNZqvbugZqr1gy4HowssN
+vhbfKUE7STcur4SDGuDYSC6U2jaebgV2SIHYod+kG0AI0Xo6CwpRHQjNPwOjwzKc
+U2pRpBRtHNBATj0jeP5p05+bUGd1RYj76Qy8oeN4C6DAd/XAGgVMgCpBUsSzDMVA
+sX7b9WYrgKF4JXKQrCBKcxJKzAGwASVjdfWDtxjvN1wqy2aj4ToW+ImMvgPf0g+L
+8JqAj7elkUOs2t6LxvQEViMFHmIxXweCLtAovEKVSMdYSPEwzBmqU5l++xZHx7kr
+KYowT6sfUEJ0A6JH7SMYJndNwKyYr2FLGTfkL0qcxwlOmrCVYy2yFN3F3bdQIfNa
+2FKu3hPR6LgD1Vl11HQyu015cv/LGTukkHZUAMruyYQTBGlY/Fym0xrj8tvsU8sP
+ZHhauOhg8kg7GR4FoRLc9sS5M3bY9JHd390PISFnGenE1iVqEp7BzMV4mUelFIP7
+OzWzufiRmsAzlIt2sR44cv4BKZfgsO4l7qsQTYdn+3e/dEfWXZ0aOd5jJ/M+T2Y5
+7lAdLnY2tapxEQy/KRasdGPbzCQH8l84zGV3uoAfIxpIkFaQpRRd0053e9cZWras
+3Dj4J59Q4SUsKJeH5muXCKoFUBPkVS1g8qIJk4Y7I2XRKICskK0DYvmL62tP0Aas
+rC6qjEv8HOV6kRBt6VCzt3nFYqodPFUNdmGYh9tuidaAFPt9CBg6I78IpiB9JoxS
+YrY=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/standalone/io/certificates/client_authority.pem b/tests/standalone/io/certificates/client_authority.pem
new file mode 100644
index 0000000..4bd5d3b
--- /dev/null
+++ b/tests/standalone/io/certificates/client_authority.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDKjCCAhKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9jbGll
+bnRhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEyWhcNMjUxMDE2MTE1NTEyWjAaMRgw
+FgYDVQQDEw9jbGllbnRhdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDDUuYMDCw7aXr++mXOcSr57uKhpriDN4He73Lz6r1jRg43nx/yCj+I
+rlOUd4kAZcMOv67W3oitzTlLER2pIFWLvG9GwLcgXtoiWD9wyHOod75cc4qjdRz1
+QRTPBqPXOHfe20Q3csR06Z6TM70cGFad+q4QIKK0Q4M4OnD3Rn935dtd4JbfiWXM
+w8h2XagjEqDWhZCIWJr06D7Wn6b1H3ch7o7M/TvjvUoyRnrfmTWHuIiETcpHXQXX
+nNfyrmaNyvJTE+HFknirVEkyMUzNao7CLecWD74NDRDZBQieSJQsu7oiucAvhBZY
+GblIv3Mv15cs2QkIN5JNN1+jl8LCImQBAgMBAAGjezB5MBIGA1UdEwEB/wQIMAYB
+Af8CAQAwHQYDVR0OBBYEFP2QVKgb4eoW/2TVmEuN53Ie/L8/MB8GA1UdIwQYMBaA
+FP2QVKgb4eoW/2TVmEuN53Ie/L8/MA4GA1UdDwEB/wQEAwICBDATBgNVHSUEDDAK
+BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAWBF95hJRPEfV4S2wAAupnr4s
+8nQeVb2ANnALEX1prwr/xQM6DY+cLasHH84Vp47KH10DOiCxJGH7xlUVlVx+PWzu
+EGNDiZINVyFkXytkpiKG0/jd+0jR1lnmUp1WU1Zli7uRNxFRsy0G+tsgaoD2gvk7
+14zx2en1/1beGL4lRoMLJ5yVdiSRjt/H37ZPjVtCHiHLRfernCPy6rj1KtmdL+gC
+C8Jr3I+haXvEFr9vMbNUY6PwkdJ1xITs7CTjXFZ2bka/Glnfqzg1KavkI3WsYq8R
+mFniNvRw74z/kNrcxT/W956vsD+74OFI6BoeNi8acw7J+zvYjIWUo5h3BcG8Eg==
+-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/server_chain.pem b/tests/standalone/io/certificates/server_chain.pem
index c653fca..ff6e568 100644
--- a/tests/standalone/io/certificates/server_chain.pem
+++ b/tests/standalone/io/certificates/server_chain.pem
@@ -1,57 +1,59 @@
 -----BEGIN CERTIFICATE-----
-MIIDPDCCAiSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
-cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDEzMTQzNDQ0WhcNMjUxMDEwMTQzNDQ0
+MIIDZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
+cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEyWhcNMjUxMDE2MTE1NTEy
 WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDgGEoJKUJIo0nICRkMHWmXyZcQa4j4TIRndtH7HS6Z/GDQpo849zKU
-l8lAql+BuOv0ridXz5qnaspNFyw2QgxH6Yc69V1CM5pBfF0QwJccG/Z4WbVZTSK7
-+ED7t4qm3VPTvjHFjKaPXhwQFItPwkUq5vPomNeCYEKaDWHHuffwFLwN0kjv+6YI
-3vyZmcij7Rhf76K3EV4kJowKcIfSQ8qs9Ts8PkRmJRtYXp0sHuRhgl+cmn6i6yNp
-ebVZN2oD4EYQzijPCF9amUwjkOKqyHqXdf8tq+h0sVVQJddUf/abLa3UB4km6pvF
-QLm3jbhq0isP6zVjMVO47vnX5AjrJM9LAgMBAAGjgYwwgYkwPAYDVR0RBDUwM4IJ
+ggEKAoIBAQDca2l3VIWhnlTqazrA07hiHjgXACUYS/nVox+a2Jar383kBz2kzN6B
+u4K7IwD2msym2IOBp1YT9OKPh9/KkSGvpPelu7ToCoehala32W+0ozh53CR8IpzQ
+tmh7J9oHtN2PcbLgEzHfAWyrY3xp9RpWUONjxoG8xXPedNsZL0Rj65Z3fKAjOypl
++XJsgrqrNNAi3x0OMdhextMmLrYl+YQjgdND8UpykTSc8Q0vwngDZuLH/Nhx0cAA
+Ade0ZfXS6snwWVxrWke+zGF6yANoiV00gsBhq+WZZ50SmE2mz5LT9uj4t5WpcOI/
+2TlbV9HSjdOEAFD8cJIrK5FkEmz383E1AgMBAAGjgbQwgbEwPAYDVR0RBDUwM4IJ
 bG9jYWxob3N0ggkxMjcuMC4wLjGCAzo6MYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAA
-ATAJBgNVHRMEAjAAMB0GA1UdDgQWBBRZ8+LQg9nfOOv1RaqPI9nrvbBufjAfBgNV
-HSMEGDAWgBRqwKMjCmov/0owT8uQJYA+aHX5QTANBgkqhkiG9w0BAQsFAAOCAQEA
-TJA1aeexRpyq2G81igrhtVysyCA2xBq3GEPHZNf6+YM65rJs8ngyLQ533JURy9QY
-hRHYYh4O387d6QUBpCH7QMCoO/IyhFnYaUsFuDi4Xfg0BY05uRj9oJlyhtOoPR73
-yFu3bK6CKyRjQ69HX+QpaJUADgRjuyDV6BAhq3oCfDghql1HBplCEJelcoZUs2xj
-Ao5Hw90mm03JgmPMkftEFIlsbBejPTIN7IhdNRJy3mJfY5r0g1MLAR8UHtCRTsxy
-AQkZjpVKPe8kKR1wCY9xsOYpIvruLUcbVayzM6iXVDwWApgT2x1qgIlRb9ZzTjdj
-WJVFf3HhnyLstIpI4Vw+UQ==
+ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQO+6Atr6tkTBmPasN4oTDUlbxQ1zAf
+BgNVHSMEGDAWgBRrkK4hOni2neySWQNmMfb9imn/+DAOBgNVHQ8BAf8EBAMCA6gw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBACdVUzrhfXoW
+wG0zI9aT6CxD7T0i0WK4fC6Yrx0Pqz53xnuiwBfvuAJ/PRXKYsJMxa2LuHGJKU/A
+nImCXGJHoUwL6x4Eor6fg7L9nPNqtIrQ6tzubxNtVPpLj4tK6Ps3IM+FICYUSX0b
+FLSfnv74afUp/2+0OHsoUVsL1rCTO2WgEkEShLERdJvdcvUSTWHfC5IQORS9vfzG
++cZGOOPebfm8TY2DJxMYj/t7CHs1Sk550x590sKb/prwtJAYtQxGe7v0m9rihiM3
+dFKZiNh99yXbQ1ELYyhkFP8WAdK8ZTnynGqgAYJmV89Dg8k2uU8z+dahlE3foORD
+Y/Gn0CZE1NY=
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-MIIDAzCCAeugAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQ0NFoXDTI1MTAxMDE0MzQ0NFowIDEeMBwG
+MIIDLjCCAhagAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowIDEeMBwG
 A1UEAwwVaW50ZXJtZWRpYXRlYXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAuas8jPtdCT4lahfVYHBrmUlFAvfKa5odZ7XqJ6TRMfzuoV6a
-51H6L90GToMFBOvcf7qzsdw9y07rS61mGfK4c7BifsiMbm+2DNvnKwVqH7d6FVYN
-oHYgn3FqBzCebsE8f8LD+YE+XC3JPp84QnE5jhv422rPp4FnugjK5xIpQuhRa0GH
-CVBpEe9Sq/KQXHW0lKcVLAL4eHrupdRdNJjDaVT3ZzCwUVHeBdQtkc8ZH/64H0KA
-+G+W+Bl4NPCqdLUCUwSn8RGxYj2Su7RZNvD2leyW1GtIbztztaSLbKZ48ZnjNnzg
-C5J3T6kqNXsJExDm6gh5GxIndUjaQ20SB+XfWwIDAQABo1AwTjAMBgNVHRMEBTAD
-AQH/MB0GA1UdDgQWBBRqwKMjCmov/0owT8uQJYA+aHX5QTAfBgNVHSMEGDAWgBQf
-nG+qRtaEj/s3oh1Yrf94203UFzANBgkqhkiG9w0BAQsFAAOCAQEAYr/qbcG6WybE
-TB+8UU1eN06tXvSGL1mtNlMcjyFc2PZDsdo+XjehXBqyF3k6raCJAdttiyjHlalj
-58D6F1IK1x/c8CNS5WxOEBjkTwy8KMK1vpggYO+lvkjJQL9RGns0fKrsdYexCPtn
-iKmcRWgfJWs/mT5LmxBsufYxIvAAuzjJNMrmrxAbComJvcjbJPf8rPqMLmnYoV20
-ufSK5euF3CCbtKUXQuqR2XY4kX+hmzuu7UGyOvlUXSa2J6aGTsutU0KRWlsisiTh
-ts7qtG/pzVEEYs71dTL6OmXGjxQFmtsVHZog/ybNVYP4Mvz5eA+SkaiUPrM/x46F
-YzNX6fPCwA==
+AQ8AMIIBCgKCAQEA1OV9iea75DPQ18NppXxEFW26J7IfjUvp4wVnj9m7pOhsByqd
+wwS6hpjlkpEwCyugKD/t7u/VGwp2BB+BeaX7FPj6rnYY82bOJQlyB/vvDmOZfAe2
+84ug9O7QcsQHSQ7YQFuvYKaeYCKdrGjzQPVYkoVdv2js2dYTDG3QSIxpbi305Vef
+ia6Zfs5CAW/SfL36+ETo2pXNlD1ZBGRL8H3z+mMnIEj1Tbaipf+1Npr2l3xqIs1k
+RWsM3X+9xMkWGyvsDdbLIGiTTVxM9kOF0aNLdQIKb2tZsg4jRrFIgiO+5TXwp0FW
+4ldc5/GhtaoPDcsIALyIQc7CJ/PpPm9hnxIy7QIDAQABo3sweTASBgNVHRMBAf8E
+CDAGAQH/AgEAMB0GA1UdDgQWBBRrkK4hOni2neySWQNmMfb9imn/+DAfBgNVHSME
+GDAWgBRpz+jRK9iGqijrL/4WCsGsIjxoETAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBACcwiLJUPzYGIeGIYGlo
+XlP4++adiPlXvsyTxLdGVSFWJMBV5EhtiXQXaUsOs2PyC7SWxiiUdAgE8Y2tMsF3
+Bh5LY/kKxZQXZuFa+RN1kPlhlYJWdiPyqcBziSPFBtqwudWLDUVSaVAQDhYYVB3K
+5+pFaeQKfhYmPvJKR9U2nTvukOhN1fZM8GUBnm2uaiA3giQ0wxXyQIuqC9S52qbh
+x4D4ZdbshQAgThPkHBoZVmd/NF1TNzitZZy7uaU7GpGrS1dcevN7pEUwm3+KIkIT
+AOSLB2FbFOwPUg6a/lWkFPotT3gl0tdyCaqkfneGCHzVciT0JTS/AqpdYEtuxEMe
+PJk=
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
 MIIC+zCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQ0NFoXDTI1MTAxMDE0MzQ0NFowGDEWMBQG
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowGDEWMBQG
 A1UEAwwNcm9vdGF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBALLIFA1JvTuzPd0uD8uOxdGZmwlaRXyytqkQF66UGM+HLCmH6Vro5TpRL7Ka
-4fgEpbhS5purJqjpUiZkavxxBKQkdpxM0nH1lLX6NnR6UVh/Z3Tv6s8cR3o9L60J
-iH4N7hGdQH9Anz/PBXbshoMJqU+lZkOoqcmk4Tk27uxNlbpTLFoarm67hzqe4v/e
-xAfh4HoBZRVdnpWezM/7aX1hw2B2iFiU8pgyrVKZnXRhh4I6Ba1XTd37lc2d1fuf
-LaUICoAruR/ZhvRQaOtAN05dAHSOB9612WBBaEEiWzz/piEDEownZQ7NBWC5ANj4
-xRp7JPNtQtxYoju6j9MIJ4JoOQUCAwEAAaNQME4wHQYDVR0OBBYEFB+cb6pG1oSP
-+zeiHVit/3jbTdQXMB8GA1UdIwQYMBaAFB+cb6pG1oSP+zeiHVit/3jbTdQXMAwG
-A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAC8PKipPvbQ0TXBKCMnCZiPI
-Vs7IfZuEzOgV6VByqveXuN8WJA2+ax9+2t1xuyIgftjj/uNJgm82AceVZqAtkGF0
-n29mPyoPC2tcrPHV2QUXy26+Rfb2JTQkkHXUnRtgU+gqnqugh+r9CCjoM0XkvR26
-/OrOmy7JIHtGPq5JEH9L73UryKKdQ3HS0ZkOMfxRyMNBa0y2/hYW8QDz/m0a1U9z
-q1rLvtYXZKWhz6dJJrphF6iBDzm+r6zo+uyCU7mps5wlGB9h4Ez8nx/Af1iT0HPE
-cl5zOR0RA5qefGx0hIuaxq0mHEYDY/coJ2rptvHwcnwgtSXBaQLe6MMNP+ElYDE=
+ggEBAMDzkcftGzdNJz5vXEAZSCAO2J6bCPz896pK3qtaViR/aF8I2vHZQm0IEoJc
+Y1NUMF3F50d6fMYCkEoORAkC0d7iAwTprhBdIg35+TxwGObcStrohDtEgwFmFRzg
+LtYeXiU0t0dBWOOQ9k2f9VGqbzKwZ2dbhOHSTXMTFoEcMStbeFc++oiOLY+QSq/J
+Xd/BXqvwVM3Mt+OwLvyUu45Kw18ENo77qubIPJUwoyaf+N2nFRqcc7bmNy0Wvk2Q
+StvQXy6DpN3KOoZx/sR7Ff8hYuHXcxbSsJ1hOO+tIJyOZyEJvU2BBOYVlKr4E4JU
+mkex0CM1IfIFqfcEkbvjwLjaojsCAwEAAaNQME4wHQYDVR0OBBYEFGnP6NEr2Iaq
+KOsv/hYKwawiPGgRMB8GA1UdIwQYMBaAFGnP6NEr2IaqKOsv/hYKwawiPGgRMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJKl4RCEaXwtosNeurZlS3b9
+owXdsXDRdnfEawcc//AbRkrS4bHCQyOJNp/3DibEKkeAXCJrJ5cvXRjE5gb3Q+rl
+0AqziLY15xuMAxUK3zv0e8Zir21PQzQ9x8zbmlucEoT/jn7KvMSSqfEoer77cXev
+BpmQDQzE3FNgKohmHIzIDoTPiU3ahv6x8IhJ1e47UmRsSPFgtqglHcdCYIEclXpY
+bHvctT6+pFZuJfIs9+BATMXPJWSX7NhlMcnyP+xdDxDKuF/nwVFy6xA+njuWnnZT
+TyiGCnx+u/VpKzOrwMfzv2DW8Db80UERoox5n6QNQLnXNWPMddUL92/p9lMzWJY=
 -----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/server_key.pem b/tests/standalone/io/certificates/server_key.pem
index 4486e44..29a9e32 100644
--- a/tests/standalone/io/certificates/server_key.pem
+++ b/tests/standalone/io/certificates/server_key.pem
@@ -1,29 +1,29 @@
 -----BEGIN ENCRYPTED PRIVATE KEY-----
-MIIE5TAcBgoqhkiG9w0BDAEBMA4ECHTqlBo01lkOAgIIAASCBMM6W9ZnVX28yt1o
-m1qzZCpCpn7B116hWgk/qWnSBEeT2i+wUeG22fDn17/XrcWIJT58k0/FGWiQn4yT
-Cya55z9J3JKwC22+BVlUErBmlanfwEXbJOjivEvMqSLd98smmA+nw8fUZnFBqH+O
-3sokCiRxK5t/PrC8ahWk+H800e9cvAViewxBwZkUGClVivs/oPAmAhgd4aqWS8Aw
-G4Bi58mUK8dL51cxapWXBR0oxBnedyhElNwgiSoBxUqgEB4yjS8SMAAEy+UReRnf
-kkkc0jyQi7aDhyRvRIm6OX7x/KPys1n4ZdckgaThh+VHitj2rb5xu/g0fxCRL+8W
-o4hcgDgsbYhs61ATO/7xqEFGTUqiRGQa3IgCey2gRHFRKh24OvUBJJK30jGDpT8X
-M0jcIeQGbclzqODPoSfxL51F8wVpbwv5VnsvnsPunNCYCpB3rXNSHQBFs9aiEdfF
-YNGH8wk9AYuya8Ji92XZ6pMheAfhbR5E5JeEZfo1gv1ZDEYLKhrFX30YjekU8L2h
-lyJpr0+nGhIAeKuw1FxQnTiIdv5Hs8wmBsGuMDK/gYPklLONHRw/G99sqqd1wB0l
-CLEZ8PVO/63dpXqoTrDJIRCsVa9/wanoX8XD5zDGFA2OLGuz24u9xJbcERegM5us
-DEKTZz/4XE2t3dFUzsf9EtBl4CkxKT4o7R+Q2akADGWp6x72XW/1LiGhRtFOjhsl
-enS5DONUCXndG2Sc3GemO63hWjlBsUAcz1mvJhd8zVK5Wg/FM0j8lhf9yFnPKd/f
-+6gGnnhASjeoX/FlQl0Jm5J8++hmH0bXqfcQXIE+klUcSJOs0aP8byXndvfWmtKZ
-VoUFZL55MW2TeO1MC1jkVWu6QfTHWSC0g6Lz48MN3ASejsDa0/Wu+Z/Wowexd/ky
-Z+CHG5LMMULSl9LAAZzFLld0tt1Z/fPRsyWCl2km9+NIRHlKC3d8btkip6+3X8Io
-AVvLugD2HIM5Mkad7+CwQuS014aA69fCGl11Ei8slSvP7YlN4f9qX8ledWUFTSAb
-qTvHT3AkdDI9iuLXgjTE4/uxJy2vIe/OioxzdgrRMyJm+nP/yeYoudyAtFYwHTii
-omh4zoWeAWDFmI7MCwAGYI526QjFTcf3fg0Dg+dx1lqcjw5aTzqCnJ6TEQTXE/UH
-xpOtRuJUnA2dYNgtanoInu18HPxpKpJimpf2N64ZmAYuAdpaYuj7uV/7coYTINCP
-LbL0FTq5J2hRXBtCiTViTwPKHXvomiHuD38jRYJK87vWfcHrfus6AnFJ2w+S6DUw
-cHziCh0MvQG774nDAcpZAfumx7tA4qX92EwtETifRf5vA/AWzkkeu+su8Gyze3al
-3J9plGmZ+4V81rh188mWHFTBBThiIi6Tqm7iLO/YGDyI+9PWQT9nLSb/pCKk//ZV
-v0VXUEpLwW0Os7cMAkfgaddrjakuON4rQ9b1ixb8es7bJiYhyhUuPoopJ0nHNtNa
-+Wtt5LRe1M8lqt++Xy+pmL95woCdGhvATYI0W6JJWJVIluequkhI/iQp0TdG7LlX
-A67qzWPCUIjYl8w/ydPLXo0803UKUZWYJ01eWdDKB16BYFBkT7uJlek/DZAOOb7q
-6Wo1KF3SnMiD
+MIIE5TAcBgoqhkiG9w0BDAEBMA4ECKAry4fwmB/TAgIIAASCBMNsKbVVvIs/l6/N
+/1J9WXSiA1gnRTd2n58GJUV6mkiaRUMiWu3fK+V7iHpIi7KeLeD+JGsDeqxw0bB5
+lmS/RJy0wNBP0PL0oiI8VUe3wxTUU2b5wW9fomeOTGWOIUL5VZXHkTCf5KMcFWMY
+GMnDpIN/f/m9zvz/3FogxIZlIAxG7gKKrfEcKExIShAJ5wYDbDSFZWfNcjMODGPn
+xz3W04aRsJGf3KlOQvSuNtcBpsuwXuAXezzuFETM20xrWW3iJIsO5UmqJ1OJcdet
+A+k5k0K+1/WwLkceWJYSd19O+7LNULsZhKUJ515ZSO1TJGgfd5DznkgRXYUx5ucS
+tvJLYvShGbaYulsVKn8q2nkIxnQCov3my1hIRk/qCKb+uOvRD9dIkjSlNubqaRb6
+geEOfTh1g5PCeKPlSTkVueLQqWxKMye4eWYqUxExkUNuGJ0d2ndBGJRo6bulnc7I
+kt44DzEufV5OLvyTufimpohqRm3Yzq87DWSSThCKOGkhfGutn8B7cJR8ZPrG2euT
+J7Bv4EuFjhpKDieqDi8yoXgIkWSgyzFNMsewV4lxFNP/wbvoKPFrKsU4ny6jRfzy
+WTjMN1UOTBvsyZbVvjLII79cBKLqlowHAZQ7YwuxtbjeB9FRH+ZwkzYeyn4GNHdf
+QoVwOMKAiOMjzAK9qdW7isVXy/7v9EXaZplRmwMRhCZevC9zeY2Rueahq8qpHpH1
+GPjrew5elPkBRQhxX6IiL7kI7upE65UI5hnnTnrdrZkRmMYOFEZLyLbTU4wMCxui
+4BmEiGp6qCWe3UND1b8YhG+gsRYzHK5oEJV+Ck7m+e9iU3/axggUfAhZeBmdlgqd
+bUajlzcgbtfaSgZ08XXU1YPw0aLlmJGzb+oWMFwBJHAUYpOV2uqDHiXZZt4SoAF9
+gJQaXvqMGzY8JyP5ZQauljVtPGcopA+jbix3Rbwf97lLqJHSpWoHpcCa6FrfaMqG
+dx8oQsO67WN0gm5DIN3kB2jHOj9Nf7kr3HGjyC5tPq8s1+aT6baZcHWzVfyVr10c
+9X13Pz5XzEa1oiaO7JDPkzb9T7aPJZwskATNB8h6tWfqdGyUY5eURtsCnVrtG/1p
+pAXyY/0vAksfDPjMChKLKxZ7rBbscoNzr2f7Vw4CTnIpaxA4eLEx6UdpG4/5RzYJ
+0YuR+SzCkuNti7uZGi9DCGkZkYl6VndatW+Pk/+JVBexdKt6MsER6aVsS8ev9UbW
+JG+2C8bjMlfKy21644KwYOtZbVcE9jwlsz8w+e6YbOzBvbwiPmoCi0xcMxRJPa2y
+cKMrs2hSKmhUP6uIH0b0qNcHEPA32mVzGC0MToC5R+yb6OdyvoEsisqS7tEAMfTJ
+0yowcZr2lPehaMr4efSB8JY6DuofitfgI6X6bmiIPQ9v//djxhkxkRAbpTRGmFZx
+1YIKDa72S8jUxHWlVvmoqTWI8T+jltF2pYBctS6IMKEot/CcBCHb5l1zfMyo5a0x
+73ooh5tq+vRWJGaLRMj66VVSWGQoJmfAGwWpjBpTLa0UQoHO0/J1IbfjFOj5HV3J
+bscmoGWhVwuJM5ActB0MOvXGQe9mf2X4p/1Rp+yBuipH1SJzFEzbOZ3kE50Z6aXH
+CoJJOKkcuf43
 -----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/standalone/io/certificates/server_trusted.pem b/tests/standalone/io/certificates/server_trusted.pem
new file mode 100644
index 0000000..96649c0
--- /dev/null
+++ b/tests/standalone/io/certificates/server_trusted.pem
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIIDLjCCAhagAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowIDEeMBwG
+A1UEAwwVaW50ZXJtZWRpYXRlYXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA1OV9iea75DPQ18NppXxEFW26J7IfjUvp4wVnj9m7pOhsByqd
+wwS6hpjlkpEwCyugKD/t7u/VGwp2BB+BeaX7FPj6rnYY82bOJQlyB/vvDmOZfAe2
+84ug9O7QcsQHSQ7YQFuvYKaeYCKdrGjzQPVYkoVdv2js2dYTDG3QSIxpbi305Vef
+ia6Zfs5CAW/SfL36+ETo2pXNlD1ZBGRL8H3z+mMnIEj1Tbaipf+1Npr2l3xqIs1k
+RWsM3X+9xMkWGyvsDdbLIGiTTVxM9kOF0aNLdQIKb2tZsg4jRrFIgiO+5TXwp0FW
+4ldc5/GhtaoPDcsIALyIQc7CJ/PpPm9hnxIy7QIDAQABo3sweTASBgNVHRMBAf8E
+CDAGAQH/AgEAMB0GA1UdDgQWBBRrkK4hOni2neySWQNmMfb9imn/+DAfBgNVHSME
+GDAWgBRpz+jRK9iGqijrL/4WCsGsIjxoETAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBACcwiLJUPzYGIeGIYGlo
+XlP4++adiPlXvsyTxLdGVSFWJMBV5EhtiXQXaUsOs2PyC7SWxiiUdAgE8Y2tMsF3
+Bh5LY/kKxZQXZuFa+RN1kPlhlYJWdiPyqcBziSPFBtqwudWLDUVSaVAQDhYYVB3K
+5+pFaeQKfhYmPvJKR9U2nTvukOhN1fZM8GUBnm2uaiA3giQ0wxXyQIuqC9S52qbh
+x4D4ZdbshQAgThPkHBoZVmd/NF1TNzitZZy7uaU7GpGrS1dcevN7pEUwm3+KIkIT
+AOSLB2FbFOwPUg6a/lWkFPotT3gl0tdyCaqkfneGCHzVciT0JTS/AqpdYEtuxEMe
+PJk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC+zCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowGDEWMBQG
+A1UEAwwNcm9vdGF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMDzkcftGzdNJz5vXEAZSCAO2J6bCPz896pK3qtaViR/aF8I2vHZQm0IEoJc
+Y1NUMF3F50d6fMYCkEoORAkC0d7iAwTprhBdIg35+TxwGObcStrohDtEgwFmFRzg
+LtYeXiU0t0dBWOOQ9k2f9VGqbzKwZ2dbhOHSTXMTFoEcMStbeFc++oiOLY+QSq/J
+Xd/BXqvwVM3Mt+OwLvyUu45Kw18ENo77qubIPJUwoyaf+N2nFRqcc7bmNy0Wvk2Q
+StvQXy6DpN3KOoZx/sR7Ff8hYuHXcxbSsJ1hOO+tIJyOZyEJvU2BBOYVlKr4E4JU
+mkex0CM1IfIFqfcEkbvjwLjaojsCAwEAAaNQME4wHQYDVR0OBBYEFGnP6NEr2Iaq
+KOsv/hYKwawiPGgRMB8GA1UdIwQYMBaAFGnP6NEr2IaqKOsv/hYKwawiPGgRMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJKl4RCEaXwtosNeurZlS3b9
+owXdsXDRdnfEawcc//AbRkrS4bHCQyOJNp/3DibEKkeAXCJrJ5cvXRjE5gb3Q+rl
+0AqziLY15xuMAxUK3zv0e8Zir21PQzQ9x8zbmlucEoT/jn7KvMSSqfEoer77cXev
+BpmQDQzE3FNgKohmHIzIDoTPiU3ahv6x8IhJ1e47UmRsSPFgtqglHcdCYIEclXpY
+bHvctT6+pFZuJfIs9+BATMXPJWSX7NhlMcnyP+xdDxDKuF/nwVFy6xA+njuWnnZT
+TyiGCnx+u/VpKzOrwMfzv2DW8Db80UERoox5n6QNQLnXNWPMddUL92/p9lMzWJY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDKjCCAhKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9jbGll
+bnRhdXRob3JpdHkwHhcNMTUxMDE5MTE1NTEyWhcNMjUxMDE2MTE1NTEyWjAaMRgw
+FgYDVQQDEw9jbGllbnRhdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDDUuYMDCw7aXr++mXOcSr57uKhpriDN4He73Lz6r1jRg43nx/yCj+I
+rlOUd4kAZcMOv67W3oitzTlLER2pIFWLvG9GwLcgXtoiWD9wyHOod75cc4qjdRz1
+QRTPBqPXOHfe20Q3csR06Z6TM70cGFad+q4QIKK0Q4M4OnD3Rn935dtd4JbfiWXM
+w8h2XagjEqDWhZCIWJr06D7Wn6b1H3ch7o7M/TvjvUoyRnrfmTWHuIiETcpHXQXX
+nNfyrmaNyvJTE+HFknirVEkyMUzNao7CLecWD74NDRDZBQieSJQsu7oiucAvhBZY
+GblIv3Mv15cs2QkIN5JNN1+jl8LCImQBAgMBAAGjezB5MBIGA1UdEwEB/wQIMAYB
+Af8CAQAwHQYDVR0OBBYEFP2QVKgb4eoW/2TVmEuN53Ie/L8/MB8GA1UdIwQYMBaA
+FP2QVKgb4eoW/2TVmEuN53Ie/L8/MA4GA1UdDwEB/wQEAwICBDATBgNVHSUEDDAK
+BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAWBF95hJRPEfV4S2wAAupnr4s
+8nQeVb2ANnALEX1prwr/xQM6DY+cLasHH84Vp47KH10DOiCxJGH7xlUVlVx+PWzu
+EGNDiZINVyFkXytkpiKG0/jd+0jR1lnmUp1WU1Zli7uRNxFRsy0G+tsgaoD2gvk7
+14zx2en1/1beGL4lRoMLJ5yVdiSRjt/H37ZPjVtCHiHLRfernCPy6rj1KtmdL+gC
+C8Jr3I+haXvEFr9vMbNUY6PwkdJ1xITs7CTjXFZ2bka/Glnfqzg1KavkI3WsYq8R
+mFniNvRw74z/kNrcxT/W956vsD+74OFI6BoeNi8acw7J+zvYjIWUo5h3BcG8Eg==
+-----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/trusted_certs.pem b/tests/standalone/io/certificates/trusted_certs.pem
index b037014..05470f6 100644
--- a/tests/standalone/io/certificates/trusted_certs.pem
+++ b/tests/standalone/io/certificates/trusted_certs.pem
@@ -1,18 +1,18 @@
 -----BEGIN CERTIFICATE-----
 MIIC+zCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQ0NFoXDTI1MTAxMDE0MzQ0NFowGDEWMBQG
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNTUxMloXDTI1MTAxNjExNTUxMlowGDEWMBQG
 A1UEAwwNcm9vdGF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBALLIFA1JvTuzPd0uD8uOxdGZmwlaRXyytqkQF66UGM+HLCmH6Vro5TpRL7Ka
-4fgEpbhS5purJqjpUiZkavxxBKQkdpxM0nH1lLX6NnR6UVh/Z3Tv6s8cR3o9L60J
-iH4N7hGdQH9Anz/PBXbshoMJqU+lZkOoqcmk4Tk27uxNlbpTLFoarm67hzqe4v/e
-xAfh4HoBZRVdnpWezM/7aX1hw2B2iFiU8pgyrVKZnXRhh4I6Ba1XTd37lc2d1fuf
-LaUICoAruR/ZhvRQaOtAN05dAHSOB9612WBBaEEiWzz/piEDEownZQ7NBWC5ANj4
-xRp7JPNtQtxYoju6j9MIJ4JoOQUCAwEAAaNQME4wHQYDVR0OBBYEFB+cb6pG1oSP
-+zeiHVit/3jbTdQXMB8GA1UdIwQYMBaAFB+cb6pG1oSP+zeiHVit/3jbTdQXMAwG
-A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAC8PKipPvbQ0TXBKCMnCZiPI
-Vs7IfZuEzOgV6VByqveXuN8WJA2+ax9+2t1xuyIgftjj/uNJgm82AceVZqAtkGF0
-n29mPyoPC2tcrPHV2QUXy26+Rfb2JTQkkHXUnRtgU+gqnqugh+r9CCjoM0XkvR26
-/OrOmy7JIHtGPq5JEH9L73UryKKdQ3HS0ZkOMfxRyMNBa0y2/hYW8QDz/m0a1U9z
-q1rLvtYXZKWhz6dJJrphF6iBDzm+r6zo+uyCU7mps5wlGB9h4Ez8nx/Af1iT0HPE
-cl5zOR0RA5qefGx0hIuaxq0mHEYDY/coJ2rptvHwcnwgtSXBaQLe6MMNP+ElYDE=
+ggEBAMDzkcftGzdNJz5vXEAZSCAO2J6bCPz896pK3qtaViR/aF8I2vHZQm0IEoJc
+Y1NUMF3F50d6fMYCkEoORAkC0d7iAwTprhBdIg35+TxwGObcStrohDtEgwFmFRzg
+LtYeXiU0t0dBWOOQ9k2f9VGqbzKwZ2dbhOHSTXMTFoEcMStbeFc++oiOLY+QSq/J
+Xd/BXqvwVM3Mt+OwLvyUu45Kw18ENo77qubIPJUwoyaf+N2nFRqcc7bmNy0Wvk2Q
+StvQXy6DpN3KOoZx/sR7Ff8hYuHXcxbSsJ1hOO+tIJyOZyEJvU2BBOYVlKr4E4JU
+mkex0CM1IfIFqfcEkbvjwLjaojsCAwEAAaNQME4wHQYDVR0OBBYEFGnP6NEr2Iaq
+KOsv/hYKwawiPGgRMB8GA1UdIwQYMBaAFGnP6NEr2IaqKOsv/hYKwawiPGgRMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJKl4RCEaXwtosNeurZlS3b9
+owXdsXDRdnfEawcc//AbRkrS4bHCQyOJNp/3DibEKkeAXCJrJ5cvXRjE5gb3Q+rl
+0AqziLY15xuMAxUK3zv0e8Zir21PQzQ9x8zbmlucEoT/jn7KvMSSqfEoer77cXev
+BpmQDQzE3FNgKohmHIzIDoTPiU3ahv6x8IhJ1e47UmRsSPFgtqglHcdCYIEclXpY
+bHvctT6+pFZuJfIs9+BATMXPJWSX7NhlMcnyP+xdDxDKuF/nwVFy6xA+njuWnnZT
+TyiGCnx+u/VpKzOrwMfzv2DW8Db80UERoox5n6QNQLnXNWPMddUL92/p9lMzWJY=
 -----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/untrusted_server_chain.pem b/tests/standalone/io/certificates/untrusted_server_chain.pem
index 132c1f4..d2b585a 100644
--- a/tests/standalone/io/certificates/untrusted_server_chain.pem
+++ b/tests/standalone/io/certificates/untrusted_server_chain.pem
@@ -1,57 +1,59 @@
 -----BEGIN CERTIFICATE-----
-MIIDPDCCAiSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
-cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDEzMTQzNDMzWhcNMjUxMDEwMTQzNDMz
+MIIDZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
+cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDE5MTE0NjA3WhcNMjUxMDE2MTE0NjA3
 WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDHQhbVk4kfjfIBK19ALltfqiF5Swiq3qx0FRnwOKyKsDsxk1PCYcON
-rFO74V62AwVSfbxBPAKOTVTDcCVlxMDq8rbFb5KAcqer+ayAl6545Bk0h2E9QPFD
-DuuGX0sHBuME54HjUC7KclyGU9MNxLe7hR8EkSbdSJD/UktWjLA/BkBpjCbKpy2D
-qgCmUEM6ViL/QjNNgNnTzkllhgK6UuwUTmqmS+7mImFA1Xd+5TU64Mlw/K4rRdXK
-36kCwpqR3+uz+QcXkto81JRTuzeviZiJe5P3ea+hYvAra3h0gRF0sX+Ypwj3svvr
-K3aoxLMy63s2e4m+qSP61jJKmUPfMfBvAgMBAAGjgYwwgYkwPAYDVR0RBDUwM4IJ
+ggEKAoIBAQC9KksWuXwx2Zh0JiU1QDj6lBZ3qJ5LNgYi/U4+yfP6KFcDw0nExUHe
+glLbdEZ3sAwthrpQaWBqA8ZvMb3My+ZSYyDhHUBaTGKxgQZylALN5Xb108OFrxLm
+xbu7YTpS1zHFaVkAGD5dhWwdP/00p0P4iVHkcefsSBltkkJRT096O0jD/cY7/Fe6
+U+ry7fCYKYpJ8x+DGf5g7mPjWW2MC9sfknUGXknHbxArzvFFIrnay2ya/0Nvoi7I
+Ch8TrkAY91mdlAiCzSFMVRulGipOqN+s5hXLd8ANDWYImH8wIxChT9YPHloAZm0P
+m/UuKW1dxfS64nub9gfUFCyxzqHxa5xTAgMBAAGjgbQwgbEwPAYDVR0RBDUwM4IJ
 bG9jYWxob3N0ggkxMjcuMC4wLjGCAzo6MYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAA
-ATAJBgNVHRMEAjAAMB0GA1UdDgQWBBSimSv95R8Wzx8/eAb1V4+4G5QZhjAfBgNV
-HSMEGDAWgBRLBvtUNk6xwJifFnkGMNsp1ereMjANBgkqhkiG9w0BAQsFAAOCAQEA
-HrxC2/kUj5GGnWcihZZgmbuo9DS1qpu6K6w+Bed0PYN0A++ov4PXWj7FGDwA4Xz4
-WKlx75eX7H5SCpwmWVX+W+uZ7h3Zmvv/e7oQBcvciMSlHayfqaa266WAF4XYpDrg
-Vaf6KRZko6ovtBUQdcjEJisvk/SO0I1PqQvTrWEkF4LJmiiAzhpr7eobpxkuEe2G
-ggFELDM6HviEsJMDIkmvCIJWwJVccSQYz+TLxIYNQIwKS2yCvNg7Vf7EtffXi51Y
-0medhTHokJDzhifAL6z30L0kQu9KjPCpxgQ3V/v3rIoyvpyfW42jT4TnzWDZqjEL
-Tl4nFwH5ckHcm2RMaPTTcQ==
+ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTSkaw7Ct7VZ6/s/WLtKkNo3vXF8zAf
+BgNVHSMEGDAWgBTicNglV5Pq//6VpIWaOwJyKKr4EjAOBgNVHQ8BAf8EBAMCA6gw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAEuIlec3o/Dr
+0kfWCSwA+ImHkaKyEVW4RALKEnaYBSWOyk9oIzS/k7ygz4QI+ay4EW9KoJMwIxAK
+fliM/lsD+Vj78imGbLeYI1OxQDznZcsUloamivhPe5MQf7jR9q4aTZ7f0n1kZulf
+8VfSexCCvKeB8DIGS4zDtu0Fs4QOJGHtnSwwBNjYmyIyXY7SsG1+Ka95ttrMV2HF
+ZB7SQ+HdPHyn3sBcPbSbqkIwC5IGiqPZS2hiPpgE4nYU1e8brL8rrlUL/INsYnFb
+slKJApx/wi/jBBKZ6C5S9a/4LDIgQeNH2KdlD40JA920w2PAKbk95At2vy1lr3kQ
+7iIgRvcraSo=
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-MIIDAzCCAeugAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQzMloXDTI1MTAxMDE0MzQzMlowIDEeMBwG
+MIIDLjCCAhagAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNDYwN1oXDTI1MTAxNjExNDYwN1owIDEeMBwG
 A1UEAwwVaW50ZXJtZWRpYXRlYXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAsOz8JUXytrHdpO4xZ1Rn2ON7JF5JeA6U8GddgV8Y4KPm9SAh
-6aHVI556z/oqCWlVnI/1aJRvPrI2rTBwcT49dkOlBcj3tzAcmSHepA5R37P1S5/p
-Wg+dPYmItmMxxW25YS4iPk1A/WQN83riRTwZhit4Asa8Gk5l3Rs5L4dleXk4vxN6
-FVL/uWMSVA3H3ELk66ieOrQLGgjIb/yPuOlzKDwzTRJ6nkG5X5lsQYPmN7t85oy6
-vuqBBdZ/s0S8qUbAIDa81pAyiBBN9gvfWQ8BJ9rJc4Tf4r3TupucJLCswLg9yT7y
-RE2FiyLsUSEg+YqhhfiCZDXO94Y4ek0fIbkajwIDAQABo1AwTjAMBgNVHRMEBTAD
-AQH/MB0GA1UdDgQWBBRLBvtUNk6xwJifFnkGMNsp1ereMjAfBgNVHSMEGDAWgBQv
-7fUg7ltvey4S1EAIQ5vX/kgEFTANBgkqhkiG9w0BAQsFAAOCAQEAIWN2IrusjYc7
-OBm2dM38h0v8QtTzQIergzeZPNIXbvNicJ+QTvRWNFxUY9B1dR4n1E8WOaUjuAuE
-BaoijJwGzZrVUlvNyGaO8v9ODe2i5hYcy2U2mMGCfdElmU9F5xw9g1iZE+7TorF8
-KkGIolhQ6r2VMDI8AU/YUAoTkPni6IL9qZZV2C/uQ5emW8rySv7VKlb+ze/JNsyo
-U4ubR6IVzza5ky/o/EhxqzbpnF8J+m5lYUqlYIs4M7KZOH0fGPebST+mYR+vV0CZ
-q93BD4B+N73Id1VQEFPofQtAw8Kh8C/MzDGZpuMs97phtN7cYhrQcqvnRaCyPT/q
-Jt202WYG+w==
+AQ8AMIIBCgKCAQEA2mNFVzURk/dREoJiWUrxNjMSOtIMCl1ep/CJqC7g4QL1aOEp
++4vJ7s+NFG6K4aafLg9UwdQ9mPLwkCkX4ETBCJDU7atD0AM7OhlGTC9q22kMDdSz
+IeT4HQ7QQntDkg4TPBz/uoUwlrDsfLUObx1VB1G/eag0wFE+1HmtwXnusT8L6xzs
+Nfbjn6NrkXIoww1F+s1Bc8AtZVlib7KSR56idhgZGo5PAIBygQT21H4W5HYlossn
+8sfj/HtHtNk+qgeqK0uIAiW3RAj1mKm7OoY/zcgTvRJPYqkRbahB5pPyPQfXlfvj
+8pBl8xBzeBNGXf2pqU8nter+2cCBT3E8MwhkOQIDAQABo3sweTASBgNVHRMBAf8E
+CDAGAQH/AgEAMB0GA1UdDgQWBBTicNglV5Pq//6VpIWaOwJyKKr4EjAfBgNVHSME
+GDAWgBQzJoFbvQyxUqLv02M/SqkjAAAk9DAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAEZg1NvkzRFh1OA5eBeP
+bgIfYRhcOJlwxBgjYa8+h6NlIrnYvJC0OCyV/2tvYkrNcJmI4AAGlchsdlPZGkP4
+gyPP/aml6f/Ys6fMggLNaT2PjO9ZozF/o9JM2H1j1/OGBa7EmMYCG4EDEzqpDrYa
+pQFjr6ULc0pvXJIHDaIWQgzqSYrvaIzO1V59zQymK0GUMFydPQreljFUHW5zi8x6
+jYvd3kgJGe0R96+ktLPF41JJwRqUJENyTqESYYd2Tu0GS7bFqEmQ0zT5aVYkr/VR
+GNhOE92EOJNymB11NWNjEfAp5nVMPsySJBIO50nlQY0igAiZZfhFz0cykrwGhuN7
+dRY=
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
 MIIC+zCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
-YXV0aG9yaXR5MB4XDTE1MTAxMzE0MzQzMloXDTI1MTAxMDE0MzQzMlowGDEWMBQG
+YXV0aG9yaXR5MB4XDTE1MTAxOTExNDYwNloXDTI1MTAxNjExNDYwNlowGDEWMBQG
 A1UEAwwNcm9vdGF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAM4Wx84AS3CwNP+Lm8YeQT3zg679qGfjrtE87qyvBipV4nPRz4ggls4nY99s
-VkoGcoZedL3E42/zR1RFQ5DZzzpf5NVYwwYtlDrhVQGb6k8zH6PK4KEou2JkV6oq
-GFy101vNAoxSeSlPetAU5MmHz/EO0alpvJZ5NKnUVTUD19U/CmTFMHL1RSsgWsPf
-UrFH58lt4v311i8vxvM3qFA7wO0Q2tptP6sf1PGSaS00W5HBFwNa8J3ewCN7opFt
-JxCbqrsG6ExG9o7gCDpY+tW2/ML24xrJfilGdhyM3H7qA6Y7ubTD/BbY+MoJxo4W
-XEEgNhMcw7uKaZngTS+DPaAP5NMCAwEAAaNQME4wHQYDVR0OBBYEFC/t9SDuW297
-LhLUQAhDm9f+SAQVMB8GA1UdIwQYMBaAFC/t9SDuW297LhLUQAhDm9f+SAQVMAwG
-A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAMpYu2n0fFULWM0dU06AH1yL
-anz1CywTTjFk0lwAmer+fexNrcc4VkWGp+XyOEZFMGRWfdixJ+F8SiOGrz83gKh+
-Z9FYJY6Ooj1y7KK8UQ78fOVUgVdPIdc3NjZFXnMz46oNXyYuOGnAyLSr8CeOQQNn
-h5TnNR82b6gun/Zu1qDPgTBfyMifdYp20GJpJMnAjx5NG/iJ/OMQCOfWfydOfLHH
-O1yxFOFfnzmeFAb9kz19bYp7UOK2C8XNyYoEuIgJo6tvlR5jIg6dT422jRSMOBtt
-55VZiS33SkH/hu1c3PoBF8QK9BPdv1QStz8k86nHMmbGk3tLmxQrYQ7SGQ6DDGo=
+ggEBAOICaW5E0IzpRZSO3RcMT7Qsj9gIBbYPkCUT9nA4YXbW+ZPPnupmgikWjfz1
+bhSm1J/32AUqg9LngXulq0CLBVUoVGgR9yPFSUuawHKvqliKwdUiGhvAh7iKE1hZ
+x7fIqhwMm8Cbn7LmK8gbzpRkTLIMyOUFVnMMwTtttfLQpXegT9HukZ2JuvqPCpAW
+aBBCZufpime3xcNyh4AEo34sNyDPfMjaiB3j5AQIehOm2phZia9DsGmKofhhNiWU
+xuQsHMubE8ODXeWEipuz3SRzwc4znIxeCiaDDBgIaRVY/7t/JdMFhI4AfktGn3fp
+AhevaZ1AnOqJ/3fDwMWrn31USHsCAwEAAaNQME4wHQYDVR0OBBYEFDMmgVu9DLFS
+ou/TYz9KqSMAACT0MB8GA1UdIwQYMBaAFDMmgVu9DLFSou/TYz9KqSMAACT0MAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJvF47StRunE0dEvD6rx9ALO
+0GRXAB7v4iyZP+PIfbIwVLY0jjMPh9jzuyzOtkPSwEUX+mtTe83o8r9Srkf7oJEQ
+GH/tfJpzJcSsOtGkw8s33I436IT7lKAr1k2V9S0/9u+k7N4Iuo9JeYj+8BSM4cpO
+i3uN98qx5IIHI7mZ77Iv1ZXN324mBzP/isppagbw2jl8VyHfy3rUNLQaMT41nNof
+pCw/z6JpQhz6WHA+GkKlJ2sAiNhLtSOBzk2wx1080eZb3GbEkDKLXCKdR/cQf9vS
+feky5cPaFQnfnfFv0b9Ygx3DopWCZ5hg5SxwxwTQv6Cy6XlIfaaFwNkrTzuhFoE=
 -----END CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/untrusted_server_key.pem b/tests/standalone/io/certificates/untrusted_server_key.pem
index a72f6c9..a432114 100644
--- a/tests/standalone/io/certificates/untrusted_server_key.pem
+++ b/tests/standalone/io/certificates/untrusted_server_key.pem
@@ -1,29 +1,29 @@
 -----BEGIN ENCRYPTED PRIVATE KEY-----
-MIIE5TAcBgoqhkiG9w0BDAEBMA4ECMRqdkj+7kZPAgIIAASCBMOpU0aPEIY0+mrz
-ZjdJkd+yrsehwoRBsnevLvs07xY1yJzyQbOpJCSN/dCkTLaee+ob8dtgs9ZJNZJ+
-e05o86J7B+zPncKNS3A97QcKy9XlTRTU0IPynxka6U65gDT4w2qDRnRohsYNgf8s
-iLD+duupiN8fimd0TnL48Qimk6VJfcZ62wPQGL2IZmcuNKG0o2wOpbg4NGviTGSl
-9Cm2mOYO3dU2MVBXZa4KUMG7ZXdG0eCzC+Vs6blYnc4TiYskQ3fILr1kKAWvzhZX
-qbaApIIVzMOosH/UUNxMh8ReJJN0CGNIlzPFtNlwKPzv0gUuwt8IpcayNPgDfycr
-Uj+hvURrRZ5Ah/WpY6dW4WnSYXH5uieufvH/G3/f96deuXsCsS4nLnDRTH2Z3GJe
-OjkzmUesFDYtOhz5KyMGb0SDsqSlVoGt3vd3bR2MjYCBl3EugzfbBTLV7rBF7Pe5
-l3rALKCAhJsf/RWXvkObgH+zfLGzW0vPpLQOR7errXYgumXABK8hKJrs1fwV4KJt
-DKgOkCqVun3diXt6CSwotJCn1RCbc4qk4rNaXbF5uRNiiAvCdashSCEPhT6JGGy8
-o4/qoTc8mYIgsT1nbH9cFb8x2e+a0W/NaaO9VSWEj1v8h9pyVqBk1q5PKl1vhCnE
-5HkkpxEs2NYtuv6c+wsf1IZiGBKdkVJArl351WKkiUFhg5asEYN9y28/UL2AmXhC
-QwPeNu/I/GGf2bFLsVSi7PvvtRT8//CfVmoKxf+SjSU6jQfB4r+1gMEJlY0XIbw8
-Mie+QR7L+NXEEqrZs+w/eEUN6sTPwkUdvULyJm8Y21Qc9hyDl7KECKSfJ/qaj7aE
-41JCHBLfv4TpCOpmG/5RxCqLcIAdX7q8li9OcaHwCGuWt1ANYaRp1t3d69t10Vtq
-uu41Bo7ZgKZC7yTbhEEEywXBRzi6OZoOxEDpMmKiVakaDRV5aim0PWo4srdyMwpm
-n75+X6mNrsRiDKHzH3/SRA8u6LHVPKSisA0fIW9qOvZSV9T93+hsYwQsH/JQX7FS
-6dBQeMn/LHMDyi8FEAeSYvsNpZ3HFH0yCMxdmlV+WNJRGNuYe/DXqYtHnW8hmrXQ
-73jsfh1M72rNY4kLpuskuxzQ0fN0x8No6IYHReY7bA/YuTlwkPQZso0zqfSwCvaQ
-Vx0bf7ZKEAOAEJQwQDzCPK27CNHt5DqTXD2P1LZmA3S+XunrtgkPCcpeUwng0xXV
-cujmb5ND+kkA94F+jAXNOtMBCSDcYNOCXwNJ2vr4cOWsC31c/LgoUl+8oDbwIi5e
-s8HKhmUKNbo6wE9oN07zqPqP68Afy2LmwjxUt7ODF8gAAo+RbudrVrUm7IgiE2uo
-Cy3u9rbx9kJlTKvrMEgc+51+Oz9ZeUUG6I8mMltX6CpWqdpz2w8hrf9w8nIIK6ba
-iUJnrlaIJdqjAue0X9YFr+QDpF5Pua65vromGwleHmSHU4YhR780JlYxMpikg+i+
-uaPDuZOEwNlb+vlwk2m4pARYDlx7TQRZGdFcWevaco3dWQ2Uo1UPT5Wh4ZDXHNDs
-lUn/aqNAIuOgeT9hJZcPgj+K0cAH8g42VW1Ewl87HPyM+MfB/RGkRUOncVvc9Gms
-ipieyen0TlrX
+MIIE4jAcBgoqhkiG9w0BDAEBMA4ECM5Q9vG4KGZGAgIIAASCBMBiQm5+L2fG6oTd
+F4NPWJQj2ud4FjIp98E0HHmqZZjWxkTJHdHjPvHNGIrAYpyM54Hj1Av6RsOCtyEk
+/XfmlXuf6MzoY54rYSrFKxSssrRvPu6PT5BpWB0ErEs/gksRXRMXDVCVv14rvIAl
+f37j/aqaUYNQSsy7n5t/7PZ6w4icVIPYFZlKcIzYM0M6yy/vN3EarInQtgIc0U5/
+m8/87oyH83AzxtVH07Y6iYOEdTqmNFgGLnLmRaGnG6bsa/O8u8FKtP+9D468qxPD
+Te58rrkicvHPNNtKSvi1acN7jtHQ1+0asQwny/ElYrrfUr1K6ypfGWUmIL0LBxYK
+5QLYWqQTmUlisirGDmKJ29H0PyF3enUpOyKBFTzrqfGrIPLpmbHN29DlmliOcRjU
+ftbPFVH8n2dLf9Xtnhgzk9H1JoL228aYdd2nO3Lb8Kn4DV2iRS6y/4RXTbSdlRBf
+eB6FT1WgcU1Rtl+2ekxncVBrTV/akM7S/Y6XtpzwUpi41JXpUtV3aRltYH7HLXQR
+qZKfkUcma+WiBwgjjiBs9be0h2Ow6n4SX++I9xgEhGEkq8ob/HQTiIC2frH/EqVN
+/zl20GgQWmkresmJxKaesNYocsqr7cvq2yx8PbItXW6nugtm1U29YyQSEtXypIXl
+VY4PcccfaKH1iF1ia5sF7yhHQEeuG6c1WBJCXog2t1Nrru2Df3AVMgqcltTGo+K3
+6R/7BveklhFcQkAjn3HUEy8/mlq9nrblWT9YfcP7gqR4szCAZoALGXG7DYVyrheg
+yZwSraFunzlBbfVvMAhtEPakNNT9tadhEZObkQfCB1g7UeXtgZ1u7v8wtq+5xKHe
+RtECM9Jitk5Tn9HPvumdkzuM9zyagJs90WxsAUxInzB6zCWaBduiZIjEK/WZRocY
+0lK9yDEEnwZ/8uiif9Y52fvdI6cHBy041VYvXSxal08ToEye3NBbXTwhMbI6hbfp
+1drJcb0ARYIFzX16cy85YF64iwPqSBt5cQBPhwF1sDcjBPeYFeZ43qNw4KnO1M2w
+jGCmFvFcapwGhuJfFQMt9gEX3jx/8460/GUxTYm/gLvXL4Ae8OkWLRW6TMvDNw39
+esRdO/gQcfj2P5YZuBjptU0B//a9f7OaJNyyr39Hj3l5TgkDv5iV5HLZYXkn6nMT
+SiKMtYDq4qKyqeMcGVACCm0/Z1xUtPQsBYoL7+1v+ewyZpqNs9XYZJGSDpUddBzD
+EHEqUEIIUslV2fRFDnfIKDovjIfaaox3g1cpoZLzFmzQ/GYo2bFp6zMFTvqlWFTN
+RTElsHnKbX/0nlQHMNGmEwbowuPerDd1LehexSWm8GWutWCUH5SfE1k0F8UTnqwF
+AvySfhx28xY24neoj5OfM4O6j2mY9d392NrUo5xXhIWfFkXi97uFpkVvx2N7EfGF
+pjZRbnQUmf/HZ3p2N7EUnUV9q+AKume2EeFwTBS6fZdrhHvD4aYkbm41tBoNoS75
+DKpQJ7OTIdgy2uOrY4xSnKOJGuh+iJysQe5axeKKEEIr84VF23SpfqTiNFDDFec0
+749mgVHS/+tCw6UsgS/3vS+3AqMW8DgNKYkhcaDQVFYbVJLmlLGYmLZfkKBbUzy3
+Vv6uVhro
 -----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/standalone/io/create_sample_certificates.sh b/tests/standalone/io/create_sample_certificates.sh
index c9baee7..eaa62f0 100755
--- a/tests/standalone/io/create_sample_certificates.sh
+++ b/tests/standalone/io/create_sample_certificates.sh
@@ -36,26 +36,61 @@
 openssl x509 -req -in intermediate_authority_request.pem \
     -out intermediate_authority.pem -set_serial 1 \
     -CA root_authority.pem -CAkey root_authority_key.pem \
-    -passin $password -extfile ../intermediate_authority_v3_extensions \
-    -days 3650
+    -passin $password -extfile ../sample_certificate_v3_extensions \
+    -extensions intermediate_authority -days 3650
 
 # Create a certificate request for the server certificate
 openssl req -subj /CN=localhost -batch -verbose -passout $password -new \
     -keyout localhost_key.pem -out localhost_request.pem
 
-# Sign the server certificate  with the intermediate authority.  Add the
+# Sign the server certificate with the intermediate authority.  Add the
 # certificate extensions for SubjectAltName and that it is not a CA itself.
 openssl x509 -req -in localhost_request.pem -out localhost.pem -set_serial 1 \
     -CA intermediate_authority.pem -CAkey intermediate_authority_key.pem \
-    -passin $password -extfile ../localhost_v3_extensions -days 3650
+    -passin $password -extfile ../sample_certificate_v3_extensions \
+    -extensions localhost -days 3650
 
+# Create a self-signed client certificate authority.
+openssl req -subj /CN=clientauthority -set_serial 1 -batch -verbose \
+    -passout $password -new -x509 -keyout client_authority_key.pem \
+    -out client_authority.pem -config ../sample_certificate_v3_extensions \
+    -extensions client_authority -days 3650
+
+# Create certificate requests for the client certificates
+openssl req -subj /CN=user1 -batch -verbose -passout $password -new \
+    -keyout client1_key.pem -out client1_request.pem
+openssl req -subj /CN=user2 -batch -verbose -passout $password -new \
+    -keyout client2_key.pem -out client2_request.pem
+
+# Sign the certificate requests with the client authority
+openssl x509 -req -in client1_request.pem -out client1.pem -set_serial 1 \
+    -CA client_authority.pem -CAkey client_authority_key.pem \
+    -passin $password -extfile ../sample_certificate_v3_extensions \
+    -extensions client_certificate -days 3650
+openssl x509 -req -in client2_request.pem -out client2.pem -set_serial 1 \
+    -CA client_authority.pem -CAkey client_authority_key.pem \
+    -passin $password -extfile ../sample_certificate_v3_extensions \
+    -extensions client_certificate -days 3650
+
+# Copy the certificates we will use to the 'certificates' directory.
+CERTS=../certificates
 cat localhost.pem intermediate_authority.pem root_authority.pem \
-    > ../certificates/server_chain.pem
+    > $CERTS/server_chain.pem
+
+cat intermediate_authority.pem root_authority.pem client_authority.pem \
+    > $CERTS/server_trusted.pem
 
 # BoringSSL only accepts private keys signed with the PBE-SHA1-RC4-128 cipher.
-openssl pkcs8 -in localhost_key.pem -out ../certificates/server_key.pem \
+openssl pkcs8 -in localhost_key.pem -out $CERTS/server_key.pem \
+    -topk8 -v1 PBE-SHA1-RC4-128 -passin $password -passout $password
+openssl pkcs8 -in client1_key.pem -out $CERTS/client1_key.pem \
+    -topk8 -v1 PBE-SHA1-RC4-128 -passin $password -passout $password
+openssl pkcs8 -in client2_key.pem -out $CERTS/client2_key.pem \
     -topk8 -v1 PBE-SHA1-RC4-128 -passin $password -passout $password
 
-cp root_authority.pem ../certificates/trusted_certs.pem
+cp root_authority.pem $CERTS/trusted_certs.pem
+cp client_authority.pem $CERTS
+cp client1.pem $CERTS
+cp client2.pem $CERTS
 
 cd ..
diff --git a/tests/standalone/io/intermediate_authority_v3_extensions b/tests/standalone/io/intermediate_authority_v3_extensions
deleted file mode 100644
index 8d0f70c..0000000
--- a/tests/standalone/io/intermediate_authority_v3_extensions
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# OpenSSL configuration file giving the v3 extensions for an intermediate
-# certificate authority.
-
-basicConstraints = CA:true
-subjectKeyIdentifier=hash
-authorityKeyIdentifier=keyid:always,issuer
-
diff --git a/tests/standalone/io/localhost_v3_extensions b/tests/standalone/io/localhost_v3_extensions
deleted file mode 100644
index 99cc4d1..0000000
--- a/tests/standalone/io/localhost_v3_extensions
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# OpenSSL configuration file giving the v3 extensions for the localhost
-# server certificate
-subjectAltName = @alt_names
-basicConstraints = CA:false
-subjectKeyIdentifier=hash
-authorityKeyIdentifier=keyid,issuer
-
-[alt_names]
-DNS.1 = localhost
-DNS.2 = 127.0.0.1
-DNS.3 = ::1
-IP.1 = 127.0.0.1
-IP.2 = ::1
-
diff --git a/tests/standalone/io/sample_certificate_v3_extensions b/tests/standalone/io/sample_certificate_v3_extensions
new file mode 100644
index 0000000..f9e741e
--- /dev/null
+++ b/tests/standalone/io/sample_certificate_v3_extensions
@@ -0,0 +1,46 @@
+# Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# OpenSSL configuration file giving the v3 extensions for the sample
+# certificates created by create_sample_certificates.sh
+
+default_bits = 2048
+distinguished_name = name_section
+[name_section]
+CN = foo
+
+[localhost]
+subjectAltName = @alt_names
+basicConstraints = critical,CA:false
+subjectKeyIdentifier = hash
+authorityKeyIdentifier=keyid,issuer
+keyUsage=critical, digitalSignature, keyEncipherment, keyAgreement
+extendedKeyUsage=serverAuth
+
+[alt_names]
+DNS.1 = localhost
+DNS.2 = 127.0.0.1
+DNS.3 = ::1
+IP.1 = 127.0.0.1
+IP.2 = ::1
+
+[intermediate_authority]
+basicConstraints = critical, CA:true, pathlen:0
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always, issuer
+keyUsage=critical, keyCertSign
+extendedKeyUsage=serverAuth
+
+[client_authority]
+basicConstraints = critical,CA:true,pathlen:0
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always, issuer
+keyUsage=critical, keyCertSign
+extendedKeyUsage=clientAuth
+
+[client_certificate]
+basicConstraints = CA:false
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always, issuer
+extendedKeyUsage=clientAuth
diff --git a/tests/standalone/io/secure_server_client_certificate_test.dart b/tests/standalone/io/secure_server_client_certificate_test.dart
index 3f34d93..81f0995 100644
--- a/tests/standalone/io/secure_server_client_certificate_test.dart
+++ b/tests/standalone/io/secure_server_client_certificate_test.dart
@@ -15,75 +15,62 @@
 SecurityContext serverContext = new SecurityContext()
   ..useCertificateChain(localFile('certificates/server_chain.pem'))
   ..usePrivateKey(localFile('certificates/server_key.pem'),
-                  password: 'dartdart');
+      password: 'dartdart')
+  ..setTrustedCertificates(file: localFile('certificates/client_authority.pem'))
+  ..setClientAuthorities(localFile('certificates/client_authority.pem'));
 
-SecurityContext clientContext = new SecurityContext()
+SecurityContext clientCertContext = new SecurityContext()
+  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'))
+  ..useCertificateChain(localFile('certificates/client1.pem'))
+  ..usePrivateKey(localFile('certificates/client1_key.pem'),
+      password: 'dartdart');
+
+SecurityContext clientNoCertContext = new SecurityContext()
   ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
 
-Future testClientCertificate() {
-  var completer = new Completer();
-  SecureServerSocket.bind(HOST,
-                          0,
-                          serverContext,
-                          requestClientCertificate: true).then((server) {
-    var clientEndFuture = SecureSocket.connect(HOST,
-                                               server.port,
-                                               context: clientContext,
-                                               sendClientCertificate: true);
-    server.listen((serverEnd) {
-      X509Certificate certificate = serverEnd.peerCertificate;
-      Expect.isNotNull(certificate);
-      Expect.equals("CN=localhost", certificate.subject);
-      Expect.equals("CN=myauthority", certificate.issuer);
-      clientEndFuture.then((clientEnd) {
-        X509Certificate certificate = clientEnd.peerCertificate;
-        Expect.isNotNull(certificate);
-        Expect.equals("CN=localhost", certificate.subject);
-        Expect.equals("CN=myauthority", certificate.issuer);
-        clientEnd.close();
-        serverEnd.close();
-        server.close();
-        completer.complete();
-      });
-    });
-  });
-  return completer.future;
+Future testClientCertificate({bool required, bool sendCert}) async {
+  var server = await SecureServerSocket.bind(HOST, 0, serverContext,
+      requestClientCertificate: true, requireClientCertificate: required);
+  var clientContext = sendCert ? clientCertContext : clientNoCertContext;
+  var clientEndFuture = SecureSocket.connect(HOST, server.port,
+      context: clientContext, sendClientCertificate: true);
+  if (required && !sendCert) {
+    try {
+      await server.first;
+    } catch (e) {
+      try {
+        await clientEndFuture;
+      } catch (e) {
+        return;
+      }
+    }
+    Expect.fail("Connection succeeded with no required client certificate");
+  }
+  var serverEnd = await server.first;
+  var clientEnd = await clientEndFuture;
+
+  X509Certificate clientCertificate = serverEnd.peerCertificate;
+  if (sendCert) {
+    Expect.isNotNull(clientCertificate);
+    Expect.equals("/CN=user1", clientCertificate.subject);
+    Expect.equals("/CN=clientauthority", clientCertificate.issuer);
+  } else {
+    Expect.isNull(clientCertificate);
+  }
+  X509Certificate serverCertificate = clientEnd.peerCertificate;
+  Expect.isNotNull(serverCertificate);
+  Expect.equals("/CN=localhost", serverCertificate.subject);
+  Expect.equals("/CN=intermediateauthority", serverCertificate.issuer);
+  clientEnd.close();
+  serverEnd.close();
 }
 
-Future testRequiredClientCertificate() {
-  var completer = new Completer();
-  SecureServerSocket.bind(HOST,
-                          0,
-                          serverContext,
-                          requireClientCertificate: true).then((server) {
-    var clientEndFuture = SecureSocket.connect(HOST,
-                                               server.port,
-                                               context: clientContext,
-                                               sendClientCertificate: true);
-    server.listen((serverEnd) {
-      X509Certificate certificate = serverEnd.peerCertificate;
-      Expect.isNotNull(certificate);
-      Expect.equals("CN=localhost", certificate.subject);
-      Expect.equals("CN=myauthority", certificate.issuer);
-      clientEndFuture.then((clientEnd) {
-        X509Certificate certificate = clientEnd.peerCertificate;
-        Expect.isNotNull(certificate);
-        Expect.equals("CN=localhost", certificate.subject);
-        Expect.equals("CN=myauthority", certificate.issuer);
-        clientEnd.close();
-        serverEnd.close();
-        server.close();
-        completer.complete();
-      });
-    });
-  });
-  return completer.future;
-}
-
-void main() {
+main() async {
   asyncStart();
-  InternetAddress.lookup("localhost").then((hosts) => HOST = hosts.first)
-    .then((_) => testClientCertificate())
-    .then((_) => testRequiredClientCertificate())
-    .then((_) => asyncEnd());
+  HOST = (await InternetAddress.lookup("localhost")).first;
+  await testClientCertificate(required: false, sendCert: true);
+  await testClientCertificate(required: true, sendCert: true);
+  await testClientCertificate(required: false, sendCert: false);
+  await testClientCertificate(required: true, sendCert: false);
+  asyncEnd();
 }
diff --git a/tests/standalone/io/secure_server_client_no_certificate_test.dart b/tests/standalone/io/secure_server_client_no_certificate_test.dart
deleted file mode 100644
index 97a422b..0000000
--- a/tests/standalone/io/secure_server_client_no_certificate_test.dart
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:async";
-import "dart:io";
-
-import "package:async_helper/async_helper.dart";
-import "package:expect/expect.dart";
-
-InternetAddress HOST;
-String localFile(path) => Platform.script.resolve(path).toFilePath();
-
-SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChain(localFile('certificates/server_chain.pem'))
-  ..usePrivateKey(localFile('certificates/server_key.pem'),
-                  password: 'dartdart');
-
-SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
-
-Future testNoClientCertificate() {
-  var completer = new Completer();
-  SecureServerSocket.bind(HOST,
-                          0,
-                          serverContext,
-                          requestClientCertificate: true).then((server) {
-    var clientEndFuture = SecureSocket.connect(HOST,
-                                               server.port,
-                                               context: clientContext);
-    server.listen((serverEnd) {
-      X509Certificate certificate = serverEnd.peerCertificate;
-      Expect.isNull(certificate);
-      clientEndFuture.then((clientEnd) {
-        clientEnd.close();
-        serverEnd.close();
-        server.close();
-        completer.complete();
-      });
-    });
-  });
-  return completer.future;
-}
-
-Future testNoRequiredClientCertificate() {
-  var completer = new Completer();
-  bool clientError = false;
-  SecureServerSocket.bind(HOST,
-                          0,
-                          serverContext,
-                          requireClientCertificate: true).then((server) {
-    Future clientDone =
-        SecureSocket.connect(HOST, server.port, context: clientContext)
-        .catchError((e) { clientError = true; });
-    server.listen((serverEnd) {
-      Expect.fail("Got a unverifiable connection");
-    },
-    onError: (e) {
-      clientDone.then((_) {
-        Expect.isTrue(clientError);
-        server.close();
-        completer.complete();
-      });
-    });
-  });
-  return completer.future;
-}
-
-void main() {
-  asyncStart();
-  InternetAddress.lookup("localhost").then((hosts) => HOST = hosts.first)
-    .then((_) => testNoRequiredClientCertificate())
-    .then((_) => testNoClientCertificate())
-    .then((_) => asyncEnd());
-}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 125523a..2831a9c 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -206,8 +206,6 @@
 [ $runtime == vm ]
 # Failures in secure networking while NSS is replaced with BoringSSL
 io/https_client_certificate_test: RuntimeError # Issue 24070
-io/secure_server_client_certificate_test: RuntimeError # Issue 24069
-io/secure_server_client_no_certificate_test: RuntimeError # Issue 24069
 io/secure_socket_renegotiate_test: RuntimeError
 io/secure_socket_bad_data_test: RuntimeError  # An error in a secure connection just puts a READ_CLOSED on the stream, rather than signaling an error on the stream.
 
diff --git a/tools/VERSION b/tools/VERSION
index fb4794f..f633fa3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
 MINOR 13
 PATCH 0
 PRERELEASE 7
-PRERELEASE_PATCH 1
+PRERELEASE_PATCH 2
diff --git a/tools/dom/src/dartium_CustomElementSupport.dart b/tools/dom/src/dartium_CustomElementSupport.dart
index 85ff4d6..aec7b4a 100644
--- a/tools/dom/src/dartium_CustomElementSupport.dart
+++ b/tools/dom/src/dartium_CustomElementSupport.dart
@@ -8,9 +8,11 @@
 class _VMElementUpgrader implements ElementUpgrader {
   final Type _type;
   final Type _nativeType;
+  final String _extendsTag;
 
   _VMElementUpgrader(Document document, Type type, String extendsTag) :
       _type = type,
+      _extendsTag = extendsTag,
       _nativeType = _validateCustomType(type).reflectedType {
 
     if (extendsTag == null) {
@@ -28,20 +30,39 @@
 
   Element upgrade(element) {
     var jsObject;
-    var tag = _getCustomElementName(element);
+    var tag;
+    var isNativeElementExtension = false;
+
+    try {
+      tag = _getCustomElementName(element);
+    } catch (e) {
+      isNativeElementExtension = element.localName == _extendsTag;
+    }
+
     if (element.runtimeType == HtmlElement || element.runtimeType == TemplateElement) {
+      if (tag != _extendsTag) {
+        throw new UnsupportedError('$tag is not registered.');
+      }
       jsObject = unwrap_jso(element);
     } else if (element.runtimeType == js.JsObjectImpl) {
       // It's a Polymer core element (written in JS).
       jsObject = element;
-    } else {
+    } else if (isNativeElementExtension) {
+      // Extending a native element.
+      jsObject = element.blink_jsObject;
+
+      // Element to extend is the real tag.
+      tag = element.localName;
+    } else if (tag != null && element.localName != tag) {
+      throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
+    } else if (tag == null) {
       throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
     }
 
     // Remember Dart class to tagName for any upgrading done in wrap_jso.
-    _addCustomElementType(tag, _type);
+    addCustomElementType(tag, _type, _extendsTag);
 
-    return createCustomUpgrader(_nativeType, jsObject);
+    return _createCustomUpgrader(_type, jsObject);
   }
 }
 
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index 22158c9..4dc5fc9 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -352,32 +352,14 @@
  **********                                                          **********
  ******************************************************************************/
 
-// List of known tagName to DartClass for custom elements, used for upgrade.
-var _knownCustomElements = new Map<String, Map<Type, String>>();
-
-void _addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
-  _knownCustomElements[tagName] = 
-      {'type': dartClass, 'extends': extendTag != null ? extendTag : "" };
-}
-
-Type _getCustomElementType(object) {
-  var entry = _knownCustomElements[_getCustomElementName(object)];
-  if (entry != null) {
-    return entry['type'];
-  }
-  return null;
-}
-
 String _getCustomElementExtends(object) {
-  var entry = _knownCustomElements[_getCustomElementName(object)];
+  var entry = getCustomElementEntry(object);
   if (entry != null) {
     return entry['extends'];
   }
   return null;
 }
 
-_getCustomElement(object) => _knownCustomElements[_getCustomElementName(object)];
-
 // Return the tag name or is attribute of the custom element or data binding.
 String _getCustomElementName(element) {
   var jsObject;
@@ -407,13 +389,6 @@
   return tag;
 }
 
-Rectangle make_dart_rectangle(r) =>
-    r == null ? null : new Rectangle(
-    js.JsNative.getProperty(r, 'left'),
-    js.JsNative.getProperty(r, 'top'),
-    js.JsNative.getProperty(r, 'width'),
-    js.JsNative.getProperty(r, 'height'));
-
 /// An abstract class for all DOM objects we wrap in dart:html and related
 ///  libraries.
 class DartHtmlDomObject {
@@ -423,247 +398,14 @@
 
 }
 
-// Flag to disable JS interop asserts.  Setting to false will speed up the
-// wrap_jso calls.
-bool __interop_checks = true;
-
-/** Expando for JsObject, used by every Dart class associated with a Javascript
- *  class (e.g., DOM, WebAudio, etc.).
- */
-
-/**
- * Return the JsObject associated with a Dart class [dartClass_instance].
- */
-unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
-
-/**
- * Create Dart class that maps to the JS Type, add the JsObject as an expando
- * on the Dart class and return the created Dart class.
- */
-wrap_jso(jsObject) {
-  try {
-    if (jsObject is! js.JsObject || jsObject == null) {
-      // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
-      // or it's a simple type.
-      return jsObject;
-    }
-
-    var wrapper = js.getDartHtmlWrapperFor(jsObject);
-    // if we have a wrapper return the Dart instance.
-    if (wrapper != null) {
-      if (wrapper.runtimeType == HtmlElement && !wrapper._isBadUpgrade) {
-        // We're a Dart instance but we need to upgrade.
-        var customElementClass = _getCustomElementType(wrapper);
-        if (customElementClass != null) {
-          var dartClass_instance;
-          try {
-            dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
-          } finally {
-            dartClass_instance.blink_jsObject = jsObject;
-            jsObject['dart_class'] = dartClass_instance;
-            js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
-            return dartClass_instance;
-          }
-        }
-      }
-
-      return wrapper;
-    }
-
-    if (jsObject is js.JsArray) {
-      var wrappingList = new _DartHtmlWrappingList(jsObject);
-      js.setDartHtmlWrapperFor(jsObject, wrappingList);
-      return wrappingList;
-    }
-
-    // Try the most general type conversions on it.
-    // TODO(alanknight): We may be able to do better. This maintains identity,
-    // which is useful, but expensive. And if we nest something that only
-    // this conversion handles, how does that work? e.g. a list of maps of elements.
-    var converted = convertNativeToDart_SerializedScriptValue(jsObject);
-    if (!identical(converted, jsObject)) {
-      return converted;
-    }
-
-    var constructor = js.JsNative.getProperty(jsObject, 'constructor');
-    if (constructor == null) {
-      // Perfectly valid case for JavaScript objects where __proto__ has
-      // intentionally been set to null.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
-    }
-    var jsTypeName = js.JsNative.getProperty(constructor, 'name');
-    if (jsTypeName is! String || jsTypeName.length == 0) {
-      // Not an html type.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
-    }
-
-    var dartClass_instance;
-    if (jsObject.hasProperty('dart_class')) {
-      // Got a dart_class (it's a custom element) use it it's already set up
-      // make sure it's upgraded.
-      dartClass_instance = _upgradeHtmlElement(jsObject['dart_class']);
-    } else {
-      var customElementClass = null;
-      var extendsTag = "";
-      var custom = _getCustomElement(jsObject);
-      if (custom != null) {
-        customElementClass = custom['type'];
-        extendsTag = custom['extends'];
-      }
-      // Custom Element to upgrade.
-      if (jsTypeName == 'HTMLElement' && customElementClass != null && extendsTag == "") {
-        try {
-          dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
-        } finally {
-          dartClass_instance.blink_jsObject = jsObject;
-          jsObject['dart_class'] = dartClass_instance;
-          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
-       }
-      } else {
-        // TODO(terry): Verify with jakemacd that this is right?
-        // If we every get an auto-binding we're matching previous non-JS Interop
-        // did to return a TemplateElement.
-        if (jsTypeName == 'auto-binding') {
-          jsTypeName = "HTMLTemplateElement";
-        }
-
-        var func = getHtmlCreateFunction(jsTypeName);
-        if (func == null) {
-          // One last ditch effort could be a JS custom element.
-          if (jsObject.toString() == "[object HTMLElement]") {
-            func = getHtmlCreateFunction("HTMLElement");
-          }
-        }
-        if (func != null) {
-          dartClass_instance = func();
-          dartClass_instance.blink_jsObject = jsObject;
-          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
-        }
-      }
-    }
-    // TODO(jacobr): cache that this is not a dart:html JS class.
-    return dartClass_instance;
-  } catch(e, stacktrace){
-    if (__interop_checks) {
-      if (e is DebugAssertException)
-        window.console.log("${e.message}\n ${stacktrace}");
-      else
-        window.console.log("${stacktrace}");
-    }
-  }
-
-  return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type, add the JsObject as an expando
- * on the Dart class and return the created Dart class.
- */
-wrap_jso_no_SerializedScriptvalue(jsObject) {
-  try {
-    if (jsObject is! js.JsObject || jsObject == null) {
-      // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
-      // or it's a simple type.
-      return jsObject;
-    }
-
-    // TODO(alanknight): With upgraded custom elements this causes a failure because
-    // we need a new wrapper after the type changes. We could possibly invalidate this
-    // if the constructor name didn't match?
-    var wrapper = js.getDartHtmlWrapperFor(jsObject);
-    if (wrapper != null) {
-      return wrapper;
-    }
-
-    if (jsObject is js.JsArray) {
-      var wrappingList = new _DartHtmlWrappingList(jsObject);
-      js.setDartHtmlWrapperFor(jsObject, wrappingList);
-      return wrappingList;
-    }
-
-    var constructor = js.JsNative.getProperty(jsObject, 'constructor');
-    if (constructor == null) {
-      // Perfectly valid case for JavaScript objects where __proto__ has
-      // intentionally been set to null.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
-    }
-    var jsTypeName = js.JsNative.getProperty(constructor, 'name');
-    if (jsTypeName is! String || jsTypeName.length == 0) {
-      // Not an html type.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
-    }
-
-    var func = getHtmlCreateFunction(jsTypeName);
-    if (func != null) {
-      var dartClass_instance = func();
-      dartClass_instance.blink_jsObject = jsObject;
-      js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
-      return dartClass_instance;
-    }
-    return jsObject;
-  } catch(e, stacktrace){
-    if (__interop_checks) {
-      if (e is DebugAssertException)
-        window.console.log("${e.message}\n ${stacktrace}");
-      else
-        window.console.log("${stacktrace}");
-    }
-  }
-
-  return null;
-}
-
-/**
- * Create Dart class that maps to the JS Type that is the JS type being
- * extended using JS interop createCallback (we need the base type of the
- * custom element) not the Dart created constructor.
- */
-wrap_jso_custom_element(jsObject) {
-  try {
-    if (jsObject is! js.JsObject) {
-      // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
-      return jsObject;
-    }
-
-    // Find out what object we're extending.
-    var objectName = jsObject.toString();
-    // Expect to see something like '[object HTMLElement]'.
-    if (!objectName.startsWith('[object ')) {
-      return jsObject;
-    }
-
-    var extendsClass = objectName.substring(8, objectName.length - 1);
-    var func = getHtmlCreateFunction(extendsClass);
-    if (__interop_checks)
-      debug_or_assert("func != null name = ${extendsClass}", func != null);
-    var dartClass_instance = func();
-    dartClass_instance.blink_jsObject = jsObject;
-    return dartClass_instance;
-  } catch(e, stacktrace){
-    if (__interop_checks) {
-      if (e is DebugAssertException)
-        window.console.log("${e.message}\n ${stacktrace}");
-      else
-        window.console.log("${stacktrace}");
-    }
-
-    // Problem?
-    return null;
-  }
-}
-
-// Upgrade a Dart HtmlElement to the user's Dart custom element class.
+/// Upgrade a Dart HtmlElement to the user's Dart custom element class.
 _upgradeHtmlElement(dartInstance) {
   // Only try upgrading HtmlElement (Dart class) if there is a failure then
   // don't try it again - one failure is enough.
-  if (dartInstance.runtimeType == HtmlElement && !dartInstance._isBadUpgrade) {
+  if (dartInstance.runtimeType == HtmlElement && !dartInstance.isBadUpgrade) {
     // Must be exactly HtmlElement not something derived from it.
 
-    var customElementClass = _getCustomElementType(dartInstance);
+    var customElementClass = getCustomElementType(dartInstance);
 
     // Custom Element to upgrade.
     if (customElementClass != null) {
@@ -674,7 +416,6 @@
         dartInstance._badUpgrade();
       } finally {
         dartInstance.blink_jsObject = jsObject;
-        jsObject['dart_class'] = dartInstance;
         js.setDartHtmlWrapperFor(jsObject, dartInstance);
      }
    }
@@ -720,53 +461,10 @@
   return result;
 }
 
-// Converts a flat Dart map into a JavaScript object with properties this is
-// is the Dartium only version it uses dart:js.
-// TODO(alanknight): This could probably be unified with the dart2js conversions
-// code in html_common and be more general.
-convertDartToNative_Dictionary(Map dict) {
-  if (dict == null) return null;
-  var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object'));
-  dict.forEach((String key, value) {
-    if (value is List) {
-      var jsArray = new js.JsArray();
-      value.forEach((elem) {
-        jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
-      });
-      jsObject[key] = jsArray;
-    } else {
-      jsObject[key] = value;
-    }
-  });
-  return jsObject;
-}
-
-// Converts a Dart list into a JsArray. For the Dartium version only.
-convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
-
-// Conversion function place holder (currently not used in dart2js or dartium).
-List convertDartToNative_StringArray(List<String> input) => input;
-
-/**
- * Wraps a JsArray and will call wrap_jso on its entries.
- */
-class _DartHtmlWrappingList extends ListBase implements NativeFieldWrapperClass2 {
-  _DartHtmlWrappingList(this.blink_jsObject);
-
-  final js.JsArray blink_jsObject;
-
-  operator [](int index) => wrap_jso(js.JsNative.getArrayIndex(blink_jsObject, index));
-
-  operator []=(int index, value) => blink_jsObject[index] = value;
-
-  int get length => blink_jsObject.length;
-  int set length(int newLength) => blink_jsObject.length = newLength;
-}
-
 /**
  * Upgrade the JS HTMLElement to the Dart class.  Used by Dart's Polymer.
  */
-createCustomUpgrader(Type customElementClass, $this) {
+_createCustomUpgrader(Type customElementClass, $this) {
   var dartClass;
   try {
     dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
@@ -786,12 +484,6 @@
 $else
 class DartHtmlDomObject extends NativeFieldWrapperClass2 {}
 
-unwrap_jso(dartClass_instance) => dartClass_instance;
-wrap_jso(jsObject) => jsObject;
-make_dart_rectangle(r) => r;
-convertDartToNative_Dictionary(Map dict) => dict;
-List convertDartToNative_StringArray(List<String> input) => input;
-convertDartToNative_List(List input) => input;
-createCustomUpgrader(Type customElementClass, $this) => $this;
+_createCustomUpgrader(Type customElementClass, $this) => $this;
 
 $endif
diff --git a/tools/dom/templates/html/impl/impl_CustomEvent.darttemplate b/tools/dom/templates/html/impl/impl_CustomEvent.darttemplate
index c4de5c6..e16b74a 100644
--- a/tools/dom/templates/html/impl/impl_CustomEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CustomEvent.darttemplate
@@ -36,7 +36,7 @@
 
 $if DARTIUM
     // Need for identity.
-    e.blink_jsObject['dart_class'] = e;
+    js.setDartHtmlWrapperFor(e.blink_jsObject, e);
 
 $endif
     return e;
diff --git a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
index 3c6e3a4..1df549e 100644
--- a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
@@ -223,12 +223,28 @@
     return isElement ? jsClassName : null;
   }
 
+  // Get the first class that's a super of a dart.dom library.
+  ClassMirror _getDartHtmlClassName(ClassMirror classMirror) {
+    while (classMirror.superclass != null) {
+      var fullName = classMirror.superclass.qualifiedName;
+      var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
+      if (domLibrary) {
+        return classMirror.superclass;
+      }
+
+      classMirror = classMirror.superclass;
+    }
+
+    return null;
+  }
+
   /**
    * Get the class that immediately derived from a class in dart:html or
    * dart:svg (has an attribute DomName of either HTML* or SVG*).
    */
   ClassMirror _getDomSuperClass(ClassMirror classMirror) {
     var isElement = false;
+    var foundSuperElement = null;
 
     while (classMirror.superclass != null) {
       var fullName = classMirror.superclass.qualifiedName;
@@ -236,6 +252,9 @@
 
       var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
       if (domLibrary) {
+        if (foundSuperElement == null) {
+          foundSuperElement = classMirror.superclass;
+        }
         // Lookup JS class (if not found).
         var metadatas = classMirror.metadata;
         for (var metadata in metadatas) {
@@ -243,7 +262,7 @@
           var metaType = reflectClass(metaDataMirror.runtimeType);
           if (MirrorSystem.getName(metaType.simpleName) == 'DomName' &&
               (metaDataMirror.name.startsWith('HTML') || metaDataMirror.name.startsWith('SVG'))) {
-            if (isElement) return classMirror;
+            if (isElement) return foundSuperElement;
           }
         }
       }
@@ -369,6 +388,25 @@
       throw new DomException.jsInterop("HierarchyRequestError: Only HTML elements can be customized.");
     }
 
+    var customClassType = _getDartHtmlClassName(classMirror);
+
+    if (extendsTag != null) {
+      var nativeElement = document.createElement(extendsTag);
+
+      // Trying to extend a native element is it the Dart class consistent with the
+      // extendsTag?
+      if (nativeElement.runtimeType != customClassType.reflectedType) {
+        var nativeElementClassMirror = reflectClass(nativeElement.runtimeType);
+        var customClassNativeElement = MirrorSystem.getName(customClassType.simpleName);
+        var extendsNativeElement = MirrorSystem.getName(nativeElementClassMirror.simpleName);
+        throw new DomException.jsInterop("HierarchyRequestError: Custom class type ($customClassNativeElement) and extendsTag class ($extendsNativeElement) don't match .");
+      }
+    } else if (customClassType.reflectedType != HtmlElement && customClassType.reflectedType != svg.SvgElement) {
+      var customClassName = MirrorSystem.getName(classMirror.simpleName);
+      var customClassElement = MirrorSystem.getName(customClassType.simpleName);
+      throw new DomException.jsInterop("HierarchyRequestError: Custom element $customClassName is a native $customClassElement should be derived from HtmlElement or SvgElement.");
+    }
+
     if (_hasCreatedConstructor(classMirror)) {
       // Start the hookup the JS way create an <x-foo> element that extends the
       // <x-base> custom element. Inherit its prototype and signal what tag is
@@ -384,7 +422,7 @@
       var elemProto = js.JsNative.callMethod(js.JsNative.getProperty(js.context, 'Object'), "create", [js.JsNative.getProperty(baseElement, 'prototype')]);
 
       // Remember for any upgrading done in wrap_jso.
-      _addCustomElementType(tag, customElementClass, extendsTag);
+      addCustomElementType(tag, customElementClass, extendsTag);
 
       // TODO(terry): Hack to stop recursion re-creating custom element when the
       //              created() constructor of the custom element does e.g.,
@@ -405,9 +443,26 @@
 
           var dartClass;
           try {
+            if (extendsTag != null) {
+              // If we're extending a native element then create that element.
+              // Then upgrade that element to the customElementClass through
+              // normal flow.
+              dartClass = document.createElement(extendsTag);
+              js.setDartHtmlWrapperFor($this, dartClass);
+              dartClass.blink_jsObject = $this;
+            }
+
+            // Upgrade to the CustomElement Dart class.
             dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
           } catch (e) {
+            // Got a problem make it an HtmlElement and rethrow the error.
             dartClass = HtmlElement.internalCreateHtmlElement();
+            // We need to remember the JS object (because constructElement failed
+            // it normally sets up the blink_jsObject.
+            dartClass.blink_jsObject = $this;
+
+            // Mark to only try this once don't try upgrading from HtmlElement
+            // to the user's Dart class - we had a problem.
             dartClass._badUpgrade();
             throw e;
           } finally {
diff --git a/tools/dom/templates/html/impl/impl_HTMLElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLElement.darttemplate
index fdc305f..1d12631 100644
--- a/tools/dom/templates/html/impl/impl_HTMLElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLElement.darttemplate
@@ -8,10 +8,17 @@
 $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS {
 $!MEMBERS
 $if DARTIUM
-  // Flags to only try upgrading once if there's a failure don't try upgrading
+  // Flags to only try upgrading once. If there's a failure don't try upgrading
   // anymore.
   bool _badUpgradeOccurred = false;
-  bool get _isBadUpgrade => _badUpgradeOccurred;
+
+  /// Required for SDK Infrastructure. Internal use only.
+  ///
+  /// Did this encounter a failure attempting to upgrade to
+  /// a custom element.
+  @Deprecated("Required for SDK Infrastructure. Internal use only.")
+  bool get isBadUpgrade => _badUpgradeOccurred;
+
   void _badUpgrade() { _badUpgradeOccurred = true; }
 $endif
 }