From 4e0a5e36b38e3f15ed8f7d700d26f2424a47111c Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Wed, 11 Feb 2015 14:53:10 +0100
Subject: ssl: Integrate public_key CRL verification with the ssl application

---
 lib/ssl/doc/src/Makefile                  |   4 +-
 lib/ssl/doc/src/refman.xml                |  19 +-
 lib/ssl/doc/src/ssl.xml                   |  45 ++-
 lib/ssl/doc/src/ssl_crl_cache.xml         |  66 ++++
 lib/ssl/doc/src/ssl_crl_cache_api.xml     |  97 +++++
 lib/ssl/doc/src/ssl_session_cache_api.xml |   6 +-
 lib/ssl/src/Makefile                      |   9 +-
 lib/ssl/src/ssl.app.src                   |   4 +
 lib/ssl/src/ssl.erl                       |  12 +-
 lib/ssl/src/ssl_certificate.erl           |  54 ++-
 lib/ssl/src/ssl_config.erl                |  37 +-
 lib/ssl/src/ssl_connection.erl            |  11 +-
 lib/ssl/src/ssl_connection.hrl            |   4 +-
 lib/ssl/src/ssl_crl.erl                   |  82 ++++
 lib/ssl/src/ssl_crl_cache.erl             | 179 +++++++++
 lib/ssl/src/ssl_crl_cache_api.erl         |  30 ++
 lib/ssl/src/ssl_handshake.erl             | 177 +++++++--
 lib/ssl/src/ssl_internal.hrl              |   6 +-
 lib/ssl/src/ssl_manager.erl               | 142 ++++---
 lib/ssl/src/ssl_pkix_db.erl               |  76 +++-
 lib/ssl/test/make_certs.erl               |  89 ++++-
 lib/ssl/test/ssl_basic_SUITE.erl          |   2 +-
 lib/ssl/test/ssl_crl_SUITE.erl            | 598 ++++++++----------------------
 lib/ssl/test/ssl_session_cache_SUITE.erl  |   6 +-
 lib/ssl/test/ssl_test_lib.erl             |   6 +-
 25 files changed, 1133 insertions(+), 628 deletions(-)
 create mode 100644 lib/ssl/doc/src/ssl_crl_cache.xml
 create mode 100644 lib/ssl/doc/src/ssl_crl_cache_api.xml
 create mode 100644 lib/ssl/src/ssl_crl.erl
 create mode 100644 lib/ssl/src/ssl_crl_cache.erl
 create mode 100644 lib/ssl/src/ssl_crl_cache_api.erl

diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index fb12499ef7..cfbf98f6e3 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -1,7 +1,7 @@
 #
 # %CopyrightBegin%
 #
-# Copyright Ericsson AB 1999-2012. All Rights Reserved.
+# Copyright Ericsson AB 1999-2015. All Rights Reserved.
 #
 # The contents of this file are subject to the Erlang Public License,
 # Version 1.1, (the "License"); you may not use this file except in
@@ -37,7 +37,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
 # Target Specs
 # ----------------------------------------------------
 XML_APPLICATION_FILES = refman.xml
-XML_REF3_FILES = ssl.xml ssl_session_cache_api.xml
+XML_REF3_FILES = ssl.xml ssl_crl_cache.xml ssl_crl_cache.xml ssl_session_cache_api.xml 
 XML_REF6_FILES = ssl_app.xml
 
 XML_PART_FILES = release_notes.xml usersguide.xml
diff --git a/lib/ssl/doc/src/refman.xml b/lib/ssl/doc/src/refman.xml
index ae11198edb..d5f2219af9 100644
--- a/lib/ssl/doc/src/refman.xml
+++ b/lib/ssl/doc/src/refman.xml
@@ -4,7 +4,7 @@
 <application xmlns:xi="http://www.w3.org/2001/XInclude">
   <header>
     <copyright>
-      <year>1999</year><year>2013</year>
+      <year>1999</year><year>2015</year>
       <holder>Ericsson AB. All Rights Reserved.</holder>
     </copyright>
     <legalnotice>
@@ -28,23 +28,10 @@
     <rev>B</rev>
     <file>refman.sgml</file>
   </header>
-  <description>
-    <p>The <em>SSL</em> application provides secure communication over
-      sockets.
-      </p>
-    <p>This product includes software developed by the OpenSSL Project for
-      use in the OpenSSL Toolkit (http://www.openssl.org/).
-      </p>
-    <p>This product includes cryptographic software written by Eric Young
-      (eay@cryptsoft.com).  
-      </p>
-    <p>This product includes software written by Tim Hudson
-      (tjh@cryptsoft.com).
-      </p>
-    <p>For full OpenSSL and SSLeay license texts, see <seealso marker="licenses#licenses">Licenses</seealso>.</p>
-  </description>
   <xi:include href="ssl_app.xml"/>
   <xi:include href="ssl.xml"/>
+  <xi:include href="ssl_crl_cache.xml"/>
+  <xi:include href="ssl_crl_cache_api.xml"/>
   <xi:include href="ssl_session_cache_api.xml"/>
 </application>
 
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 7a5f72710a..c9b02d44ec 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -51,9 +51,9 @@
       <item>IDEA cipher suites are not supported as they have
       become deprecated by the latest TLS spec so there is not any
       real motivation to implement them.</item>
-      <item>CRL and policy certificate extensions are not supported
-      yet. However CRL verification is supported by public_key, only not integrated
-      in ssl yet. </item>
+      <item>CRL validation is supported.</item>
+      <item>Policy certificate extensions are not supported
+      yet. </item>
       <item>Support for 'Server Name Indication' extension client side
       (RFC 6066 section 3).</item>
     </list>
@@ -301,10 +301,47 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() | {revo
 	<item> Possible such reasons see <seealso
 	marker="public_key:public_key#pkix_path_validation-3"> public_key:pkix_path_validation/3 </seealso></item>
       </taglist>
+      </item>
+
+      <tag>{crl_check, boolean() | peer | best_effort )</tag>
+      <item>
+	Perform CRL (Certificate Revocation List) verification
+	<seealso marker="public_key:public_key#pkix_crl_validate-3">
+	public_key:pkix_crls_validate/3</seealso>, during the
+	<seealso
+	marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3  </seealso>
+	invokation on all the certificates in the peer certificate chain. Defaults to
+	false.
+
+	<p><c>peer</c> - check is only performed on
+	the peer certificate.</p>
+
+	<p><c>best_effort</c> - if certificate revokation status can not be determined
+	it will be accepted as valid.</p>
 
+	<p>The CA certificates specified for the connection will be used to 
+	construct the certificate chain validating the CRLs.</p>
+ 	
+	<p>The CRLs will be fetched from a local or external cache
+	<seealso marker="ssl:ssl_crl_cache_api">ssl_crl_cache_api(3)</seealso>.</p>
       </item>
 
-      <tag>{partial_chain, fun(Chain::[DerCert]) -> {trusted_ca, DerCert} | unknown_ca }</tag>
+      <tag>{crl_cache, {Module::atom, {DbHandle::internal | term(), Args::list()}}</tag>
+      <item>
+	<p>Module defaults to ssl_crl_cache with <c> DbHandle </c> internal and an
+	empty argument list. The following arguments may be specified for the internal cache.</p>
+	<taglist>
+	  <tag>{http, timeout()}</tag>
+	  <item>
+	    Enables fetching of CRLs specified as http URIs in<seealso 
+	    marker="public_key:cert_records"> X509 cerificate extensions.</seealso>
+	    Requires the OTP inets application.
+	  </item>	    
+	</taglist>    
+      </item>
+      
+      <tag>{partial_chain, fun(Chain::[DerCert]) -> {trusted_ca, DerCert} | unknown_ca </tag>
+      
       <item>
 	Claim an intermediat CA in the chain as trusted. TLS will then perform the public_key:pkix_path_validation/3
 	with the selected CA as trusted anchor and the rest of the chain.
diff --git a/lib/ssl/doc/src/ssl_crl_cache.xml b/lib/ssl/doc/src/ssl_crl_cache.xml
new file mode 100644
index 0000000000..1ed76d3e2a
--- /dev/null
+++ b/lib/ssl/doc/src/ssl_crl_cache.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+  <header>
+    <copyright>
+      <year>2015</year><year>2015</year>
+      <holder>Ericsson AB. All Rights Reserved.</holder>
+    </copyright>
+    <legalnotice>
+      The contents of this file are subject to the Erlang Public License,
+      Version 1.1, (the "License"); you may not use this file except in
+      compliance with the License. You should have received a copy of the
+      Erlang Public License along with this software. If not, it can be
+      retrieved online at http://www.erlang.org/.
+
+      Software distributed under the License is distributed on an "AS IS"
+      basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+      the License for the specific language governing rights and limitations
+      under the License.
+    </legalnotice>
+    <title>ssl_crl_cache</title>
+    <file>ssl_crl_cache.xml</file>
+  </header>
+  
+  <module>ssl_crl_cache</module>
+  <modulesummary>CRL cache </modulesummary>
+  <description>
+    <p>
+      Implements an internal CRL (Certificate Revocation List) cache.
+      In addition to implementing the <seealso
+      marker="ssl_cache_crl_api"> ssl_cache_crl_api</seealso>
+      the following functions are available.
+    </p>
+  </description>
+  
+    <funcs>
+      <func>
+      <name>insert(CRLSrc) -> ok | {error, Reason}</name>
+      <name>insert(URI, CRLSrc) -> ok | {error, Reason}</name>
+      <fsummary> </fsummary>
+      <type>
+	<v> CRLSrc = {file, string()} | {der, [ <seealso
+	marker="public_key:public_key"> der_encoded() </seealso> ]}</v>
+	<v> URI = http_uri:uri()</v>
+	<v> Reason = term()</v>
+      </type>
+      <desc>
+	Insert CRLs into the ssl applications local cache.
+      </desc>
+    </func>
+
+     <func>
+      <name>delete(Entries) -> ok |  {error, Reason} </name>
+      <fsummary> </fsummary>
+      <type>
+	<v> Entries =  http_uri:uri() | {file, string()} | {der, [<seealso
+	marker="public_key:public_key"> der_encoded() </seealso>]}</v>
+	<v> Reason = term()</v>
+      </type>
+      <desc>
+	Delete CRLs from the ssl applications local cache.
+      </desc>
+     </func>     
+    </funcs>
+</erlref>
\ No newline at end of file
diff --git a/lib/ssl/doc/src/ssl_crl_cache_api.xml b/lib/ssl/doc/src/ssl_crl_cache_api.xml
new file mode 100644
index 0000000000..24365c9f59
--- /dev/null
+++ b/lib/ssl/doc/src/ssl_crl_cache_api.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+  <header>
+    <copyright>
+      <year>2015</year><year>2015</year>
+      <holder>Ericsson AB. All Rights Reserved.</holder>
+    </copyright>
+    <legalnotice>
+      The contents of this file are subject to the Erlang Public License,
+      Version 1.1, (the "License"); you may not use this file except in
+      compliance with the License. You should have received a copy of the
+      Erlang Public License along with this software. If not, it can be
+      retrieved online at http://www.erlang.org/.
+
+      Software distributed under the License is distributed on an "AS IS"
+      basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+      the License for the specific language governing rights and limitations
+      under the License.
+    </legalnotice>
+    <title>ssl_crl_cache_api</title>
+    <file>ssl_crl_cache_api.xml</file>
+  </header>
+  
+  <module>ssl_crl_cache_api</module>
+  <modulesummary>API for a SSL/TLS CRL (Certificate Revocation List) cache.</modulesummary>
+  <description>
+    <p>
+      When SSL/TLS performs certificate path validation according to 
+      <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url> it should
+      also perform CRL validation checks. To enable the CRL checks the application
+      needs access to CRLs. A database of CRLs can be set up in many different ways.
+      This module provides an API to integrate an arbitrary CRL cache with the erlang
+      ssl application. It is also used by the application itself to provide a simple
+      default implementation of a CRL cache. 
+    </p>
+  </description>
+  
+  <section>
+    <title>Common Data Types</title>
+    
+    <p>The following data types are used in the functions below:
+    </p>
+    
+    <p><c>cache_ref() = opaque()</c></p> 
+    <p> dist_point() = #'DistributionPoint'{} see <seealso
+    marker="public_key:cert_records"> X509 certificates records</seealso></p>
+  </section>
+  
+  <funcs>
+    <func>
+      <name>lookup(DistributionPoint, DbHandle) -> not_available | CRLs </name>
+      <fsummary> </fsummary>
+      <type>
+        <v> DistributionPoint = dist_point() </v>
+	<v> DbHandle  = cache_ref() </v>
+	<v> CRLs = [<seealso
+	   marker="public_key:public_key">public_key:der_encoded()</seealso>] </v>
+	</type>
+	<desc> <p>Lookup the CRLs belonging to the distribution point <c> Distributionpoint </c> </p>.
+	This function may choose to only look in the cache or to follow distribution point
+	links depending on how the cache is administrated.
+	</desc>
+    </func>
+    
+    <func>
+      <name>select(Issuer, DbHandle) -> CRLs </name>
+      <fsummary>Select the CRLs in the cache that are issued by <c>Issuer</c></fsummary>
+      <type>
+	<v> Issuer = <seealso
+	marker="public_key:public_key">public_key:issuer_name()</seealso></v>
+	<v> DbHandle  = cache_ref() </v>
+	</type>
+	<desc>
+	  <p>Select the CRLs in the cache that are issued by <c>Issuer</c> </p>
+	</desc>
+    </func>
+    
+    <func>
+      <name>fresh_crl(DistributionPoint, CRL) -> FreshCRL</name>
+      <fsummary> <c>fun fresh_crl/2 </c> will be used as input option <c>update_crl</c> to
+      public_key:pkix_crls_validate/3 </fsummary>
+      <type>
+	<v> DistributionPoint = dist_point() </v>
+	<v> CRL = [<seealso
+	marker="public_key:public_key">public_key:der_encoded()</seealso>] </v>
+	<v> FreshCRL = [<seealso
+	marker="public_key:public_key">public_key:der_encoded()</seealso>] </v>
+      </type>
+      <desc>
+	<p> <c>fun fresh_crl/2 </c> will be used as input option <c>update_crl</c> to
+	<seealso marker="public_key#pkix_path_validation-3">public_key:pkix_crls_validate/3 </seealso> </p>
+      </desc>
+    </func>
+  </funcs>
+</erlref>
\ No newline at end of file
diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml
index cb97bbfbb2..9f87d31e90 100644
--- a/lib/ssl/doc/src/ssl_session_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_session_cache_api.xml
@@ -4,7 +4,7 @@
 <erlref>
   <header>
     <copyright>
-      <year>1999</year><year>2014</year>
+      <year>1999</year><year>2015</year>
       <holder>Ericsson AB. All Rights Reserved.</holder>
     </copyright>
     <legalnotice>
@@ -119,14 +119,14 @@
     
     <func>
       <name>select_session(Cache, PartialKey) -> [session()]</name>
-      <fsummary>>Selects sessions that could be reused.</fsummary>
+      <fsummary>Selects a sessions that could be reused.</fsummary>
       <type>
 	<v> Cache = cache_ref()</v>
 	<v> PartialKey = partialkey()</v>
 	<v> Session = session()</v>
       </type>
       <desc>
-	<p>Selects sessions that could be reused. Should be callable
+	<p>Selects a sessions that could be reused. Should be callable
 	from any process.
 	</p>
       </desc>
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index 0c00a650b9..d71d3fc445 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -1,7 +1,7 @@
 #
 # %CopyrightBegin%
 #
-# Copyright Ericsson AB 1999-2014. All Rights Reserved.
+# Copyright Ericsson AB 1999-2015. All Rights Reserved.
 #
 # The contents of this file are subject to the Erlang Public License,
 # Version 1.1, (the "License"); you may not use this file except in
@@ -38,7 +38,8 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN)
 # ----------------------------------------------------
 
 BEHAVIOUR_MODULES= \
-        ssl_session_cache_api
+        ssl_session_cache_api \
+	ssl_crl_cache_api
 
 MODULES= \
 	ssl \
@@ -65,6 +66,8 @@ MODULES= \
 	ssl_manager \
 	ssl_session \
 	ssl_session_cache \
+	ssl_crl\
+	ssl_crl_cache \
 	ssl_socket \
 	ssl_listen_tracker_sup \
 	tls_record \
@@ -164,5 +167,5 @@ $(EBIN)/ssl_session_cache.$(EMULATOR):  ssl_internal.hrl ssl_handshake.hrl
 $(EBIN)/ssl_session_cache_api.$(EMULATOR):  ssl_internal.hrl ssl_handshake.hrl
 $(EBIN)/ssl_ssl3.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl
 $(EBIN)/ssl_tls1.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl
-
+$(EBIN)/ssl_cache.$(EMULATOR): ssl_cache.erl ssl_internal.hrl ../../public_key/include/public_key.hrl
 
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 36681e2897..955875fa95 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -39,6 +39,10 @@
 	       ssl_manager,
 	       ssl_pkix_db,
 	       ssl_certificate,
+	       %% CRL handling
+	       ssl_crl,
+	       ssl_crl_cache, 
+	       ssl_crl_cache_api,
 	       %% App structure
 	       ssl_app,
 	       ssl_sup,
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 973b579f97..623fa92121 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -654,7 +654,9 @@ handle_options(Opts0) ->
 		    honor_cipher_order = handle_option(honor_cipher_order, Opts, false),
 		    protocol = proplists:get_value(protocol, Opts, tls),
 		    padding_check =  proplists:get_value(padding_check, Opts, true),
-		    fallback =  proplists:get_value(fallback, Opts, false)
+		    fallback =  proplists:get_value(fallback, Opts, false),
+		    crl_check = handle_option(crl_check, Opts, false),
+		    crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}})
 		   },
 
     CbInfo  = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
@@ -667,7 +669,7 @@ handle_options(Opts0) ->
 		  cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
 		  erl_dist, next_protocols_advertised,
 		  client_preferred_next_protocols, log_alert,
-		  server_name_indication, honor_cipher_order, padding_check,
+		  server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache,
 		  fallback],
 
     SockOpts = lists:foldl(fun(Key, PropList) ->
@@ -850,6 +852,12 @@ validate_option(padding_check, Value) when is_boolean(Value) ->
     Value;
 validate_option(fallback, Value) when is_boolean(Value) ->
     Value;
+validate_option(crl_check, Value) when is_boolean(Value)  ->
+    Value;
+validate_option(crl_check, Value) when (Value == best_effort) or (Value == peer) -> 
+    Value;
+validate_option(crl_cache, {Cb, {_Handle, Options}} = Value) when is_atom(Cb) and is_list(Options) ->
+    Value;
 validate_option(Opt, Value) ->
     throw({error, {options, {Opt, Value}}}).
 
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 30d224fee2..764bd82de0 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2007-2014 All Rights Reserved.
+%% Copyright Ericsson AB 2007-2015 All Rights Reserved.
 %%
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -33,7 +33,8 @@
 -export([trusted_cert_and_path/4,
 	 certificate_chain/3,
 	 file_to_certificats/2,
-	 validate_extension/3,
+	 file_to_crls/2,
+	 validate/3,
 	 is_valid_extkey_usage/2,
 	 is_valid_key_usage/2,
 	 select_extension/2,
@@ -84,15 +85,18 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef, PartialChainHandler) -
 
 %%--------------------------------------------------------------------
 -spec certificate_chain(undefined | binary(), db_handle(), certdb_ref()) ->
-			  {error, no_cert} | {ok, [der_cert()]}.
+			  {error, no_cert} | {ok, #'OTPCertificate'{} | undefined, [der_cert()]}.
 %%
 %% Description: Return the certificate chain to send to peer.
 %%--------------------------------------------------------------------
 certificate_chain(undefined, _, _) ->
     {error, no_cert};
-certificate_chain(OwnCert, CertDbHandle, CertsDbRef) ->
+certificate_chain(OwnCert, CertDbHandle, CertsDbRef) when is_binary(OwnCert) ->
     ErlCert = public_key:pkix_decode_cert(OwnCert, otp),
-    certificate_chain(ErlCert, OwnCert, CertDbHandle, CertsDbRef, [OwnCert]).
+    certificate_chain(ErlCert, OwnCert, CertDbHandle, CertsDbRef, [OwnCert]);
+certificate_chain(OwnCert, CertDbHandle, CertsDbRef) ->
+    DerCert = public_key:pkix_encode('OTPCertificate', OwnCert, otp),
+    certificate_chain(OwnCert, DerCert, CertDbHandle, CertsDbRef, [DerCert]).
 %%--------------------------------------------------------------------
 -spec file_to_certificats(binary(), term()) -> [der_cert()].
 %%
@@ -101,29 +105,39 @@ certificate_chain(OwnCert, CertDbHandle, CertsDbRef) ->
 file_to_certificats(File, DbHandle) ->
     {ok, List} = ssl_manager:cache_pem_file(File, DbHandle),
     [Bin || {'Certificate', Bin, not_encrypted} <- List].
+
 %%--------------------------------------------------------------------
--spec validate_extension(term(), {extension, #'Extension'{}} | {bad_cert, atom()} | valid,
-			 term()) -> {valid, term()} |
-				    {fail, tuple()} |
-				    {unknown, term()}.
+-spec file_to_crls(binary(), term()) -> [der_cert()].
+%%
+%% Description: Return list of DER encoded certificates.
+%%--------------------------------------------------------------------
+file_to_crls(File, DbHandle) ->
+    {ok, List} = ssl_manager:cache_pem_file(File, DbHandle),
+    [Bin || {'CertificateList', Bin, not_encrypted} <- List].
+
+%%--------------------------------------------------------------------
+-spec validate(term(), {extension, #'Extension'{}} | {bad_cert, atom()} | valid,
+	       term()) -> {valid, term()} |
+			  {fail, tuple()} |
+			  {unknown, term()}.
 %%
 %% Description:  Validates ssl/tls specific extensions
 %%--------------------------------------------------------------------
-validate_extension(_,{extension, #'Extension'{extnID = ?'id-ce-extKeyUsage',
-					      extnValue = KeyUse}}, Role) ->
+validate(_,{extension, #'Extension'{extnID = ?'id-ce-extKeyUsage',
+				    extnValue = KeyUse}}, {Role, _,_, _, _}) ->
     case is_valid_extkey_usage(KeyUse, Role) of
 	true ->
 	    {valid, Role};
 	false ->
 	    {fail, {bad_cert, invalid_ext_key_usage}}
     end;
-validate_extension(_, {bad_cert, _} = Reason, _) ->
-    {fail, Reason};
-validate_extension(_, {extension, _}, Role) ->
+validate(_, {extension, _}, Role) ->
     {unknown, Role};
-validate_extension(_, valid, Role) ->
+validate(_, {bad_cert, _} = Reason, _) ->
+    {fail, Reason};
+validate(_, valid, Role) ->
     {valid, Role};
-validate_extension(_, valid_peer, Role) ->
+validate(_, valid_peer, Role) ->
     {valid, Role}.
 
 %%--------------------------------------------------------------------
@@ -194,14 +208,14 @@ certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) ->
 		    %% certificate. The verification of the
 		    %% cert chain will fail if guess is
 		    %% incorrect.
-		    {ok, lists:reverse(Chain)}
+		    {ok, undefined, lists:reverse(Chain)}
 	    end;
 	{{ok, {SerialNr, Issuer}}, SelfSigned} -> 
 	    certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, SelfSigned)
     end.
   
-certificate_chain(_,_, Chain, _SerialNr, _Issuer, true) ->
-    {ok, lists:reverse(Chain)};
+certificate_chain(_, _, [RootCert | _] = Chain, _, _, true) ->	  
+    {ok, RootCert, lists:reverse(Chain)};		      
 
 certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) ->
     case ssl_manager:lookup_trusted_cert(CertDbHandle, CertsDbRef,
@@ -214,7 +228,7 @@ certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned
 	    %% The trusted cert may be obmitted from the chain as the
 	    %% counter part needs to have it anyway to be able to
 	    %% verify it.
-	    {ok, lists:reverse(Chain)}		      
+	    {ok, undefined, lists:reverse(Chain)}		      
     end.
 
 find_issuer(OtpCert, CertDbHandle) ->
diff --git a/lib/ssl/src/ssl_config.erl b/lib/ssl/src/ssl_config.erl
index 545b8aa0f6..fc8b214a29 100644
--- a/lib/ssl/src/ssl_config.erl
+++ b/lib/ssl/src/ssl_config.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
 %%
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -31,13 +31,13 @@ init(SslOpts, Role) ->
     
     init_manager_name(SslOpts#ssl_options.erl_dist),
 
-    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, OwnCert} 
+    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbHandle, OwnCert} 
 	= init_certificates(SslOpts, Role),
     PrivateKey =
 	init_private_key(PemCacheHandle, SslOpts#ssl_options.key, SslOpts#ssl_options.keyfile,
 			 SslOpts#ssl_options.password, Role),
     DHParams = init_diffie_hellman(PemCacheHandle, SslOpts#ssl_options.dh, SslOpts#ssl_options.dhfile, Role),
-    {ok, CertDbRef, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, PrivateKey, DHParams}.
+    {ok, CertDbRef, CertDbHandle, FileRefHandle, CacheHandle, CRLDbHandle, OwnCert, PrivateKey, DHParams}.
 
 init_manager_name(false) ->
     put(ssl_manager, ssl_manager:manager_name(normal));
@@ -46,9 +46,11 @@ init_manager_name(true) ->
 
 init_certificates(#ssl_options{cacerts = CaCerts,
 			       cacertfile = CACertFile,
-			       certfile = CertFile,
-			       cert = Cert}, Role) ->
-    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle} =
+			       certfile = CertFile,			   
+			       cert = Cert,
+			       crl_cache = CRLCache
+			      }, Role) ->
+    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbInfo} =
 	try 
 	    Certs = case CaCerts of
 			undefined ->
@@ -56,39 +58,40 @@ init_certificates(#ssl_options{cacerts = CaCerts,
 			_ ->
 			    {der, CaCerts}
 		    end,
-	    {ok, _, _, _, _, _} = ssl_manager:connection_init(Certs, Role)
+	    {ok, _, _, _, _, _, _} = ssl_manager:connection_init(Certs, Role, CRLCache)
 	catch
 	    _:Reason ->
 		file_error(CACertFile, {cacertfile, Reason})
 	end,
     init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, 
-		      CacheHandle, CertFile, Role).
+		      CacheHandle, CRLDbInfo, CertFile, Role).
 
-init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, <<>>, _) ->
-    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, undefined};
+init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, 
+		  CRLDbInfo, <<>>, _) ->
+    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbInfo, undefined};
 
 init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, 
-		  CacheHandle, CertFile, client) ->
+		  CacheHandle, CRLDbInfo, CertFile, client) ->
     try 
 	%% Ignoring potential proxy-certificates see: 
 	%% http://dev.globus.org/wiki/Security/ProxyFileFormat
 	[OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
-	{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, OwnCert}
+	{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbInfo, OwnCert}
     catch _Error:_Reason  ->
-	    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, undefined}
+	    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CRLDbInfo, undefined}
     end;
 
 init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, 
-		  PemCacheHandle, CacheRef, CertFile, server) ->
+		  PemCacheHandle, CacheRef, CRLDbInfo, CertFile, server) ->
     try
 	[OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
-	{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, OwnCert}
+	{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CRLDbInfo, OwnCert}
     catch
 	_:Reason ->
 	    file_error(CertFile, {certfile, Reason})	    
     end;
-init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, _, _) ->
-    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, Cert}.
+init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CRLDbInfo, _, _) ->
+    {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CRLDbInfo, Cert}.
 
 init_private_key(_, undefined, <<>>, _Password, _Client) ->
     undefined;
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index b6059eac58..08d0145aa7 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
 %%
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -411,11 +411,15 @@ certify(#certificate{} = Cert,
 	       role = Role,
 	       cert_db = CertDbHandle,
 	       cert_db_ref = CertDbRef,
+	       crl_db = CRLDbInfo,
 	       ssl_options = Opts} = State, Connection) ->
-    case ssl_handshake:certify(Cert, CertDbHandle, CertDbRef, Opts#ssl_options.depth,
+    case ssl_handshake:certify(Cert, CertDbHandle, CertDbRef, 
+			       Opts#ssl_options.depth,
 			       Opts#ssl_options.verify,
 			       Opts#ssl_options.verify_fun,
 			       Opts#ssl_options.partial_chain,
+			       Opts#ssl_options.crl_check,
+			       CRLDbInfo,		       
 			       Role) of
         {PeerCert, PublicKeyInfo} ->
 	    handle_peer_cert(Role, PeerCert, PublicKeyInfo,
@@ -964,7 +968,7 @@ format_status(terminate, [_, State]) ->
 %%% Internal functions
 %%--------------------------------------------------------------------
 ssl_config(Opts, Role, State) ->
-    {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, Key, DHParams} = 
+    {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, CRLDbInfo, OwnCert, Key, DHParams} = 
 	ssl_config:init(Opts, Role), 
     Handshake = ssl_handshake:init_handshake_history(),
     TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}),
@@ -975,6 +979,7 @@ ssl_config(Opts, Role, State) ->
 		file_ref_db = FileRefHandle,
 		cert_db_ref = Ref,
 		cert_db = CertDbHandle,
+		crl_db = CRLDbInfo,
 		session_cache = CacheHandle,
 		private_key = Key,
 		diffie_hellman_params = DHParams,
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index b9a1ef3a84..ac3b26e4bf 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -1,8 +1,7 @@
-
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
 %%
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -53,6 +52,7 @@
           session               :: #session{} | secret_printout(),
 	  session_cache         :: db_handle(),
 	  session_cache_cb      :: atom(),
+	  crl_db                :: term(), 
           negotiated_version    :: ssl_record:ssl_version(),
           client_certificate_requested = false :: boolean(),
 	  key_algorithm         :: ssl_cipher:key_algo(),
diff --git a/lib/ssl/src/ssl_crl.erl b/lib/ssl/src/ssl_crl.erl
new file mode 100644
index 0000000000..b8761f0601
--- /dev/null
+++ b/lib/ssl/src/ssl_crl.erl
@@ -0,0 +1,82 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+%----------------------------------------------------------------------
+%% Purpose: CRL handling 
+%%----------------------------------------------------------------------
+
+-module(ssl_crl).
+
+-include("ssl_alert.hrl").
+-include("ssl_internal.hrl").
+-include_lib("public_key/include/public_key.hrl"). 
+
+-export([trusted_cert_and_path/3]).
+
+trusted_cert_and_path(CRL, {SerialNumber, Issuer},{Db, DbRef} = DbHandle) -> 
+    case ssl_pkix_db:lookup_trusted_cert(Db, DbRef, SerialNumber, Issuer) of
+	undefined ->
+	    trusted_cert_and_path(CRL, issuer_not_found, DbHandle);
+	{ok, {_, OtpCert}}  ->
+	    {ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef),
+	    {ok, Root,  lists:reverse(Chain)}
+    end;
+
+trusted_cert_and_path(CRL, issuer_not_found, {Db, DbRef} = DbHandle) -> 
+    try find_issuer(CRL, DbHandle) of
+	OtpCert ->
+	    {ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef),
+	    {ok, Root, lists:reverse(Chain)}
+    catch
+	throw:_ ->
+	    {error, issuer_not_found}
+    end.
+
+find_issuer(CRL, {Db,_}) ->
+    Issuer = public_key:pkix_normalize_name(public_key:pkix_crl_issuer(CRL)),
+    IsIssuerFun =
+	fun({_Key, {_Der,ErlCertCandidate}}, Acc) ->
+		verify_crl_issuer(CRL, ErlCertCandidate, Issuer, Acc);
+	   (_, Acc) ->
+		Acc
+	end,
+    
+    try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, Db) of
+	issuer_not_found ->
+	    {error, issuer_not_found}
+    catch 
+	{ok, IssuerCert}  ->
+	    IssuerCert
+    end.
+
+
+verify_crl_issuer(CRL, ErlCertCandidate, Issuer, NotIssuer) ->
+    TBSCert =  ErlCertCandidate#'OTPCertificate'.tbsCertificate,
+    case public_key:pkix_normalize_name(TBSCert#'OTPTBSCertificate'.subject) of
+	Issuer ->
+	    case public_key:pkix_crl_verify(CRL, ErlCertCandidate) of
+		true ->
+		    throw({ok, ErlCertCandidate});
+		false ->
+		    NotIssuer;
+		_ ->
+		    NotIssuer
+	    end;
+	_ ->
+	    NotIssuer
+    end.
diff --git a/lib/ssl/src/ssl_crl_cache.erl b/lib/ssl/src/ssl_crl_cache.erl
new file mode 100644
index 0000000000..b2bdb19979
--- /dev/null
+++ b/lib/ssl/src/ssl_crl_cache.erl
@@ -0,0 +1,179 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+%----------------------------------------------------------------------
+%% Purpose: Simple default CRL cache 
+%%----------------------------------------------------------------------
+
+-module(ssl_crl_cache).
+
+-include("ssl_internal.hrl").
+-include_lib("public_key/include/public_key.hrl"). 
+
+-behaviour(ssl_crl_cache_api).
+
+-export([lookup/2, select/2, fresh_crl/2]).
+-export([insert/1, insert/2, delete/1]).
+
+%%====================================================================
+%% Cache callback API
+%%====================================================================
+
+lookup(#'DistributionPoint'{distributionPoint={fullName, Names}}, 
+       CRLDbInfo) ->
+    get_crls(Names, CRLDbInfo);
+lookup(_,_) ->
+    not_available.
+
+select(Issuer, {{_Cache, Mapping},_}) ->
+    case ssl_pkix_db:lookup(Issuer, Mapping) of
+	undefined ->
+	    [];
+	CRLs ->
+	    CRLs
+    end.
+
+fresh_crl(DistributionPoint, CRL) ->
+    case get_crls(DistributionPoint, undefined) of
+	not_available ->
+	    CRL;
+	[NewCRL] ->
+	    NewCRL
+    end.
+
+%%====================================================================
+%% API 
+%%====================================================================
+
+insert(CRLs) ->
+    insert(?NO_DIST_POINT, CRLs).
+
+insert(URI, {file, File}) when is_list(URI) ->				     
+    case file:read_file(File) of
+	{ok, PemBin} ->
+	    PemEntries = public_key:pem_decode(PemBin),
+	    CRLs = [ CRL || {'CertificateList', CRL, not_encrypted} 
+				<- PemEntries],
+	    do_insert(URI, CRLs);
+	Error ->
+	    Error
+    end;
+insert(URI, {der, CRLs}) ->	
+    do_insert(URI, CRLs).
+
+delete({file, File}) ->
+    case file:read_file(File) of
+	{ok, PemBin} ->
+	    PemEntries = public_key:pem_decode(PemBin),
+	    CRLs = [ CRL || {'CertificateList', CRL, not_encrypted} 
+				<- PemEntries],
+	    ssl_manager:delete_crls({?NO_DIST_POINT, CRLs});
+	Error ->
+	    Error
+    end;
+delete({der, CRLs}) ->	
+    ssl_manager:delete_crls({?NO_DIST_POINT, CRLs});
+
+delete(URI) ->
+    case http_uri:parse(URI) of
+	{ok, {http, _, _ , _, Path,_}} -> 
+	    ssl_manager:delete_crls(string:strip(Path, left, $/));
+	_ ->
+	    {error, {only_http_distribution_points_supported, URI}}
+    end.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+do_insert(URI, CRLs) ->
+    case http_uri:parse(URI) of
+	{ok, {http, _, _ , _, Path,_}} -> 
+	    ssl_manager:insert_crls(string:strip(Path, left, $/), CRLs);
+	_ ->
+	    {error, {only_http_distribution_points_supported, URI}}
+    end.
+
+get_crls([], _) ->
+    not_available;
+get_crls([{uniformResourceIdentifier, "http"++_ = URL} | Rest], 
+	 CRLDbInfo) ->
+    case cache_lookup(URL, CRLDbInfo) of
+	[] ->
+	   handle_http(URL, Rest, CRLDbInfo);
+	CRLs ->
+	    CRLs
+    end;
+get_crls([ _| Rest], CRLDbInfo) ->
+    %% unsupported CRL location
+    get_crls(Rest, CRLDbInfo).
+
+http_lookup(URL, Rest, CRLDbInfo, Timeout) ->
+    case application:ensure_started(inets) of
+	ok ->
+	    http_get(URL, Rest, CRLDbInfo, Timeout);  
+	_ ->
+	    get_crls(Rest, CRLDbInfo)
+    end.
+
+http_get(URL, Rest, CRLDbInfo, Timeout) ->
+    case httpc:request(get, {URL, [{"connection", "close"}]}, 
+		       [{timeout, Timeout}], [{body_format, binary}]) of
+        {ok, {_Status, _Headers, Body}} ->
+            case Body of
+                <<"-----BEGIN", _/binary>> ->
+                    Pem = public_key:pem_decode(Body),
+		    lists:filtermap(fun({'CertificateList', 
+					 CRL, not_encrypted}) ->
+					    {true, CRL};
+				       (_) ->
+					    false
+				    end, Pem);
+		_ ->
+		    try public_key:der_decode('CertificateList', Body) of
+			_ ->
+			    [Body]
+		    catch
+			_:_ ->
+			    get_crls(Rest, CRLDbInfo)
+		    end   
+	    end;
+        {error, _Reason} ->
+            get_crls(Rest, CRLDbInfo)
+    end.
+
+cache_lookup(_, undefined) ->
+    [];
+cache_lookup(URL, {{Cache, _}, _}) ->
+    {ok, {_, _, _ , _, Path,_}} = http_uri:parse(URL), 
+    case ssl_pkix_db:lookup(string:strip(Path, left, $/), Cache) of
+	undefined ->
+	    [];
+	CRLs ->
+	    CRLs
+    end.
+
+handle_http(URI, Rest, {_,  [{http, Timeout}]} = CRLDbInfo) ->
+    CRLs = http_lookup(URI, Rest, CRLDbInfo, Timeout),
+    %% Uncomment to improve performance, but need to 
+    %% implement cache limit and or cleaning to prevent 
+    %% DoS attack possibilities
+    %%insert(URI, {der, CRLs}),
+    CRLs;
+handle_http(_, Rest, CRLDbInfo) ->
+    get_crls(Rest, CRLDbInfo).
+
diff --git a/lib/ssl/src/ssl_crl_cache_api.erl b/lib/ssl/src/ssl_crl_cache_api.erl
new file mode 100644
index 0000000000..0915ba12e5
--- /dev/null
+++ b/lib/ssl/src/ssl_crl_cache_api.erl
@@ -0,0 +1,30 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_crl_cache_api).
+
+-include_lib("public_key/include/public_key.hrl"). 
+
+-type db_handle() :: term(). 
+
+-callback lookup(#'DistributionPoint'{}, db_handle()) -> not_available | [public_key:der_encode()].
+-callback select(term(), db_handle()) ->  [public_key:der_encode()].
+-callback fresh_crl(#'DistributionPoint'{}, public_key:der_encode()) -> public_key:der_encode().
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 07535e79b4..6cab8eb7a1 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
 %%
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -49,7 +49,7 @@
 	 finished/5,  next_protocol/1]).
 
 %% Handle handshake messages
--export([certify/8, client_certificate_verify/6, certificate_verify/6, verify_signature/5,
+-export([certify/10, client_certificate_verify/6, certificate_verify/6, verify_signature/5,
 	 master_secret/5, server_key_exchange_hash/2, verify_connection/6,
 	 init_handshake_history/0, update_handshake_history/2, verify_server_key/5
 	]).
@@ -149,7 +149,7 @@ client_hello_extensions(Host, Version, CipherSuites, SslOpts, ConnectionStates,
 certificate(OwnCert, CertDbHandle, CertDbRef, client) ->
     Chain =
 	case ssl_certificate:certificate_chain(OwnCert, CertDbHandle, CertDbRef) of
-	    {ok, CertChain} ->
+	    {ok, _,  CertChain} ->
 		CertChain;
 	    {error, _} ->
 		%% If no suitable certificate is available, the client
@@ -161,7 +161,7 @@ certificate(OwnCert, CertDbHandle, CertDbRef, client) ->
 
 certificate(OwnCert, CertDbHandle, CertDbRef, server) ->
     case ssl_certificate:certificate_chain(OwnCert, CertDbHandle, CertDbRef) of
-	{ok, Chain} ->
+	{ok, _, Chain} ->
 	    #certificate{asn1_certificates = Chain};
 	{error, _} ->
 	    ?ALERT_REC(?FATAL, ?INTERNAL_ERROR)
@@ -383,49 +383,24 @@ verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature,
 
 %%--------------------------------------------------------------------
 -spec certify(#certificate{}, db_handle(), certdb_ref(), integer() | nolimit,
-	      verify_peer | verify_none, {fun(), term}, fun(),
+	      verify_peer | verify_none, {fun(), term}, fun(), term(), term(),
 	      client | server) ->  {der_cert(), public_key_info()} | #alert{}.
 %%
 %% Description: Handles a certificate handshake message
 %%--------------------------------------------------------------------
 certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
-	MaxPathLen, _Verify, VerifyFunAndState, PartialChain, Role) ->
+	MaxPathLen, _Verify, ValidationFunAndState0, PartialChain, CRLCheck, CRLDbHandle, Role) ->
     [PeerCert | _] = ASN1Certs,
-
-    ValidationFunAndState =
-	case VerifyFunAndState of
-	    undefined ->
-		{fun(OtpCert, ExtensionOrVerifyResult, SslState) ->
-			 ssl_certificate:validate_extension(OtpCert,
-							    ExtensionOrVerifyResult, SslState)
-		 end, Role};
-	    {Fun, UserState0} ->
-		{fun(OtpCert, {extension, _} = Extension, {SslState, UserState}) ->
-			 case ssl_certificate:validate_extension(OtpCert,
-								 Extension,
-								 SslState) of
-			     {valid, NewSslState} ->
-				 {valid, {NewSslState, UserState}};
-			     {fail, Reason} ->
-				 apply_user_fun(Fun, OtpCert, Reason, UserState,
-						SslState);
-			     {unknown, _} ->
-				 apply_user_fun(Fun, OtpCert,
-						Extension, UserState, SslState)
-			 end;
-		    (OtpCert, VerifyResult, {SslState, UserState}) ->
-			 apply_user_fun(Fun, OtpCert, VerifyResult, UserState,
-					SslState)
-		 end, {Role, UserState0}}
-	end,
+        
+    ValidationFunAndState = validation_fun_and_state(ValidationFunAndState0, Role, 
+						     CertDbHandle, CertDbRef,  CRLCheck, CRLDbHandle),
 
     try
-	{TrustedErlCert, CertPath}  =
+	{TrustedCert, CertPath}  =
 	    ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbHandle, CertDbRef, PartialChain),
-	case public_key:pkix_path_validation(TrustedErlCert,
-					      CertPath,
-					     [{max_path_length,
-					       MaxPathLen},
+	case public_key:pkix_path_validation(TrustedCert,
+					     CertPath,
+					     [{max_path_length, MaxPathLen},
 					      {verify_fun, ValidationFunAndState}]) of
 	    {ok, {PublicKeyInfo,_}} ->
 		{PeerCert, PublicKeyInfo};
@@ -1374,15 +1349,66 @@ sni1(Hostname) ->
 %%--------------------------------------------------------------------
 %%% Internal functions
 %%--------------------------------------------------------------------
+validation_fun_and_state({Fun, UserState0}, Role,  CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle) ->
+    {fun(OtpCert, {extension, _} = Extension, {SslState, UserState}) ->
+	     case ssl_certificate:validate(OtpCert,
+					   Extension,
+					   SslState) of
+		 {valid, NewSslState} ->
+		     {valid, {NewSslState, UserState}};
+		 {fail, Reason} ->
+		     apply_user_fun(Fun, OtpCert, Reason, UserState,
+				    SslState);
+		 {unknown, _} ->
+		     apply_user_fun(Fun, OtpCert,
+				    Extension, UserState, SslState)
+	     end;
+	(OtpCert, VerifyResult, {SslState, UserState}) ->
+	     apply_user_fun(Fun, OtpCert, VerifyResult, UserState,
+			    SslState)
+     end, {{Role, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle}, UserState0}};
+validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle) ->
+    {fun(OtpCert, {extension, _} = Extension, SslState) ->
+	     ssl_certificate:validate(OtpCert,
+				      Extension,
+				      SslState);
+	(OtpCert, VerifyResult, SslState) when (VerifyResult == valid) or (VerifyResult == valid_peer) -> 
+	     case crl_check(OtpCert, CRLCheck, CertDbHandle, CertDbRef, CRLDbHandle, VerifyResult) of
+		 valid ->
+		     {VerifyResult, SslState};
+		 Reason ->
+		     {fail, Reason}
+	     end;
+	(OtpCert, VerifyResult, SslState) ->
+	     ssl_certificate:validate(OtpCert,
+				      VerifyResult,
+				      SslState)
+     end, {Role, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle}}.
+
+apply_user_fun(Fun, OtpCert, VerifyResult, UserState0, 
+	       {_, CertDbHandle, CertDbRef, CRLCheck, CRLDbHandle} = SslState) when
+      (VerifyResult == valid) or (VerifyResult == valid_peer) ->
+    case Fun(OtpCert, VerifyResult, UserState0) of
+	{Valid, UserState} when (Valid == valid) or (Valid == valid_peer) ->
+	    case crl_check(OtpCert, CRLCheck, CertDbHandle, CertDbRef, CRLDbHandle, VerifyResult) of
+		valid ->
+		    {Valid, {SslState, UserState}};
+		Result ->
+		    apply_user_fun(Fun, OtpCert, Result, UserState, SslState)
+	    end;
+	{fail, _} = Fail ->
+	    Fail
+    end;
 apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
     case Fun(OtpCert, ExtensionOrError, UserState0) of
-	{valid, UserState} ->
-	    {valid, {SslState, UserState}};
+	{Valid, UserState} when (Valid == valid) or (Valid == valid_peer)->
+	    {Valid, {SslState, UserState}};
 	{fail, _} = Fail ->
 	    Fail;
 	{unknown, UserState} ->
 	    {unknown, {SslState, UserState}}
     end.
+
 path_validation_alert({bad_cert, cert_expired}) ->
     ?ALERT_REC(?FATAL, ?CERTIFICATE_EXPIRED);
 path_validation_alert({bad_cert, invalid_issuer}) ->
@@ -1393,8 +1419,10 @@ path_validation_alert({bad_cert, name_not_permitted}) ->
     ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
 path_validation_alert({bad_cert, unknown_critical_extension}) ->
     ?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE);
-path_validation_alert({bad_cert, cert_revoked}) ->
+path_validation_alert({bad_cert, {revoked, _}}) ->
     ?ALERT_REC(?FATAL, ?CERTIFICATE_REVOKED);
+path_validation_alert({bad_cert, revocation_status_undetermined}) ->
+    ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
 path_validation_alert({bad_cert, selfsigned_peer}) ->
     ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
 path_validation_alert({bad_cert, unknown_ca}) ->
@@ -1954,3 +1982,70 @@ handle_psk_identity(_PSKIdentity, LookupFun)
     error;
 handle_psk_identity(PSKIdentity, {Fun, UserState}) ->
     Fun(psk, PSKIdentity, UserState).
+
+crl_check(_, false, _,_,_, _) ->
+    valid;
+crl_check(_, peer, _, _,_, valid) -> %% Do not check CAs with this option.
+    valid;
+crl_check(OtpCert, Check, CertDbHandle, CertDbRef, {Callback, CRLDbHandle}, _) ->
+    Options = [{issuer_fun, {fun(_DP, CRL, Issuer, DBInfo) ->
+				     ssl_crl:trusted_cert_and_path(CRL, Issuer, DBInfo)
+			     end, {CertDbHandle, CertDbRef}}}, 
+	       {update_crl, fun(DP, CRL) -> Callback:fresh_crl(DP, CRL) end}
+	      ],
+    case dps_and_crls(OtpCert, Callback, CRLDbHandle, ext) of
+	no_dps ->
+	    case dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer) of
+		[] ->
+		    valid; %% No relevant CRL existed
+		Dps ->
+		    crl_check_same_issuer(OtpCert, Check, Dps, Options)		
+	    end;
+	Dps ->  %% This DP list may be empty if relevant CRLs existed 
+	    %% but could not be retrived, will result in {bad_cert, revocation_status_undetermined}
+	    case public_key:pkix_crls_validate(OtpCert, Dps, Options) of
+		{bad_cert, revocation_status_undetermined} ->
+		    crl_check_same_issuer(OtpCert, Check, dps_and_crls(OtpCert, Callback, 
+								       CRLDbHandle, same_issuer), Options);
+		Other ->
+		    Other
+	    end
+    end.
+
+crl_check_same_issuer(OtpCert, best_effort, Dps, Options) ->		
+    case public_key:pkix_crls_validate(OtpCert, Dps, Options) of 
+	{bad_cert, revocation_status_undetermined}  ->
+	    valid;
+	Other ->
+	    Other
+    end;
+crl_check_same_issuer(OtpCert, _, Dps, Options) ->    
+    public_key:pkix_crls_validate(OtpCert, Dps, Options).
+
+dps_and_crls(OtpCert, Callback, CRLDbHandle, ext) ->
+	case public_key:pkix_dist_points(OtpCert) of
+	    [] ->
+		no_dps;
+	    DistPoints ->
+		distpoints_lookup(DistPoints, Callback, CRLDbHandle) 
+	end;
+    
+dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer) ->    
+    DP = #'DistributionPoint'{distributionPoint = {fullName, GenNames}} = 
+	public_key:pkix_dist_point(OtpCert),
+    CRLs = lists:flatmap(fun({directoryName, Issuer}) -> 
+				 Callback:select(Issuer, CRLDbHandle);
+			    (_) ->
+				 []
+			 end, GenNames),
+    [{DP, {CRL, public_key:der_decode('CertificateList', CRL)}} ||  CRL <- CRLs].
+
+distpoints_lookup([], _, _) ->
+    [];
+distpoints_lookup([DistPoint | Rest], Callback, CRLDbHandle) ->
+    case Callback:lookup(DistPoint, CRLDbHandle) of
+	not_available ->
+	    distpoints_lookup(Rest, Callback, CRLDbHandle);
+	CRLs ->
+	    [{DistPoint, {CRL, public_key:der_decode('CertificateList', CRL)}} ||  CRL <- CRLs]
+    end.	
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 560e24f5ce..8df79f9e8c 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -61,6 +61,8 @@
 -define(CDR_HDR_SIZE, 12).
 
 -define(DEFAULT_TIMEOUT, 5000).
+-define(NO_DIST_POINT, "http://dummy/no_distribution_point").
+-define(NO_DIST_POINT_PATH, "dummy/no_distribution_point").
 
 %% Common enumerate values in for SSL-protocols 
 -define(NULL, 0).
@@ -122,7 +124,9 @@
 	  %% the client?
 	  honor_cipher_order = false,
 	  padding_check = true,
-	  fallback = false
+	  fallback = false,
+	  crl_check, 
+	  crl_cache
 	  }).
 
 -record(socket_options,
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index bf0333ba8d..9c4b2a8bad 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -26,10 +26,11 @@
 
 %% Internal application API
 -export([start_link/1, start_link_dist/1,
-	 connection_init/2, cache_pem_file/2,
+	 connection_init/3, cache_pem_file/2,
 	 lookup_trusted_cert/4,
 	 new_session_id/1, clean_cert_db/2,
 	 register_session/2, register_session/3, invalidate_session/2,
+	 insert_crls/2, insert_crls/3, delete_crls/1, delete_crls/2, 
 	 invalidate_session/3, invalidate_pem/1, clear_pem_cache/0, manager_name/1]).
 
 % Spawn export
@@ -100,19 +101,19 @@ start_link_dist(Opts) ->
     gen_server:start_link({local, DistMangerName}, ?MODULE, [DistMangerName, Opts], []).
 
 %%--------------------------------------------------------------------
--spec connection_init(binary()| {der, list()}, client | server) ->
+-spec connection_init(binary()| {der, list()}, client | server, {Cb :: atom(), Handle:: term()}) ->
 			     {ok, certdb_ref(), db_handle(), db_handle(), db_handle(), db_handle()}.
 %%			     
 %% Description: Do necessary initializations for a new connection.
 %%--------------------------------------------------------------------
-connection_init({der, _} = Trustedcerts, Role) ->
-    call({connection_init, Trustedcerts, Role});
+connection_init({der, _} = Trustedcerts, Role, CRLCache) ->
+    call({connection_init, Trustedcerts, Role, CRLCache});
 
-connection_init(<<>> = Trustedcerts, Role) ->
-    call({connection_init, Trustedcerts, Role});
+connection_init(<<>> = Trustedcerts, Role, CRLCache) ->
+    call({connection_init, Trustedcerts, Role, CRLCache});
 
-connection_init(Trustedcerts, Role) ->
-    call({connection_init, Trustedcerts, Role}).
+connection_init(Trustedcerts, Role, CRLCache) ->
+    call({connection_init, Trustedcerts, Role, CRLCache}).
 
 %%--------------------------------------------------------------------
 -spec cache_pem_file(binary(), term()) -> {ok, term()} | {error, reason()}.
@@ -124,7 +125,7 @@ cache_pem_file(File, DbHandle) ->
 	[{Content,_}] ->
 	    {ok, Content};
 	[Content] ->
-	   {ok, Content};
+	    {ok, Content};
 	undefined ->
 	    call({cache_pem, File})
     end.
@@ -193,11 +194,28 @@ invalidate_session(Host, Port, Session) ->
 invalidate_session(Port, Session) ->
     cast({invalidate_session, Port, Session}).
 
-
 -spec invalidate_pem(File::binary()) -> ok.
 invalidate_pem(File) ->
     cast({invalidate_pem, File}).
 
+insert_crls(Path, CRLs)->
+    insert_crls(Path, CRLs, normal).
+insert_crls(?NO_DIST_POINT_PATH = Path, CRLs, ManagerType)->
+    put(ssl_manager, manager_name(ManagerType)),
+    cast({insert_crls, Path, CRLs});
+insert_crls(Path, CRLs, ManagerType)->
+    put(ssl_manager, manager_name(ManagerType)),
+    call({insert_crls, Path, CRLs}).
+
+delete_crls(Path)->
+    delete_crls(Path, normal).
+delete_crls(?NO_DIST_POINT_PATH = Path, ManagerType)->
+    put(ssl_manager, manager_name(ManagerType)),
+    cast({delete_crls, Path});
+delete_crls(Path, ManagerType)->
+    put(ssl_manager, manager_name(ManagerType)),
+    call({delete_crls, Path}).
+
 %%====================================================================
 %% gen_server callbacks
 %%====================================================================
@@ -245,50 +263,38 @@ init([Name, Opts]) ->
 %%
 %% Description: Handling call messages
 %%--------------------------------------------------------------------
-handle_call({{connection_init, <<>>, client}, _Pid}, _From,
-	    #state{certificate_db = [CertDb, FileRefDb, PemChace],
-		   session_cache_client = Cache} = State) ->
-    Result = {ok, make_ref(),CertDb, FileRefDb, PemChace, Cache},
-    {reply, Result, State};
-handle_call({{connection_init, <<>>, server}, _Pid}, _From,
-	    #state{certificate_db = [CertDb, FileRefDb, PemChace],
-		   session_cache_server = Cache} = State) ->
-    Result = {ok, make_ref(),CertDb, FileRefDb, PemChace, Cache},
-    {reply, Result, State};
-
-handle_call({{connection_init, Trustedcerts, client}, Pid}, _From,
-	    #state{certificate_db = [CertDb, FileRefDb, PemChace] = Db,
-		   session_cache_client = Cache} = State) ->
-    Result = 
-	try
-	    {ok, Ref} = ssl_pkix_db:add_trusted_certs(Pid, Trustedcerts, Db),
-	    {ok, Ref, CertDb, FileRefDb, PemChace, Cache}
-	catch
-	    _:Reason ->
-		{error, Reason}
-	end,
-    {reply, Result, State};
-handle_call({{connection_init, Trustedcerts, server}, Pid}, _From,
-	    #state{certificate_db = [CertDb, FileRefDb, PemChace] = Db,
-		   session_cache_server = Cache} = State) ->
-    Result = 
-	try
-	    {ok, Ref} = ssl_pkix_db:add_trusted_certs(Pid, Trustedcerts, Db),
-	    {ok, Ref, CertDb, FileRefDb, PemChace, Cache}
-	catch
-	    _:Reason ->
-		{error, Reason}
-	end,
-    {reply, Result, State};
-
-
-handle_call({{new_session_id,Port}, _},
+handle_call({{connection_init, <<>>, Role, {CRLCb, UserCRLDb}}, _Pid}, _From,
+	    #state{certificate_db = [CertDb, FileRefDb, PemChace | _] = Db} = State) ->
+    Ref = make_ref(), 
+    Result = {ok, Ref, CertDb, FileRefDb, PemChace, session_cache(Role, State), {CRLCb, crl_db_info(Db, UserCRLDb)}},
+    {reply, Result, State#state{certificate_db = Db}};
+
+handle_call({{connection_init, Trustedcerts, Role, {CRLCb, UserCRLDb}}, Pid}, _From,
+	    #state{certificate_db = [CertDb, FileRefDb, PemChace | _] = Db} = State) ->
+    case add_trusted_certs(Pid, Trustedcerts, Db) of
+	{ok, Ref} ->
+	    {reply, {ok, Ref, CertDb, FileRefDb, PemChace, session_cache(Role, State), 
+		     {CRLCb, crl_db_info(Db, UserCRLDb)}}, State};
+	{error, _} = Error ->
+	    {reply, Error, State}
+    end;
+
+handle_call({{insert_crls, Path, CRLs}, _}, _From,   
+	    #state{certificate_db = Db} = State) ->
+    ssl_pkix_db:add_crls(Db, Path, CRLs),
+    {reply, ok, State};
+
+handle_call({{delete_crls, CRLsOrPath}, _}, _From,   
+	    #state{certificate_db = Db} = State) ->
+    ssl_pkix_db:remove_crls(Db, CRLsOrPath),
+    {reply, ok, State};
+
+handle_call({{new_session_id, Port}, _},
 	    _, #state{session_cache_cb = CacheCb,
 		      session_cache_server = Cache} = State) ->
     Id = new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb),
     {reply, Id, State};
 
-
 handle_call({{cache_pem,File}, _Pid}, _,
 	    #state{certificate_db = Db} = State) ->
     try ssl_pkix_db:cache_pem_file(File, Db) of
@@ -298,7 +304,7 @@ handle_call({{cache_pem,File}, _Pid}, _,
 	_:Reason ->
 	    {reply, {error, Reason}, State}
     end;
-handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_,PemChace]} = State) ->
+handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_,PemChace | _]} = State) ->
     ssl_pkix_db:clear(PemChace),
     {reply, ok,  State}.
 
@@ -344,8 +350,19 @@ handle_cast({invalidate_session, Port, #session{session_id = ID} = Session},
 		   session_cache_cb = CacheCb} = State) ->
     invalidate_session(Cache, CacheCb, {Port, ID}, Session, State);
 
+
+handle_cast({insert_crls, Path, CRLs},   
+	    #state{certificate_db = Db} = State) ->
+    ssl_pkix_db:add_crls(Db, Path, CRLs),
+    {noreply, State};
+
+handle_cast({delete_crls, CRLsOrPath},   
+	    #state{certificate_db = Db} = State) ->
+    ssl_pkix_db:remove_crls(Db, CRLsOrPath),
+    {noreply, State};
+
 handle_cast({invalidate_pem, File},
-	    #state{certificate_db = [_, _, PemCache]} = State) ->
+	    #state{certificate_db = [_, _, PemCache | _]} = State) ->
     ssl_pkix_db:remove(File, PemCache),
     {noreply, State}.
 
@@ -374,7 +391,7 @@ handle_info({delayed_clean_session, Key, Cache}, #state{session_cache_cb = Cache
     CacheCb:delete(Cache, Key),
     {noreply, State};
 
-handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace],
+handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace | _],
 				    clear_pem_cache = Interval,
 				    last_pem_check = CheckPoint} = State) ->
     NewCheckPoint = os:timestamp(),
@@ -382,9 +399,8 @@ handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace],
     erlang:send_after(Interval, self(), clear_pem_cache),
     {noreply, State#state{last_pem_check = NewCheckPoint}};
 
-
 handle_info({clean_cert_db, Ref, File},
-	    #state{certificate_db = [CertDb,RefDb, PemCache]} = State) ->
+	    #state{certificate_db = [CertDb,RefDb, PemCache | _]} = State) ->
     
     case ssl_pkix_db:lookup(Ref, RefDb) of
 	undefined -> %% Alredy cleaned
@@ -606,3 +622,21 @@ is_before_checkpoint(Time, CheckPoint) ->
     calendar:datetime_to_gregorian_seconds(calendar:now_to_datetime(CheckPoint)) -
     calendar:datetime_to_gregorian_seconds(Time) > 0.
 
+add_trusted_certs(Pid, Trustedcerts, Db) ->
+    try
+	ssl_pkix_db:add_trusted_certs(Pid, Trustedcerts, Db) 	    
+    catch
+	_:Reason ->
+	    {error, Reason}
+    end.
+
+session_cache(client, #state{session_cache_client = Cache}) ->
+    Cache;
+session_cache(server, #state{session_cache_server = Cache}) ->
+    Cache.
+
+crl_db_info([_,_,_,Local], {internal, Info}) ->
+    {Local, Info};
+crl_db_info(_, UserCRLDb) ->
+    UserCRLDb.
+
diff --git a/lib/ssl/src/ssl_pkix_db.erl b/lib/ssl/src/ssl_pkix_db.erl
index 8531445ba4..d7b7e3eae3 100644
--- a/lib/ssl/src/ssl_pkix_db.erl
+++ b/lib/ssl/src/ssl_pkix_db.erl
@@ -27,9 +27,9 @@
 -include_lib("public_key/include/public_key.hrl").
 -include_lib("kernel/include/file.hrl").
 
--export([create/0, remove/1, add_trusted_certs/3, 
+-export([create/0, add_crls/3, remove_crls/2, remove/1, add_trusted_certs/3, 
 	 remove_trusted_certs/2, insert/3, remove/2, clear/1, db_size/1,
-	 ref_count/3, lookup_trusted_cert/4, foldl/3,
+	 ref_count/3, lookup_trusted_cert/4, foldl/3, select_cert_by_issuer/2,
 	 lookup_cached_pem/2, cache_pem_file/2, cache_pem_file/3,
 	 lookup/2]).
 
@@ -51,16 +51,24 @@ create() ->
      ets:new(ssl_otp_cacertificate_db, [set, public]),
      %% Let connection processes call ref_count/3 directly
      ets:new(ssl_otp_ca_file_ref, [set, public]),
-     ets:new(ssl_otp_pem_cache, [set, protected])
+     ets:new(ssl_otp_pem_cache, [set, protected]),
+     %% Default cache
+     {ets:new(ssl_otp_crl_cache, [set, protected]),
+      ets:new(ssl_otp_crl_issuer_mapping, [bag, protected])}
     ].
 
 %%--------------------------------------------------------------------
--spec remove([db_handle()]) -> ok.
+-spec remove([db_handle()]) -> ok. 
 %%
 %% Description: Removes database db  
 %%--------------------------------------------------------------------
 remove(Dbs) ->
-    lists:foreach(fun(Db) ->
+    lists:foreach(fun({Db0, Db1})  ->
+			  true = ets:delete(Db0),
+			  true = ets:delete(Db1);
+		     (undefined) -> 
+			  ok;
+		     (Db) ->
 			  true = ets:delete(Db)
 		  end, Dbs).
 
@@ -81,7 +89,7 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
 	    {ok, Certs}
     end.
 
-lookup_cached_pem([_, _, PemChache], File) ->
+lookup_cached_pem([_, _, PemChache | _], File) ->
     lookup_cached_pem(PemChache, File);
 lookup_cached_pem(PemChache, File) ->
     lookup(File, PemChache).
@@ -94,12 +102,12 @@ lookup_cached_pem(PemChache, File) ->
 %% runtime database. Returns Ref that should be handed to lookup_trusted_cert
 %% together with the cert serialnumber and issuer.
 %%--------------------------------------------------------------------
-add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) ->
+add_trusted_certs(_Pid, {der, DerList}, [CertDb, _,_ | _]) ->
     NewRef = make_ref(),
-    add_certs_from_der(DerList, NewRef, CerDb),
+    add_certs_from_der(DerList, NewRef, CertDb),
     {ok, NewRef};
 
-add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) ->
+add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache | _] = Db) ->
     case lookup_cached_pem(Db, File) of
 	[{_Content, Ref}] ->
 	    ref_count(Ref, RefDb, 1),
@@ -118,14 +126,15 @@ add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) ->
 %% Description: Cache file as binary in DB
 %%--------------------------------------------------------------------
 -spec cache_pem_file(binary(), [db_handle()]) -> {ok, term()}.
-cache_pem_file(File, [_CertsDb, _RefDb, PemChache]) ->
+cache_pem_file(File, [_CertsDb, _RefDb, PemChache | _]) ->
     {ok, PemBin} = file:read_file(File),
     Content = public_key:pem_decode(PemBin),
     insert(File, Content, PemChache),
     {ok, Content}.
 
+
 -spec cache_pem_file(reference(), binary(), [db_handle()]) -> {ok, term()}.
-cache_pem_file(Ref, File, [_CertsDb, _RefDb, PemChache]) ->
+cache_pem_file(Ref, File, [_CertsDb, _RefDb, PemChache| _]) ->
     {ok, PemBin} = file:read_file(File),
     Content = public_key:pem_decode(PemBin),
     insert(File, {Content, Ref}, PemChache),
@@ -148,6 +157,15 @@ remove(Key, Db) ->
     ets:delete(Db, Key),
     ok.
 
+%%--------------------------------------------------------------------
+-spec remove(term(), term(), db_handle()) -> ok.
+%%
+%% Description: Removes an element in a <Db>.
+%%--------------------------------------------------------------------
+remove(Key, Data, Db) ->
+    ets:delete_object(Db, {Key, Data}),
+    ok.
+
 %%--------------------------------------------------------------------
 -spec lookup(term(), db_handle()) -> [term()] | undefined.
 %%
@@ -175,6 +193,10 @@ lookup(Key, Db) ->
 foldl(Fun, Acc0, Cache) ->
     ets:foldl(Fun, Acc0, Cache).
 
+
+select_cert_by_issuer(Cache, Issuer) ->    
+    ets:select(Cache, [{{{'_','_', Issuer},{'_', '$1'}},[],['$$']}]).
+
 %%--------------------------------------------------------------------
 -spec ref_count(term(), db_handle(), integer()) -> integer().
 %%
@@ -244,9 +266,39 @@ add_certs(Cert, Ref, CertsDb) ->
 	    error_logger:info_report(Report)
     end.
 
-new_trusted_cert_entry(File, [CertsDb, RefDb, _] = Db) ->
+new_trusted_cert_entry(File, [CertsDb, RefDb, _ | _] = Db) ->
     Ref = make_ref(),
     update_counter(Ref, 1, RefDb),
     {ok, Content} = cache_pem_file(Ref, File, Db),
     add_certs_from_pem(Content, Ref, CertsDb),
     {ok, Ref}.
+
+add_crls([_,_,_, {_, Mapping} | _], ?NO_DIST_POINT, CRLs) ->
+    [add_crls(CRL, Mapping) || CRL <- CRLs];
+add_crls([_,_,_, {Cache, Mapping} | _], Path, CRLs) ->
+    insert(Path, CRLs, Cache), 
+    [add_crls(CRL, Mapping) || CRL <- CRLs].
+
+add_crls(CRL, Mapping) ->
+    insert(crl_issuer(CRL), CRL, Mapping).
+
+remove_crls([_,_,_, {_, Mapping} | _], {?NO_DIST_POINT, CRLs}) ->
+    [rm_crls(CRL, Mapping) || CRL <- CRLs];
+	
+remove_crls([_,_,_, {Cache, Mapping} | _], Path) ->
+    case lookup(Path, Cache) of
+	undefined ->
+	    ok;
+	CRLs ->
+	    remove(Path, Cache),
+	    [rm_crls(CRL, Mapping) || CRL <- CRLs]
+    end.
+
+rm_crls(CRL, Mapping) ->
+   remove(crl_issuer(CRL), CRL, Mapping). 
+
+crl_issuer(DerCRL) ->
+    CRL = public_key:der_decode('CertificateList', DerCRL),
+    TBSCRL = CRL#'CertificateList'.tbsCertList,
+    TBSCRL#'TBSCertList'.issuer.
+
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index 15a7e118ff..77631f62d3 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %% 
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
 %% 
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -324,8 +324,9 @@ eval_cmd(Port, Cmd) ->
 	    ok
     end,
     receive
-	{Port, {exit_status, Status}} when Status /= 0 ->
-	    %% io:fwrite("exit status: ~w~n", [Status]),
+	{Port, {exit_status, 0}}  ->
+	    ok;
+	{Port, {exit_status, Status}} ->
 	    exit({eval_cmd, Cmd, Status})
     after 0 ->
 	    ok
@@ -369,7 +370,7 @@ req_cnf(C) ->
      "subjectKeyIdentifier = hash\n"
      "subjectAltName	= email:copy\n"].
 
-ca_cnf(C) ->
+ca_cnf(C = #config{issuing_distribution_point = true}) ->
     ["# Purpose: Configuration for CAs.\n"
      "\n"
      "ROOTDIR	        = $ENV::ROOTDIR\n"
@@ -446,5 +447,83 @@ ca_cnf(C) ->
      "subjectAltName	= email:copy\n"
      "issuerAltName	= issuer:copy\n"
      "crlDistributionPoints=@crl_section\n"
-    ].
+    ];
 
+ca_cnf(C = #config{issuing_distribution_point = false}) ->
+    ["# Purpose: Configuration for CAs.\n"
+     "\n"
+     "ROOTDIR	        = $ENV::ROOTDIR\n"
+     "default_ca	= ca\n"
+     "\n"
+
+     "[ca]\n"
+     "dir		= $ROOTDIR/", C#config.commonName, "\n"
+     "certs		= $dir/certs\n"
+     "crl_dir	        = $dir/crl\n"
+     "database	        = $dir/index.txt\n"
+     "new_certs_dir	= $dir/newcerts\n"
+     "certificate	= $dir/cert.pem\n"
+     "serial		= $dir/serial\n"
+     "crl		= $dir/crl.pem\n",
+     ["crlnumber		= $dir/crlnumber\n" || C#config.v2_crls],
+     "private_key	= $dir/private/key.pem\n"
+     "RANDFILE	        = $dir/private/RAND\n"
+     "\n"
+     "x509_extensions   = user_cert\n",
+     ["crl_extensions = crl_ext\n" || C#config.v2_crls],
+     "unique_subject  = no\n"
+     "default_days	= 3600\n"
+     "default_md	= md5\n"
+     "preserve	        = no\n"
+     "policy		= policy_match\n"
+     "\n"
+
+     "[policy_match]\n"
+     "commonName		= supplied\n"
+     "organizationalUnitName	= optional\n"
+     "organizationName	        = match\n"
+     "countryName		= match\n"
+     "localityName		= match\n"
+     "emailAddress		= supplied\n"
+     "\n"
+
+     "[crl_ext]\n"
+     "authorityKeyIdentifier=keyid:always,issuer:always\n",
+     %["issuingDistributionPoint=critical, @idpsec\n" || C#config.issuing_distribution_point],
+
+     %"[idpsec]\n"
+     %"fullname=URI:http://localhost:8000/",C#config.commonName,"/crl.pem\n"
+
+     "[user_cert]\n"
+     "basicConstraints	= CA:false\n"
+     "keyUsage 		= nonRepudiation, digitalSignature, keyEncipherment\n"
+     "subjectKeyIdentifier = hash\n"
+     "authorityKeyIdentifier = keyid,issuer:always\n"
+     "subjectAltName	= email:copy\n"
+     "issuerAltName	= issuer:copy\n"
+     %"crlDistributionPoints=@crl_section\n"
+
+     %%"[crl_section]\n"
+     %% intentionally invalid
+     %%"URI.1=http://localhost/",C#config.commonName,"/crl.pem\n"
+     %%"URI.2=http://localhost:",integer_to_list(C#config.crl_port),"/",C#config.commonName,"/crl.pem\n"
+     %%"\n"
+
+     "[user_cert_digital_signature_only]\n"
+     "basicConstraints	= CA:false\n"
+     "keyUsage 		= digitalSignature\n"
+     "subjectKeyIdentifier = hash\n"
+     "authorityKeyIdentifier = keyid,issuer:always\n"
+     "subjectAltName	= email:copy\n"
+     "issuerAltName	= issuer:copy\n"
+     "\n"
+
+     "[ca_cert]\n"
+     "basicConstraints 	= critical,CA:true\n"
+     "keyUsage 		= cRLSign, keyCertSign\n"
+     "subjectKeyIdentifier = hash\n"
+     "authorityKeyIdentifier = keyid:always,issuer:always\n"
+     "subjectAltName	= email:copy\n"
+     "issuerAltName	= issuer:copy\n"
+     %"crlDistributionPoints=@crl_section\n"
+    ].
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 3fcc5d2ee7..50d5fb411f 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -638,7 +638,7 @@ clear_pem_cache(Config) when is_list(Config) ->
     {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
     [_, _,_, _, Prop] = StatusInfo,
     State = ssl_test_lib:state(Prop),
-    [_,FilRefDb, _] = element(6, State),
+    [_,FilRefDb |_] = element(6, State),
     {Server, Client} = basic_verify_test_no_close(Config),
     2 = ets:info(FilRefDb, size), 
     ssl:clear_pem_cache(),
diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl
index bad0949ec4..c6bf8898ad 100644
--- a/lib/ssl/test/ssl_crl_SUITE.erl
+++ b/lib/ssl/test/ssl_crl_SUITE.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
 %%
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -26,43 +26,40 @@
 -include_lib("common_test/include/ct.hrl").
 -include_lib("public_key/include/public_key.hrl").
 
--define(TIMEOUT, 120000).
 -define(LONG_TIMEOUT, 600000).
--define(SLEEP, 1000).
--define(OPENSSL_RENEGOTIATE, "R\n").
--define(OPENSSL_QUIT, "Q\n").
--define(OPENSSL_GARBAGE, "P\n").
--define(EXPIRE, 10).
 
 %%--------------------------------------------------------------------
 %% Common Test interface functions -----------------------------------
 %%--------------------------------------------------------------------
 
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() -> 
+    [{ct_hooks,[ts_install_cth]}].
 
 all() -> 
     [
-     {group, basic},
-     {group, v1_crl},
-     {group, idp_crl}
+     {group, check_true},
+     {group, check_peer},
+     {group, check_best_effort}
     ].
 
 groups() ->
-    [{basic,   [], basic_tests()},
-     {v1_crl,  [], v1_crl_tests()},
-     {idp_crl, [], idp_crl_tests()}].
+    [
+     {check_true, [],  [{group, v2_crl},
+			{group, v1_crl},
+			{group, idp_crl}]},
+     {check_peer, [],   [{group, v2_crl},
+			 {group, v1_crl},
+			 {group, idp_crl}]},
+     {check_best_effort, [], [{group, v2_crl},
+			       {group, v1_crl},
+			      {group, idp_crl}]},
+     {v2_crl,  [], basic_tests()},
+     {v1_crl,  [], basic_tests()},
+     {idp_crl, [], basic_tests()}].
 
 basic_tests() ->
     [crl_verify_valid, crl_verify_revoked].
 
-v1_crl_tests() ->
-    [crl_verify_valid, crl_verify_revoked].
-
-idp_crl_tests() ->
-    [crl_verify_valid, crl_verify_revoked].
-
-%%%================================================================
-%%% Suite init/end
 
 init_per_suite(Config0) ->
     Dog = ct:timetrap(?LONG_TIMEOUT *2),
@@ -70,10 +67,7 @@ init_per_suite(Config0) ->
 	false ->
 	    {skip, "Openssl not found"};
 	_ ->
-	    TLSVersion = ?config(tls_version, Config0),
 	    OpenSSL_version = (catch os:cmd("openssl version")),
-	    ct:log("TLS version: ~p~nOpenSSL version: ~p~n~n~p:module_info(): ~p~n~nssl:module_info(): ~p~n",
-		   [TLSVersion, OpenSSL_version, ?MODULE, ?MODULE:module_info(), ssl:module_info()]),
 	    case ssl_test_lib:enough_openssl_crl_support(OpenSSL_version) of
 		false ->
 		    {skip, io_lib:format("Bad openssl version: ~p",[OpenSSL_version])};
@@ -81,7 +75,6 @@ init_per_suite(Config0) ->
 		    catch crypto:stop(),
 		    try crypto:start() of
 			ok ->
-			    ssl:start(),
 			    {ok, Hostname0} = inet:gethostname(),
 			    IPfamily =
 				case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts,[])) of
@@ -89,8 +82,7 @@ init_per_suite(Config0) ->
 				    false -> inet
 				end,
 			    [{ipfamily,IPfamily}, {watchdog, Dog}, {openssl_version,OpenSSL_version} | Config0]
-		    catch _C:_E ->
-			    ct:log("crypto:start() caught ~p:~p",[_C,_E]),
+		    catch _:_ ->
 			    {skip, "Crypto did not start"}
 		    end
 	    end
@@ -100,443 +92,175 @@ end_per_suite(_Config) ->
     ssl:stop(),
     application:stop(crypto).
 
-%%%================================================================
-%%% Group init/end
-
-init_per_group(Group, Config) ->
-    ssl:start(),
-    inets:start(),
-    CertDir = filename:join(?config(priv_dir, Config), Group),
-    DataDir = ?config(data_dir, Config),
-    ServerRoot = make_dir_path([?config(priv_dir,Config), Group, tmp]),
-    %% start a HTTP server to serve the CRLs
-    {ok, Httpd} = inets:start(httpd, [{ipfamily, ?config(ipfamily,Config)},
-				      {server_name, "localhost"}, {port, 0},
-				      {server_root, ServerRoot},
-				      {document_root, CertDir},
-				      {modules, [mod_get]}
-				     ]),
-    [{port,Port}] = httpd:info(Httpd, [port]),
-    ct:log("~p:~p~nHTTPD IP family=~p, port=~p~n", [?MODULE, ?LINE, ?config(ipfamily,Config), Port]),
-    CertOpts =  [{crl_port,Port}|cert_opts(Group)],
-    Result =  make_certs:all(DataDir, CertDir, CertOpts),
-    ct:log("~p:~p~nmake_certs:all(~n DataDir=~p,~n CertDir=~p,~n ServerRoot=~p~n Opts=~p~n) returned ~p~n", [?MODULE,?LINE,DataDir, CertDir, ServerRoot, CertOpts, Result]),
-    [{make_cert_result, Result}, {cert_dir, CertDir}, {httpd, Httpd} | Config].
-
-cert_opts(v1_crl)  -> [{v2_crls, false}];
-cert_opts(idp_crl) -> [{issuing_distribution_point, true}];
-cert_opts(_) -> [].
-
-make_dir_path(PathComponents) ->
-    lists:foldl(fun(F,P0) -> file:make_dir(P=filename:join(P0,F)), P end,
-		"",
-		PathComponents).
-
+init_per_group(check_true, Config) ->
+    [{crl_check, true} | Config];
+init_per_group(check_peer, Config) ->
+    [{crl_check, peer} | Config];
+init_per_group(check_best_effort, Config) ->
+    [{crl_check, best_effort} | Config];
+init_per_group(Group, Config0) ->
+    case is_idp(Group) of
+	true ->
+	    [{idp_crl, true} | Config0];
+	false ->
+	    DataDir = ?config(data_dir, Config0), 
+	    CertDir = filename:join(?config(priv_dir, Config0), Group),
+	    {CertOpts, Config} = init_certs(CertDir, Group, Config0),
+	    Result =  make_certs:all(DataDir, CertDir, CertOpts),
+	    [{make_cert_result, Result}, {cert_dir, CertDir}, {idp_crl, false} | Config]
+    end.
 
 end_per_group(_GroupName, Config) ->
-    case ?config(httpd, Config) of
-	undefined -> ok;
-	Pid -> 
-	    ct:log("Stop httpd ~p",[Pid]),
-	   ok = inets:stop(httpd, Pid)
-		,ct:log("Stopped",[])
-    end,
-    inets:stop(),
+    
     Config.
 
+init_per_testcase(Case, Config0) ->
+    case ?config(idp_crl, Config0) of
+	true ->
+	    end_per_testcase(Case, Config0),
+	    inets:start(),
+	    ssl:start(),
+	    ServerRoot = make_dir_path([?config(priv_dir, Config0), idp_crl, tmp]),
+	    %% start a HTTP server to serve the CRLs
+	    {ok, Httpd} = inets:start(httpd, [{ipfamily, ?config(ipfamily, Config0)},
+					      {server_name, "localhost"}, {port, 0},
+					      {server_root, ServerRoot},
+					      {document_root, 
+					       filename:join(?config(priv_dir, Config0), idp_crl)}
+					     ]),
+	    [{port,Port}] = httpd:info(Httpd, [port]),
+	    Config = [{httpd_port, Port} | Config0],
+	    DataDir = ?config(data_dir, Config), 
+	    CertDir = filename:join(?config(priv_dir, Config0), idp_crl),
+	    {CertOpts, Config} = init_certs(CertDir, idp_crl, Config),
+	    Result =  make_certs:all(DataDir, CertDir, CertOpts),
+	    [{make_cert_result, Result}, {cert_dir, CertDir} | Config];
+	false ->
+	    end_per_testcase(Case, Config0),
+	    ssl:start(),
+	    Config0
+    end.
+
+end_per_testcase(_, Config) ->
+    case ?config(idp_crl, Config) of
+	true ->
+	    ssl:stop(),
+	    inets:stop();
+	false ->
+	    ssl:stop()
+    end.
+
 %%%================================================================
 %%% Test cases
+%%%================================================================
 
 crl_verify_valid() ->
     [{doc,"Verify a simple valid CRL chain"}].
 crl_verify_valid(Config) when is_list(Config) ->
-    process_flag(trap_exit, true),
     PrivDir = ?config(cert_dir, Config),
-    ServerOpts = [{keyfile, filename:join([PrivDir, "server", "key.pem"])},
-		  {certfile, filename:join([PrivDir, "server", "cert.pem"])},
-		  {cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}],
-
+    Check = ?config(crl_check, Config),
+    ServerOpts =  [{keyfile, filename:join([PrivDir, "server", "key.pem"])},
+      		  {certfile, filename:join([PrivDir, "server", "cert.pem"])},
+		   {cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}],
+    ClientOpts =  case ?config(idp_crl, Config) of 
+		      true ->	       
+			  [{cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])},
+			   {crl_check, Check},
+			   {crl_cache, {ssl_crl_cache, {internal, [{http, 5000}]}}},
+			   {verify, verify_peer}];
+		      false ->
+			  [{cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])},
+			   {crl_check, Check},
+			   {verify, verify_peer}]
+		  end,			  
     {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-    Data = "From openssl to erlang",
 
-    Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 
-					{from, self()}, 
-			   {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
-			   %{mfa, {ssl_test_lib, no_result, []}},
-			   {options, ServerOpts}]),
-    ct:log("~p:~p~nreturn from ssl_test_lib:start_server:~n~p",[?MODULE,?LINE,Server]),
-    Port = ssl_test_lib:inet_port(Server),
-
-    CACerts = load_cert(filename:join([PrivDir, "erlangCA", "cacerts.pem"])),
-
-    ClientOpts = [{cacerts, CACerts},
-		  {verify, verify_peer},
-		  {verify_fun, {fun validate_function/3, {CACerts, []}}}],
-
-
-    ct:log("~p:~p~ncalling ssl_test_lib:start_client",[?MODULE,?LINE]),
-    Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 
-					{host, Hostname},
-					{from, self()}, 
-					{mfa, {?MODULE, 
-					       erlang_ssl_send, [Data]}},
-					%{mfa, {ssl_test_lib, no_result, []}},
-					{options, ClientOpts}]),
-    ct:log("~p:~p~nreturn from ssl_test_lib:start_client:~n~p",[?MODULE,?LINE,Client]),
-
-    ssl_test_lib:check_result(Client, ok,  Server, ok),
-
-    %% Clean close down!   Server needs to be closed first !!
-    ssl_test_lib:close(Server),
-    ssl_test_lib:close(Client),
-    process_flag(trap_exit, false).
+    ssl_crl_cache:insert({file, filename:join([PrivDir, "erlangCA", "crl.pem"])}),
+    ssl_crl_cache:insert({file, filename:join([PrivDir, "otpCA", "crl.pem"])}),
+    
+    crl_verify_valid(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts).
 
 crl_verify_revoked() ->
-    [{doc,"Verify a simple valid CRL chain"}].
-crl_verify_revoked(Config) when is_list(Config) ->
-    process_flag(trap_exit, true),
+    [{doc,"Verify a simple CRL chain when peer cert is reveoked"}].
+crl_verify_revoked(Config)  when is_list(Config) ->
     PrivDir = ?config(cert_dir, Config),
+    Check = ?config(crl_check, Config),
     ServerOpts = [{keyfile, filename:join([PrivDir, "revoked", "key.pem"])},
-		  {certfile, filename:join([PrivDir, "revoked", "cert.pem"])},
-		  {cacertfile, filename:join([PrivDir, "revoked", "cacerts.pem"])}],
-    ct:log("~p:~p~nserver opts ~p~n", [?MODULE,?LINE, ServerOpts]),
+      		  {certfile, filename:join([PrivDir, "revoked", "cert.pem"])},
+      		  {cacertfile, filename:join([PrivDir, "revoked", "cacerts.pem"])}],
 
     {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
 
-    Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 
-					{from, self()}, 
-			   %{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
-			   {mfa, {ssl_test_lib, no_result, []}},
-			   {options, ServerOpts}]),
+    Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, 
+					      {from, self()}, 
+					      {options, ServerOpts}]),
     Port = ssl_test_lib:inet_port(Server),
+    
+    ssl_crl_cache:insert({file, filename:join([PrivDir, "erlangCA", "crl.pem"])}),
+    ssl_crl_cache:insert({file, filename:join([PrivDir, "otpCA", "crl.pem"])}),
+    
+    ClientOpts =  case ?config(idp_crl, Config) of 
+		      true ->	       
+			  [{cacertfile, filename:join([PrivDir, "revoked", "cacerts.pem"])},
+			   {crl_cache, {ssl_crl_cache, {internal, [{http, 5000}]}}},
+			   {crl_check, Check},
+			   {verify, verify_peer}];
+		      false ->
+			  [{cacertfile, filename:join([PrivDir, "revoked", "cacerts.pem"])},
+			   {crl_check, Check},
+			   {verify, verify_peer}]
+		  end,	
+    
+    Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, 
+     					      {host, Hostname},
+   					      {from, self()}, 
+     					      {options, ClientOpts}]),
+    receive
+	{Server, AlertOrColse} ->
+	    ct:pal("Server Alert or Close ~p", [AlertOrColse])
+    end,	    
+    ssl_test_lib:check_result(Client, {error, {tls_alert, "certificate revoked"}}).
 
-    CACerts = load_cert(filename:join([PrivDir, "erlangCA", "cacerts.pem"])),
-    ClientOpts = [{cacerts, CACerts},
-		  {verify, verify_peer},
-		  {verify_fun, {fun validate_function/3, {CACerts, []}}}],
 
-    {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 
+crl_verify_valid(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts) ->
+    Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 
+					{from, self()}, 
+					{mfa, {ssl_test_lib, 
+					       send_recv_result_active, []}},				       
+					{options, ServerOpts}]),
+    Port = ssl_test_lib:inet_port(Server), 
+    Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 
 					{host, Hostname},
 					{from, self()}, 
-					%{mfa, {?MODULE, 
-					       %erlang_ssl_receive, [Data]}},
-					{mfa, {ssl_test_lib, no_result, []}},
+					{mfa, {ssl_test_lib, 
+					       send_recv_result_active, []}},
 					{options, ClientOpts}]),
+    
+    ssl_test_lib:check_result(Client, ok,  Server, ok),
 
-    %% Clean close down!   Server needs to be closed first !!
     ssl_test_lib:close(Server),
-    process_flag(trap_exit, false).
-
-%%%================================================================
-%%% Lib
-
-erlang_ssl_receive(Socket, Data) ->
-    ct:log("~p:~p~nConnection info: ~p~n",
-		       [?MODULE,?LINE, ssl:connection_info(Socket)]),
-    receive
-	{ssl, Socket, Data} ->
-	    ct:log("~p:~p~nReceived ~p~n",[?MODULE,?LINE, Data]),
-	    %% open_ssl server sometimes hangs waiting in blocking read
-	    ssl:send(Socket, "Got it"), 
-	    ok;
-	{ssl, Socket, Byte} when length(Byte) == 1 ->
-	    erlang_ssl_receive(Socket, tl(Data));
-	{Port, {data,Debug}} when is_port(Port) ->
-	    ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
-	    erlang_ssl_receive(Socket,Data);
-	Other ->
-	    ct:fail({unexpected_message, Other})
-    after 4000 ->
-	    ct:fail({did_not_get, Data})
-    end.
-
-
-erlang_ssl_send(Socket, Data) ->
-    ct:log("~p:~p~nConnection info: ~p~n",
-		       [?MODULE,?LINE, ssl:connection_info(Socket)]),
-    ssl:send(Socket, Data),
-    ok.
-
-load_certs(undefined) ->
-    undefined;
-load_certs(CertDir) ->
-    case file:list_dir(CertDir) of
-        {ok, Certs} ->
-            load_certs(lists:map(fun(Cert) -> filename:join(CertDir, Cert)
-                    end, Certs), []);
-        {error, _} ->
-            undefined
-    end.
-
-load_certs([], Acc) ->
-    ct:log("~p:~p~nSuccessfully loaded ~p CA certificates~n", [?MODULE,?LINE, length(Acc)]),
-    Acc;
-load_certs([Cert|Certs], Acc) ->
-    case filelib:is_dir(Cert) of
-        true ->
-            load_certs(Certs, Acc);
-        _ ->
-            %ct:log("~p:~p~nLoading certificate ~p~n", [?MODULE,?LINE, Cert]),
-            load_certs(Certs, load_cert(Cert) ++ Acc)
-    end.
-
-load_cert(Cert) ->
-    {ok, Bin} = file:read_file(Cert),
-    case filename:extension(Cert) of
-        ".der" ->
-            %% no decoding necessary
-            [Bin];
-        _ ->
-            %% assume PEM otherwise
-            Contents = public_key:pem_decode(Bin),
-            [DER || {Type, DER, Cipher} <- Contents, Type == 'Certificate', Cipher == 'not_encrypted']
-    end.
-
-%% @doc Validator function for SSL negotiation.
-%%
-validate_function(Cert, valid_peer, State) ->
-    ct:log("~p:~p~nvaliding peer ~p with ~p intermediate certs~n",
-                [?MODULE,?LINE, get_common_name(Cert), 
-                 length(element(2, State))]),
-    %% peer certificate validated, now check the CRL
-    Res = (catch check_crl(Cert, State)),
-    ct:log("~p:~p~nCRL validate result for ~p: ~p~n",
-                [?MODULE,?LINE, get_common_name(Cert), Res]),
-    {Res, State};
-validate_function(Cert, valid, {TrustedCAs, IntermediateCerts}=State) ->
-    case public_key:pkix_is_self_signed(Cert) of
-        true ->
-            ct:log("~p:~p~nroot certificate~n",[?MODULE,?LINE]),
-            %% this is a root cert, no CRL
-            {valid, {TrustedCAs, [Cert|IntermediateCerts]}};
-        false ->
-            %% check is valid CA certificate, add to the list of
-            %% intermediates
-            Res = (catch check_crl(Cert, State)),
-            ct:log("~p:~p~nCRL intermediate CA validate result for ~p: ~p~n",
-                        [?MODULE,?LINE, get_common_name(Cert), Res]),
-            {Res, {TrustedCAs, [Cert|IntermediateCerts]}}
-    end;
-validate_function(_Cert, _Event, State) ->
-    %ct:log("~p:~p~nignoring event ~p~n", [?MODULE,?LINE, _Event]),
-    {valid, State}.
+    ssl_test_lib:close(Client).
 
-%% @doc Given a certificate, find CRL distribution points for the given
-%%      certificate, fetch, and attempt to validate each CRL through
-%%      issuer_function/4.
-%%
-check_crl(Cert, State) ->
-    %% pull the CRL distribution point(s) out of the certificate, if any
-    ct:log("~p:~p~ncheck_crl(~n Cert=~p,~nState=~p~n)",[?MODULE,?LINE,Cert,State]),
-    case pubkey_cert:select_extension(
-	   ?'id-ce-cRLDistributionPoints',
-	   pubkey_cert:extensions_list(Cert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.extensions)) of
-        undefined ->
-            ct:log("~p:~p~nno CRL distribution points for ~p~n",
-                         [?MODULE,?LINE, get_common_name(Cert)]),
-            %% fail; we can't validate if there's no CRL
-            no_crl;
-        CRLExtension ->
-	    ct:log("~p:~p~nCRLExtension=~p)",[?MODULE,?LINE,CRLExtension]),
-            CRLDistPoints = CRLExtension#'Extension'.extnValue,
-            DPointsAndCRLs = lists:foldl(fun(Point, Acc) -> 
-                            %% try to read the CRL over http or from a
-                            %% local file
-                            case fetch_point(Point) of
-                                not_available ->
-				    ct:log("~p:~p~nfetch_point returned~n~p~n)",[?MODULE,?LINE,not_available]),
-                                    Acc;
-                                Res ->
-				    ct:log("~p:~p~nfetch_point returned~n~p~n)",[?MODULE,?LINE,Res]),
-                                    [{Point, Res} | Acc]
-                            end 
-                    end, [], CRLDistPoints),
-            public_key:pkix_crls_validate(Cert, 
-                                          DPointsAndCRLs, 
-                                          [{issuer_fun, 
-                                            {fun issuer_function/4, State}}])
-    end.
-
-%% @doc Given a list of distribution points for CRLs, certificates and
-%%      both trusted and intermediary certificates, attempt to build and
-%%      authority chain back via build_chain to verify that it is valid.
-%%
-issuer_function(_DP, CRL, _Issuer, {TrustedCAs, IntermediateCerts}) ->
-    %% XXX the 'Issuer' we get passed here is the AuthorityKeyIdentifier,
-    %% which we are not currently smart enough to understand
-    %% Read the CA certs out of the file
-    ct:log("~p:~p~nissuer_function(~nCRL=~p,~nLast param=~p)",[?MODULE,?LINE,CRL, {TrustedCAs, IntermediateCerts}]),
-    Certs = [public_key:pkix_decode_cert(DER, otp) || DER <- TrustedCAs],
-    %% get the real issuer out of the CRL
-    Issuer = public_key:pkix_normalize_name(
-            pubkey_cert_records:transform(
-                CRL#'CertificateList'.tbsCertList#'TBSCertList'.issuer, decode)),
-    %% assume certificates are ordered from root to tip
-    case find_issuer(Issuer, IntermediateCerts ++ Certs) of
-        undefined ->
-            ct:log("~p:~p~nunable to find certificate matching CRL issuer ~p~n", 
-                        [?MODULE,?LINE, Issuer]),
-            error;
-        IssuerCert ->
-	    ct:log("~p:~p~nIssuerCert=~p~n)",[?MODULE,?LINE,IssuerCert]),
-            case build_chain({public_key:pkix_encode('OTPCertificate', 
-                                                     IssuerCert, 
-                                                     otp), 
-                              IssuerCert}, IntermediateCerts, Certs, []) of
-                undefined ->
-                    error;
-                {OTPCert, Path} ->
-                    {ok, OTPCert, Path}
-            end
-    end.
-
-%% @doc Attempt to build authority chain back using intermediary
-%%      certificates, falling back on trusted certificates if the
-%%      intermediary chain of certificates does not fully extend to the 
-%%      root.
-%% 
-%%      Returns: {RootCA :: #OTPCertificate{}, Chain :: [der_encoded()]}
-%%
-build_chain({DER, Cert}, IntCerts, TrustedCerts, Acc) ->
-    %% check if this cert is self-signed, if it is, we've reached the
-    %% root of the chain
-    Issuer = public_key:pkix_normalize_name(
-            Cert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.issuer),
-    Subject = public_key:pkix_normalize_name(
-            Cert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject),
-    case Issuer == Subject of
-        true ->
-            case find_issuer(Issuer, TrustedCerts) of
-                undefined ->
-                    ct:log("~p:~p~nself-signed certificate is NOT trusted~n",[?MODULE,?LINE]),
-                    undefined;
-                TrustedCert ->
-                    %% return the cert from the trusted list, to prevent
-                    %% issuer spoofing
-                    {TrustedCert, 
-                     [public_key:pkix_encode(
-                                'OTPCertificate', TrustedCert, otp)|Acc]}
-            end;
-        false ->
-            Match = lists:foldl(
-                      fun(C, undefined) ->
-                              S = public_key:pkix_normalize_name(C#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject),
-                              %% compare the subject to the current issuer
-                              case Issuer == S of
-                                  true ->
-                                      %% we've found our man
-                                      {public_key:pkix_encode('OTPCertificate', C, otp), C};
-                                  false ->
-                                      undefined
-                              end;
-                         (_E, A) ->
-                              %% already matched
-                              A
-                      end, undefined, IntCerts),
-            case Match of
-                undefined when IntCerts /= TrustedCerts ->
-                    %% continue the chain by using the trusted CAs
-                    ct:log("~p:~p~nRan out of intermediate certs, switching to trusted certs~n",[?MODULE,?LINE]),
-                    build_chain({DER, Cert}, TrustedCerts, TrustedCerts, Acc);
-                undefined ->
-                    ct:log("Can't construct chain of trust beyond ~p~n",
-                                [?MODULE,?LINE, get_common_name(Cert)]),
-                    %% can't find the current cert's issuer
-                    undefined;
-                Match ->
-                    build_chain(Match, IntCerts, TrustedCerts, [DER|Acc])
-            end
-    end.
-
-%% @doc Given a certificate and a list of trusted or intermediary
-%%      certificates, attempt to find a match in the list or bail with
-%%      undefined.
-find_issuer(Issuer, Certs) ->
-    lists:foldl(
-      fun(OTPCert, undefined) ->
-              %% check if this certificate matches the issuer
-              Normal = public_key:pkix_normalize_name(
-                        OTPCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject),
-              case Normal == Issuer of
-                  true ->
-                      OTPCert;
-                  false ->
-                      undefined
-              end;
-         (_E, Acc) ->
-              %% already found a match
-              Acc
-      end, undefined, Certs).
-
-%% @doc Find distribution points for a given CRL and then attempt to
-%%      fetch the CRL from the first available.
-fetch_point(#'DistributionPoint'{distributionPoint={fullName, Names}}) ->
-    Decoded = [{NameType, 
-                pubkey_cert_records:transform(Name, decode)} 
-               || {NameType, Name} <- Names],
-    ct:log("~p:~p~ncall fetch(~nDecoded=~p~n)",[?MODULE,?LINE,Decoded]),
-    fetch(Decoded).
-
-%% @doc Given a list of locations to retrieve a CRL from, attempt to
-%%      retrieve either from a file or http resource and bail as soon as
-%%      it can be found.
-%%
-%%      Currently, only hand a armored PEM or DER encoded file, with
-%%      defaulting to DER.
-%%
-fetch([]) ->
-    not_available;
-fetch([{uniformResourceIdentifier, "http"++_=URL}|Rest]) ->
-    ct:log("~p:~p~ngetting CRL from ~p~n", [?MODULE,?LINE, URL]),
-    case httpc:request(get, {URL, []}, [], [{body_format, binary}]) of
-        {ok, {_Status, _Headers, Body}} ->
-            case Body of
-                <<"-----BEGIN", _/binary>> ->
-		    ct:log("~p:~p~npublic_key:pem_decode,~nBody=~p~n)",[?MODULE,?LINE,Body]),
-                    [{'CertificateList', 
-                      DER, _}=CertList] = public_key:pem_decode(Body),
-		    ct:log("~p:~p~npublic_key:pem_entry_decode,~nCertList=~p~n)",[?MODULE,?LINE,CertList]),
-                    {DER, public_key:pem_entry_decode(CertList)};
-                _ ->
-		    ct:log("~p:~p~npublic_key:pem_entry_decode,~nBody=~p~n)",[?MODULE,?LINE,{'CertificateList', Body, not_encrypted}]),
-                    %% assume DER encoded
-		    try 
-			public_key:pem_entry_decode({'CertificateList', Body, not_encrypted})
-		    of 
-			CertList -> {Body, CertList}
-		    catch
-			_C:_E ->
-			    ct:log("~p:~p~nfailed DER assumption~nRest=~p", [?MODULE,?LINE,Rest]),
-			    fetch(Rest)
-		    end
-            end;
-        {error, _Reason} ->
-            ct:log("~p:~p~nfailed to get CRL ~p~n", [?MODULE,?LINE, _Reason]),
-            fetch(Rest);
-	Other ->
-            ct:log("~p:~p~nreally failed to get CRL ~p~n", [?MODULE,?LINE, Other]),
-            fetch(Rest)
-    end;
-fetch([Loc|Rest]) ->
-    %% unsupported CRL location
-    ct:log("~p:~p~nunable to fetch CRL from unsupported location ~p~n", 
-                [?MODULE,?LINE, Loc]),
-    fetch(Rest).
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+is_idp(idp_crl) ->
+    true;
+is_idp(_) ->
+    false.
+
+init_certs(_,v1_crl, Config)  -> 
+    {[{v2_crls, false}], Config};
+init_certs(_, idp_crl, Config) -> 
+    Port = ?config(httpd_port, Config),
+    {[{crl_port,Port},
+      {issuing_distribution_point, true}], Config
+    };
+init_certs(_,_,Config) -> 
+    {[], Config}.
 
-%% get the common name attribute out of an OTPCertificate record
-get_common_name(OTPCert) ->
-    %% You'd think there'd be an easier way than this giant mess, but I
-    %% couldn't find one.
-    {rdnSequence, Subject} = OTPCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject,
-    case [Attribute#'AttributeTypeAndValue'.value || [Attribute] <- Subject,
-        Attribute#'AttributeTypeAndValue'.type == ?'id-at-commonName'] of
-        [Att] ->
-            case Att of
-                {teletexString, Str} -> Str;
-                {printableString, Str} -> Str;
-                {utf8String, Bin} -> binary_to_list(Bin)
-            end;
-        _ ->
-            unknown
-    end.
+make_dir_path(PathComponents) ->
+    lists:foldl(fun(F,P0) -> file:make_dir(P=filename:join(P0,F)), P end,
+		"",
+		PathComponents).
 
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 06a41f1260..d7fafb1b53 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
 %%
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -174,7 +174,7 @@ session_cleanup(Config)when is_list(Config) ->
     State = ssl_test_lib:state(Prop),
     ClientCache = element(2, State),
     ServerCache = element(3, State),
-    SessionTimer = element(7, State),
+    SessionTimer = element(9, State),
 
     Id = proplists:get_value(session_id, SessionInfo),
     CSession = ssl_session_cache:lookup(ClientCache, {{Hostname, Port}, Id}),
@@ -217,7 +217,7 @@ get_delay_timers() ->
     {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
     [_, _,_, _, Prop] = StatusInfo,
     State = ssl_test_lib:state(Prop),
-    case element(8, State) of
+    case element(10, State) of
 	{undefined, undefined} ->
 	    ct:sleep(?SLEEP),
 	    get_delay_timers();
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index d6fbb73249..7d0546210c 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -254,7 +254,6 @@ check_result(Server, ServerMsg, Client, ClientMsg) ->
 	{Port, {data,Debug}} when is_port(Port) ->
 	    ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
 	    check_result(Server, ServerMsg, Client, ClientMsg);
-
 	Unexpected ->
 	    Reason = {{expected, {Client, ClientMsg}},
 		      {expected, {Server, ServerMsg}}, {got, Unexpected}},
@@ -268,6 +267,9 @@ check_result(Pid, Msg) ->
 	{Port, {data,Debug}} when is_port(Port) ->
 	    ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
 	    check_result(Pid,Msg);
+	%% {Port, {exit_status, Status}} when is_port(Port) ->
+	%%     ct:log("~p:~p Exit status: ~p~n",[?MODULE,?LINE, Status]),
+	%%    check_result(Pid, Msg);
 	Unexpected ->
 	    Reason = {{expected, {Pid, Msg}}, 
 		      {got, Unexpected}},
@@ -837,7 +839,7 @@ string_regex_filter(Str, Search) when is_list(Str) ->
 	_ ->
 	    true
     end;
-string_regex_filter(Str, _Search) ->
+string_regex_filter(_Str, _Search) ->
     false.
 
 anonymous_suites() ->
-- 
cgit v1.2.3