From ccb20d8a61165ddfc0edf584c9cbc3c2e7197f70 Mon Sep 17 00:00:00 2001
From: Ao Song <andy@erlang.org>
Date: Mon, 6 Jul 2020 15:20:06 +0200
Subject: [PATCH] public_key: Add initial support for OCSP

---
 lib/public_key/asn1/OCSP-2013-88.asn1     | 148 +++++++++
 lib/public_key/asn1/OTP-PUB-KEY.set.asn   |   1 +
 lib/public_key/src/Makefile               |   3 +-
 lib/public_key/src/pubkey_ocsp.erl        | 356 ++++++++++++++++++++
 lib/public_key/src/public_key.app.src     |   1 +
 lib/public_key/src/public_key.erl         |  57 +++-
 lib/public_key/test/pubkey_ocsp_SUITE.erl | 376 ++++++++++++++++++++++
 7 files changed, 940 insertions(+), 2 deletions(-)
 create mode 100644 lib/public_key/asn1/OCSP-2013-88.asn1
 create mode 100644 lib/public_key/src/pubkey_ocsp.erl
 create mode 100644 lib/public_key/test/pubkey_ocsp_SUITE.erl

diff --git a/lib/public_key/asn1/OCSP-2013-88.asn1 b/lib/public_key/asn1/OCSP-2013-88.asn1
new file mode 100644
index 000000000000..6e937f617448
--- /dev/null
+++ b/lib/public_key/asn1/OCSP-2013-88.asn1
@@ -0,0 +1,148 @@
+-- OCSP definition from RFC6960, 1998 Syntax
+
+OCSP-2013-88 {
+   iso(1) identified-organization(3) dod(6) internet(1)
+   security(5) mechanisms(5) pkix(7) id-mod(0)
+   id-mod-ocsp-2013-88(81)
+}
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+IMPORTS
+
+   -- PKIX Certificate Extensions
+      AuthorityInfoAccessSyntax, CRLReason, GeneralName
+      FROM PKIX1Implicit88 { iso(1) identified-organization(3)
+           dod(6) internet(1) security(5) mechanisms(5) pkix(7)
+           id-mod(0) id-pkix1-implicit(19) }
+
+      Name, CertificateSerialNumber, Extensions,
+      id-kp, id-ad-ocsp, Certificate, AlgorithmIdentifier
+      FROM PKIX1Explicit88 { iso(1) identified-organization(3)
+           dod(6) internet(1) security(5) mechanisms(5) pkix(7)
+           id-mod(0) id-pkix1-explicit(18) };
+
+OCSPRequest ::= SEQUENCE {
+   tbsRequest              TBSRequest,
+   optionalSignature   [0] EXPLICIT Signature OPTIONAL }
+
+TBSRequest ::= SEQUENCE {
+   version             [0] EXPLICIT Version DEFAULT v1,
+   requestorName       [1] EXPLICIT GeneralName OPTIONAL,
+   requestList             SEQUENCE OF Request,
+   requestExtensions   [2] EXPLICIT Extensions OPTIONAL }
+
+Signature ::= SEQUENCE {
+   signatureAlgorithm      AlgorithmIdentifier,
+   signature               BIT STRING,
+   certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+
+Version ::= INTEGER { v1(0) }
+
+Request ::= SEQUENCE {
+   reqCert                     CertID,
+   singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+
+CertID ::= SEQUENCE {
+   hashAlgorithm           AlgorithmIdentifier,
+   issuerNameHash          OCTET STRING, -- Hash of issuer's DN
+   issuerKeyHash           OCTET STRING, -- Hash of issuer's public key
+   serialNumber            CertificateSerialNumber }
+
+OCSPResponse ::= SEQUENCE {
+   responseStatus          OCSPResponseStatus,
+   responseBytes       [0] EXPLICIT ResponseBytes OPTIONAL }
+
+OCSPResponseStatus ::= ENUMERATED {
+   successful          (0),  -- Response has valid confirmations
+   malformedRequest    (1),  -- Illegal confirmation request
+   internalError       (2),  -- Internal error in issuer
+   tryLater            (3),  -- Try again later
+                             -- (4) is not used
+   sigRequired         (5),  -- Must sign the request
+   unauthorized        (6)   -- Request unauthorized
+}
+
+ResponseBytes ::= SEQUENCE {
+   responseType            OBJECT IDENTIFIER,
+   response                OCTET STRING }
+
+BasicOCSPResponse ::= SEQUENCE {
+  tbsResponseData          ResponseData,
+  signatureAlgorithm       AlgorithmIdentifier,
+  signature                BIT STRING,
+  certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+
+ResponseData ::= SEQUENCE {
+   version             [0] EXPLICIT Version DEFAULT v1,
+   responderID             ResponderID,
+   producedAt              GeneralizedTime,
+   responses               SEQUENCE OF SingleResponse,
+   responseExtensions  [1] EXPLICIT Extensions OPTIONAL }
+
+ResponderID ::= CHOICE {
+   byName              [1] Name,
+   byKey               [2] KeyHash }
+
+KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
+                         -- (i.e., the SHA-1 hash of the value of the
+                         -- BIT STRING subjectPublicKey [excluding
+                         -- the tag, length, and number of unused
+                         -- bits] in the responder's certificate)
+
+SingleResponse ::= SEQUENCE {
+   certID                  CertID,
+   certStatus              CertStatus,
+   thisUpdate              GeneralizedTime,
+   nextUpdate          [0] EXPLICIT GeneralizedTime OPTIONAL,
+   singleExtensions    [1] EXPLICIT Extensions OPTIONAL }
+
+CertStatus ::= CHOICE {
+   good                [0] IMPLICIT NULL,
+   revoked             [1] IMPLICIT RevokedInfo,
+   unknown             [2] IMPLICIT UnknownInfo }
+
+RevokedInfo ::= SEQUENCE {
+   revocationTime          GeneralizedTime,
+   revocationReason    [0] EXPLICIT CRLReason OPTIONAL }
+
+UnknownInfo ::= NULL
+
+ArchiveCutoff ::= GeneralizedTime
+
+AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER
+
+ServiceLocator ::= SEQUENCE {
+   issuer                  Name,
+   locator                 AuthorityInfoAccessSyntax }
+
+CrlID ::= SEQUENCE {
+    crlUrl               [0]     EXPLICIT IA5String OPTIONAL,
+    crlNum               [1]     EXPLICIT INTEGER OPTIONAL,
+    crlTime              [2]     EXPLICIT GeneralizedTime OPTIONAL }
+
+PreferredSignatureAlgorithms ::= SEQUENCE OF PreferredSignatureAlgorithm
+
+PreferredSignatureAlgorithm ::= SEQUENCE {
+   sigIdentifier   AlgorithmIdentifier,
+   certIdentifier  AlgorithmIdentifier OPTIONAL }
+
+Nonce ::= OCTET STRING
+
+-- Object Identifiers
+
+id-kp-OCSPSigning            OBJECT IDENTIFIER ::= { id-kp 9 }
+id-pkix-ocsp                 OBJECT IDENTIFIER ::= { id-ad-ocsp }
+id-pkix-ocsp-basic           OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
+id-pkix-ocsp-nonce           OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 }
+id-pkix-ocsp-crl             OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 }
+id-pkix-ocsp-response        OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 }
+id-pkix-ocsp-nocheck         OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 }
+id-pkix-ocsp-archive-cutoff  OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 }
+id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 }
+id-pkix-ocsp-pref-sig-algs   OBJECT IDENTIFIER ::= { id-pkix-ocsp 8 }
+id-pkix-ocsp-extended-revoke OBJECT IDENTIFIER ::= { id-pkix-ocsp 9 }
+
+END
diff --git a/lib/public_key/asn1/OTP-PUB-KEY.set.asn b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
index 7ab1684ff332..74964a1c8fe1 100644
--- a/lib/public_key/asn1/OTP-PUB-KEY.set.asn
+++ b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
@@ -11,4 +11,5 @@ PKCS-7.asn1
 PKCS-10.asn1
 RFC5639.asn1
 CMSAesRsaesOaep.asn1
+OCSP-2013-88.asn1
 
diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile
index e61390bce37f..76bdffe0893d 100644
--- a/lib/public_key/src/Makefile
+++ b/lib/public_key/src/Makefile
@@ -46,7 +46,8 @@ MODULES = \
 	pubkey_pbe \
 	pubkey_cert \
         pubkey_cert_records \
-	pubkey_crl
+	pubkey_crl\
+	pubkey_ocsp
 
 HRL_FILES = $(INCLUDE)/public_key.hrl 
 
diff --git a/lib/public_key/src/pubkey_ocsp.erl b/lib/public_key/src/pubkey_ocsp.erl
new file mode 100644
index 000000000000..2d9367dcdbef
--- /dev/null
+++ b/lib/public_key/src/pubkey_ocsp.erl
@@ -0,0 +1,356 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%%     http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(pubkey_ocsp).
+
+-include("public_key.hrl").
+
+-export([otp_cert/1, get_ocsp_responder_id/1, get_nonce/0, get_nonce_extn/1,
+         decode_ocsp_response/1, verify_ocsp_response/3,
+         get_acceptable_response_types_extn/0, find_single_response/3]).
+
+%%--------------------------------------------------------------------
+-spec verify_ocsp_response(binary(), list(), undefined | binary()) ->
+    {ok, term()} | {error, term()}.
+%%
+%% Description: Verify the OCSP response to get the certificate status
+%%--------------------------------------------------------------------
+verify_ocsp_response(OCSPResponseDer, ResponderCerts, Nonce) ->
+    do_verify_ocsp_response(
+        decode_ocsp_response(OCSPResponseDer), ResponderCerts, Nonce
+    ).
+
+%%--------------------------------------------------------------------
+-spec do_verify_ocsp_response({ok, #'BasicOCSPResponse'{}} | {error, term()},
+                              list(), undefined | binary()) ->
+    {ok, term()} | {error, term()}.
+%%
+%% Description: Verify the OCSP response to get the certificate status
+%%--------------------------------------------------------------------
+do_verify_ocsp_response(
+    {ok, #'BasicOCSPResponse'{
+        tbsResponseData = ResponseData,
+        signatureAlgorithm = SignatureAlgo,
+        signature = Signature,
+        certs = Certs
+    }}, ResponderCerts, Nonce) ->
+
+    #'ResponseData'{
+        responderID = ResponderID
+    } = ResponseData,
+
+    case verify_ocsp_signature(
+        public_key:der_encode('ResponseData', ResponseData),
+        SignatureAlgo#'AlgorithmIdentifier'.algorithm,
+        Signature, Certs ++ ResponderCerts,
+        ResponderID) of
+        ok ->
+            verify_ocsp_nonce(ResponseData, Nonce);
+        {error, Reason} ->
+            {error, Reason}
+    end;
+do_verify_ocsp_response({error, Reason}, _ResponderCerts, _Nonce) ->
+    {error, Reason}.
+
+%%--------------------------------------------------------------------
+-spec verify_ocsp_nonce(#'ResponseData'{}, undefined | binary()) ->
+    {ok, term()} | {error, nonce_mismatch}.
+%%
+%% Description: Check if the nonces matches in OCSP response
+%%--------------------------------------------------------------------
+verify_ocsp_nonce(ResponseData, Nonce) ->
+    #'ResponseData'{
+        responses = Responses,
+        responseExtensions = ResponseExtns
+    } = ResponseData,
+
+    case get_nonce_value(ResponseExtns) of
+        Nonce ->
+            {ok, Responses};
+        _Other ->
+            {error, nonce_mismatch}
+    end.
+
+%%--------------------------------------------------------------------
+-spec get_nonce_value(asn1_NOVALUE | list()) ->
+    undefined | binary().
+%%
+%% Description: Get the nonce value from extensions
+%%--------------------------------------------------------------------
+%% no extensions present in response
+get_nonce_value(asn1_NOVALUE) ->
+    undefined;
+%% extensions exist, but no oscp nonce
+get_nonce_value([]) ->
+    undefined;
+get_nonce_value([#'Extension'{
+                     extnID = ?'id-pkix-ocsp-nonce',
+                     extnValue = Value} | _Extns]) ->
+    Value;
+get_nonce_value([_Extn | Rest]) ->
+    get_nonce_value(Rest).
+
+%%--------------------------------------------------------------------
+-spec decode_ocsp_response(binary()) ->
+    {ok, #'BasicOCSPResponse'{}} | {error, term()}.
+%%
+%% Description: Decode the OCSP response der
+%%--------------------------------------------------------------------
+decode_ocsp_response(Response) ->
+    Resp = public_key:der_decode('OCSPResponse', Response),
+    case Resp#'OCSPResponse'.responseStatus of
+        successful ->
+             decode_response_bytes(
+                 Resp#'OCSPResponse'.responseBytes
+             );
+        Error ->
+            {error, Error}
+    end.
+
+%%--------------------------------------------------------------------
+-spec decode_response_bytes(#'ResponseBytes'{}) ->
+    {ok, #'BasicOCSPResponse'{}} | {error, term()}.
+%%
+%% Description: Get basic ocsp response field
+%%--------------------------------------------------------------------
+decode_response_bytes(#'ResponseBytes'{
+                          responseType = ?'id-pkix-ocsp-basic',
+                          response = Data}) ->
+    {ok, public_key:der_decode('BasicOCSPResponse', Data)};
+decode_response_bytes(#'ResponseBytes'{responseType = RespType}) ->
+    {error, {ocsp_response_type_not_supported, RespType}}.
+
+%%--------------------------------------------------------------------
+-spec verify_ocsp_signature(binary(), term(), term(), list(), term()) ->
+    ok | {error, term()}.
+%%
+%% Description: Verify the signature of OCSP response
+%%--------------------------------------------------------------------
+verify_ocsp_signature(
+    ResponseDataDer, SignatureAlgo, Signature, Certs, ResponderID) ->
+    case find_responder_cert(ResponderID, Certs) of
+        {ok, Cert} ->
+            do_verify_ocsp_signature(
+                ResponseDataDer, Signature, SignatureAlgo, Cert);
+        {error, Reason} ->
+            {error, Reason}
+    end.
+
+%%--------------------------------------------------------------------
+-spec find_responder_cert(term(), list()) ->
+    {ok, #'Certificate'{} | #'OTPCertificate'{}} | {error, term()}.
+%%
+%% Description: Find the OCSP responder's cert in input list
+%%--------------------------------------------------------------------
+find_responder_cert(_ResponderID, []) ->
+    {error, ocsp_responder_cert_not_found};
+find_responder_cert(ResponderID, [Cert | TCerts]) ->
+    case is_responder(ResponderID, Cert) of
+        true ->
+            {ok, Cert};
+        false ->
+            find_responder_cert(ResponderID, TCerts)
+    end.
+
+%%--------------------------------------------------------------------
+-spec do_verify_ocsp_signature(
+        binary(), term(), term(), #'Certificate'{} | #'OTPCertificate'{}) ->
+    ok | {error, term()}.
+%%
+%% Description: Verify the signature of OCSP response
+%%--------------------------------------------------------------------
+do_verify_ocsp_signature(ResponseDataDer, Signature, AlgorithmID, Cert) ->
+    {DigestType, _SignatureType} = public_key:pkix_sign_types(AlgorithmID),
+    case public_key:verify(
+             ResponseDataDer, DigestType, Signature,
+             get_public_key_rec(Cert)) of
+        true ->
+            ok;
+        false ->
+            {error, ocsp_response_bad_signature}
+    end.
+
+%%--------------------------------------------------------------------
+-spec get_public_key_rec(#'Certificate'{} | #'OTPCertificate'{}) ->
+    term().
+%%
+%% Description: Get the subject public key field
+%%--------------------------------------------------------------------
+get_public_key_rec(#'Certificate'{} = Cert) ->
+    get_public_key_rec(otp_cert(Cert));
+get_public_key_rec(#'OTPCertificate'{tbsCertificate = TbsCert}) ->
+    PKInfo = TbsCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+    PKInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey.
+
+%%--------------------------------------------------------------------
+-spec is_responder(tuple(), #'Certificate'{} | #'OTPCertificate'{}) ->
+    boolean().
+%%
+%% Description: Check if is OCSP responder's cert
+%%--------------------------------------------------------------------
+is_responder({byName, Name}, Cert) ->
+    public_key:der_encode('Name', Name) == get_subject_name(Cert);
+is_responder({byKey, Key}, Cert) ->
+    Key == crypto:hash(sha, get_public_key(Cert)).
+
+%%--------------------------------------------------------------------
+-spec otp_cert(#'Certificate'{} | #'OTPCertificate'{} | binary()) ->
+    #'OTPCertificate'{}.
+%%
+%% Description: Convert to #'OTPCertificate'{}
+%%--------------------------------------------------------------------
+otp_cert(#'OTPCertificate'{} = Cert) ->
+    Cert;
+otp_cert(#'Certificate'{} = Cert) ->
+    public_key:pkix_decode_cert(
+        public_key:der_encode('Certificate', Cert), otp);
+otp_cert(CertDer) when is_binary(CertDer) ->
+    public_key:pkix_decode_cert(CertDer, otp).
+
+%%--------------------------------------------------------------------
+-spec get_ocsp_responder_id(#'Certificate'{}) -> binary().
+%%
+%% Description: Get the OCSP responder ID der
+%%--------------------------------------------------------------------
+get_ocsp_responder_id(#'Certificate'{tbsCertificate = TbsCert}) ->
+    public_key:der_encode(
+        'ResponderID', {byName, TbsCert#'TBSCertificate'.subject}).
+
+%%--------------------------------------------------------------------
+-spec get_subject_name(#'Certificate'{} | #'OTPCertificate'{}) -> binary().
+%%
+%% Description: Get the subject der from cert
+%%--------------------------------------------------------------------
+get_subject_name(#'Certificate'{} = Cert) ->
+    get_subject_name(otp_cert(Cert));
+get_subject_name(#'OTPCertificate'{tbsCertificate = TbsCert}) ->
+    public_key:pkix_encode('Name', TbsCert#'OTPTBSCertificate'.subject, otp).
+
+%%--------------------------------------------------------------------
+-spec get_public_key(#'Certificate'{} | #'OTPCertificate'{}) -> binary().
+%%
+%% Description: Get the public key from cert
+%%--------------------------------------------------------------------
+get_public_key(#'Certificate'{} = Cert) ->
+    get_public_key(otp_cert(Cert));
+get_public_key(#'OTPCertificate'{tbsCertificate = TbsCert}) ->
+    PKInfo = TbsCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+    enc_pub_key(PKInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey).
+
+enc_pub_key(Key = #'RSAPublicKey'{}) ->
+    public_key:der_encode('RSAPublicKey', Key);
+enc_pub_key({DsaInt, #'Dss-Parms'{}}) when is_integer(DsaInt) ->
+    public_key:der_encode('DSAPublicKey', DsaInt);
+enc_pub_key({#'ECPoint'{point = Key}, _ECParam}) ->
+    Key.
+
+%%--------------------------------------------------------------------
+-spec get_nonce() -> binary().
+%%
+%% Description: Get an OCSP nonce
+%%--------------------------------------------------------------------
+get_nonce() ->
+    public_key:der_encode('Nonce', crypto:strong_rand_bytes(8)).
+
+%%--------------------------------------------------------------------
+-spec get_nonce_extn(undefined | binary()) -> undefined | #'Extension'{}.
+%%
+%% Description: Get an OCSP nonce der
+%%--------------------------------------------------------------------
+get_nonce_extn(undefined) ->
+    undefined;
+get_nonce_extn(Nonce) when is_binary(Nonce) ->
+    #'Extension'{
+        extnID    = ?'id-pkix-ocsp-nonce',
+        extnValue = Nonce
+    }.
+
+%%--------------------------------------------------------------------
+-spec get_acceptable_response_types_extn() -> #'Extension'{}.
+%%
+%% Description: Get an acceptable response types der
+%%--------------------------------------------------------------------
+get_acceptable_response_types_extn() ->
+    #'Extension'{
+        extnID    = ?'id-pkix-ocsp-response',
+        extnValue = public_key:der_encode(
+            'AcceptableResponses', [?'id-pkix-ocsp-basic'])
+    }.
+
+%%--------------------------------------------------------------------
+-spec get_serial_num(binary | #'Certificate'{} | #'OTPCertificate'{}) ->
+    term().
+%%
+%% Description: Get the serial number of a certificate
+%%--------------------------------------------------------------------
+get_serial_num(Cert) ->
+    #'OTPCertificate'{tbsCertificate = TbsCert} = otp_cert(Cert),
+    TbsCert#'OTPTBSCertificate'.serialNumber.
+
+
+%%--------------------------------------------------------------------
+-spec find_single_response(
+    binary | #'Certificate'{} | #'OTPCertificate'{}, list(), list()) ->
+    #'SingleResponse'{} | {error, no_matched_response}.
+%%
+%% Description: Find the matched single response.
+%%--------------------------------------------------------------------
+find_single_response(Cert, CertPath, SingleResponseList) ->
+    case find_issuer(Cert, CertPath) of
+        {ok, Issuer} ->
+            OtpCert = otp_cert(Cert),
+            IssuerName = get_subject_name(Issuer),
+            IssuerKey = get_public_key(Issuer),
+            SerialNum = get_serial_num(OtpCert),
+            match_single_response(
+                IssuerName, IssuerKey, SerialNum, SingleResponseList);
+        {error, issuer_not_found} ->
+            {error, no_matched_response}
+    end.
+
+match_single_response(_IssuerName, _IssuerKey, _SerialNum, []) ->
+    {error, no_matched_response};
+match_single_response(
+    IssuerName, IssuerKey, SerialNum,
+    [#'SingleResponse'{
+        certID = #'CertID'{hashAlgorithm = Algo} = CertID
+     } = Response | Reponses]) ->
+    HashType = public_key:pkix_hash_type(
+        Algo#'AlgorithmIdentifier'.algorithm),
+    case (SerialNum == CertID#'CertID'.serialNumber) andalso
+         (crypto:hash(
+             HashType, IssuerName) == CertID#'CertID'.issuerNameHash) andalso
+         (crypto:hash(
+             HashType, IssuerKey) == CertID#'CertID'.issuerKeyHash) of
+        true ->
+            {ok, Response};
+        false ->
+            match_single_response(IssuerName, IssuerKey, SerialNum, Reponses)
+    end.
+
+find_issuer(_Cert, []) ->
+    {error, issuer_not_found};
+find_issuer(Cert, [Issuer | CertPath]) ->
+    case public_key:pkix_is_issuer(Cert, Issuer) of
+        true ->
+            {ok, otp_cert(Issuer)};
+        false ->
+            find_issuer(Cert, CertPath)
+    end.
\ No newline at end of file
diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src
index 5833141e8736..6be7cd3bc494 100644
--- a/lib/public_key/src/public_key.app.src
+++ b/lib/public_key/src/public_key.app.src
@@ -8,6 +8,7 @@
 		  pubkey_cert,
 		  pubkey_cert_records,
 		  pubkey_crl,
+                  pubkey_ocsp,
 		  'OTP-PUB-KEY',
 		  'PKCS-FRAME'
             ]},
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 5decfd49bdd6..604386977053 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -63,7 +63,12 @@
 	 pkix_crl_issuer/1,
 	 short_name_hash/1,
          pkix_test_data/1,
-         pkix_test_root_cert/2
+         pkix_test_root_cert/2,
+     ocsp_status/3,
+     ocsp_responses/3,
+     ocsp_nonce/0,
+     ocsp_responder_id/1,
+     ocsp_extensions/1
 	]).
 
 -export_type([public_key/0, private_key/0, pem_entry/0,
@@ -1275,6 +1280,56 @@ pkix_test_data(#{} = Chain) ->
 pkix_test_root_cert(Name, Opts) ->
     pubkey_cert:root_cert(Name, Opts).
 
+%%--------------------------------------------------------------------
+-spec ocsp_status(binary | #'Certificate'{} | #'OTPCertificate'{},
+                  list(), list()) ->
+    {good, term()} | {unknown, term()} | {revoked, term()} | no_matched_response.
+%%
+%% Description: Get Certificate status
+%%--------------------------------------------------------------------
+ocsp_status(Cert, CertPath, Responses) ->
+    case pubkey_ocsp:find_single_response(Cert, CertPath, Responses) of
+        {ok, #'SingleResponse'{certStatus = CertStatus}} ->
+            CertStatus;
+        {error, no_matched_response} ->
+            no_matched_response
+    end.
+
+%%--------------------------------------------------------------------
+-spec ocsp_responses(binary(), list(), undefined | binary()) ->
+    {ok, [#'SingleResponse'{}]} | {error, Reason::term()}.
+%%
+%% Description: Get verified OCSP responses
+%%--------------------------------------------------------------------
+ocsp_responses(OCSPResponseDer, ResponderCerts, Nonce) ->
+    catch pubkey_ocsp:verify_ocsp_response(
+        OCSPResponseDer, ResponderCerts, Nonce).
+
+%%--------------------------------------------------------------------
+-spec ocsp_extensions(undefined | binary()) -> list().
+%% Description: Get OCSP stapling extensions for request
+%%--------------------------------------------------------------------
+ocsp_extensions(Nonce) ->
+    [Extn || Extn <- [pubkey_ocsp:get_nonce_extn(Nonce),
+                      pubkey_ocsp:get_acceptable_response_types_extn()],
+             erlang:is_record(Extn, 'Extension')].
+
+%%--------------------------------------------------------------------
+-spec ocsp_responder_id(#'Certificate'{}) -> binary().
+%%
+%% Description: Get the OCSP responder ID der
+%%--------------------------------------------------------------------
+ocsp_responder_id(Cert) ->
+    pubkey_ocsp:get_ocsp_responder_id(Cert).
+
+%%--------------------------------------------------------------------
+-spec ocsp_nonce() -> binary().
+%%
+%% Description: Get an OCSP nonce
+%%--------------------------------------------------------------------
+ocsp_nonce() ->
+    pubkey_ocsp:get_nonce().
+
 %%--------------------------------------------------------------------
 %%% Internal functions
 %%--------------------------------------------------------------------
diff --git a/lib/public_key/test/pubkey_ocsp_SUITE.erl b/lib/public_key/test/pubkey_ocsp_SUITE.erl
new file mode 100644
index 000000000000..006741e81a61
--- /dev/null
+++ b/lib/public_key/test/pubkey_ocsp_SUITE.erl
@@ -0,0 +1,376 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%%     http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(pubkey_ocsp_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() -> 
+    [ocsp_test].
+
+groups() -> 
+    [].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+    Config.
+
+end_per_suite(_Config) ->
+    ok.
+
+%%--------------------------------------------------------------------
+
+init_per_group(_GroupName, Config) ->
+    Config.
+
+end_per_group(_GroupName, Config) ->
+    Config.
+
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config) ->
+    Config.
+
+end_per_testcase(_TestCase, _Config) ->
+    ok.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+ocsp_test() ->
+    [{doc, "Test functions in pubkey_ocsp"}].
+ocsp_test(Config) when is_list(Config) ->
+    %% Feeding data
+    SingleResponseGood =
+        [#'SingleResponse'{
+            certID = {'CertID',
+                {'AlgorithmIdentifier',{1,3,14,3,2,26},<<5,0>>},
+                <<227,147,252,182,155,101,129,45,194,162,
+                    22,93,127,46,112,193,196,28,241,232>>,
+                <<99,34,37,88,164,188,98,22,125,252,71,72,
+                    246,115,141,222,108,19,122,168>>,7},
+            certStatus = {good,'NULL'},
+            thisUpdate = "20200428083205Z",
+            nextUpdate = asn1_NOVALUE,
+            singleExtensions = asn1_NOVALUE}],
+
+    Nonce = <<226,210,104,247,153,233,71,246>>,
+
+    NonceExtension =
+    #'Extension'{
+        extnID    = ?'id-pkix-ocsp-nonce',
+        extnValue = Nonce
+    },
+
+    OCSPResponseDer =
+    <<48,130,7,6,10,1,0,160,130,6,255,48,130,6,251,6,9,43,6,1,5,5,7,48,1,1,4,130,6,
+    236,48,130,6,232,48,130,1,11,161,129,137,48,129,134,49,17,48,15,6,3,85,4,3,
+    12,8,98,46,115,101,114,118,101,114,49,19,48,17,6,3,85,4,11,12,10,69,114,108,
+    97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,12,11,69,114,105,99,115,115,
+    111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,12,
+    9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,
+    1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,
+    110,46,115,101,24,15,50,48,50,48,48,52,50,56,48,56,51,50,48,53,90,48,81,48,
+    79,48,58,48,9,6,5,43,14,3,2,26,5,0,4,20,227,147,252,182,155,101,129,45,194,
+    162,22,93,127,46,112,193,196,28,241,232,4,20,99,34,37,88,164,188,98,22,125,
+    252,71,72,246,115,141,222,108,19,122,168,2,1,7,128,0,24,15,50,48,50,48,48,52,
+    50,56,48,56,51,50,48,53,90,161,25,48,23,48,21,6,9,43,6,1,5,5,7,48,1,2,4,8,
+    226,210,104,247,153,233,71,246,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,
+    130,1,1,0,85,82,43,226,38,172,139,105,77,248,24,250,244,154,2,174,232,141,52,
+    93,102,37,177,31,59,105,104,242,117,238,102,93,61,56,24,47,69,169,184,234,
+    109,204,5,64,109,101,23,197,234,6,250,223,95,175,131,138,227,66,123,199,182,
+    57,102,47,221,72,112,208,1,4,128,209,235,108,64,209,31,128,37,130,176,132,
+    203,119,24,188,187,254,8,167,54,80,28,208,26,118,236,149,184,182,25,236,252,
+    158,253,167,143,114,14,184,198,144,51,195,44,16,38,255,112,124,81,201,255,
+    132,143,98,119,135,23,232,10,184,54,150,227,131,212,81,101,158,152,82,252,
+    156,28,30,163,203,145,11,179,105,230,187,132,119,186,189,67,198,165,48,106,
+    114,75,151,128,108,28,44,121,195,162,222,25,45,99,46,84,116,125,51,72,191,
+    250,186,71,78,21,222,219,232,143,233,226,56,163,23,51,170,69,152,223,0,63,8,
+    236,219,175,18,165,88,166,125,71,31,53,40,12,133,64,250,30,190,113,10,187,38,
+    171,17,210,170,126,198,232,195,224,228,1,246,75,140,139,121,229,17,153,115,
+    199,68,227,171,176,163,117,171,160,130,4,193,48,130,4,189,48,130,4,185,48,
+    130,3,161,160,3,2,1,2,2,1,9,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,48,129,
+    131,49,14,48,12,6,3,85,4,3,12,5,111,116,112,67,65,49,19,48,17,6,3,85,4,11,12,
+    10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,12,11,69,114,
+    105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,
+    6,3,85,4,7,12,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,
+    134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,
+    99,115,115,111,110,46,115,101,48,30,23,13,50,48,48,52,50,56,48,56,51,50,48,
+    53,90,23,13,51,48,48,51,48,55,48,56,51,50,48,53,90,48,129,134,49,17,48,15,6,
+    3,85,4,3,12,8,98,46,115,101,114,118,101,114,49,19,48,17,6,3,85,4,11,12,10,69,
+    114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,12,11,69,114,105,99,
+    115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,
+    4,7,12,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,
+    13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,
+    115,111,110,46,115,101,48,130,1,34,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,
+    3,130,1,15,0,48,130,1,10,2,130,1,1,0,188,248,42,161,172,252,200,52,180,217,
+    145,59,193,72,33,176,213,106,37,81,119,251,205,254,70,196,171,127,79,157,147,
+    235,14,61,25,162,207,134,25,239,35,62,57,10,214,115,231,71,203,226,198,73,
+    223,222,199,165,82,67,33,78,176,116,241,192,97,169,143,164,219,152,40,115,
+    229,242,128,97,98,183,217,199,35,127,146,94,20,115,0,250,200,39,9,255,230,
+    216,80,140,6,133,251,39,96,240,176,184,34,1,134,247,126,237,255,130,170,98,
+    242,140,104,105,95,48,75,115,135,229,89,191,180,179,123,198,232,228,220,249,
+    113,86,186,212,176,194,66,14,164,236,219,138,254,80,57,118,232,163,192,94,78,
+    224,100,124,206,199,81,105,54,222,26,245,170,147,184,192,237,77,143,154,180,
+    79,42,107,75,77,81,215,19,75,8,160,106,199,196,66,53,16,233,184,175,85,167,
+    148,12,232,248,113,61,89,14,156,199,128,83,40,214,228,83,9,36,72,188,25,29,
+    47,172,78,114,191,120,240,227,234,255,194,61,132,57,1,141,131,227,64,152,209,
+    205,63,24,172,223,194,254,97,133,255,192,133,148,237,178,115,2,3,1,0,1,163,
+    130,1,49,48,130,1,45,48,9,6,3,85,29,19,4,2,48,0,48,11,6,3,85,29,15,4,4,3,2,5,
+    224,48,29,6,3,85,29,14,4,22,4,20,63,72,140,0,84,13,114,48,50,31,9,241,231,
+    177,20,184,8,114,244,29,48,129,179,6,3,85,29,35,4,129,171,48,129,168,128,20,
+    99,34,37,88,164,188,98,22,125,252,71,72,246,115,141,222,108,19,122,168,161,
+    129,140,164,129,137,48,129,134,49,17,48,15,6,3,85,4,3,12,8,101,114,108,97,
+    110,103,67,65,49,19,48,17,6,3,85,4,11,12,10,69,114,108,97,110,103,32,79,84,
+    80,49,20,48,18,6,3,85,4,10,12,11,69,114,105,99,115,115,111,110,32,65,66,49,
+    18,48,16,6,3,85,4,7,12,9,83,116,111,99,107,104,111,108,109,49,11,48,9,6,3,85,
+    4,6,19,2,83,69,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,
+    101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,130,
+    1,1,48,27,6,3,85,29,17,4,20,48,18,130,16,104,111,115,116,46,101,120,97,109,
+    112,108,101,46,99,111,109,48,33,6,3,85,29,18,4,26,48,24,129,22,112,101,116,
+    101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,
+    13,6,9,42,134,72,134,247,13,1,1,5,5,0,3,130,1,1,0,86,112,29,225,102,143,193,
+    55,126,115,187,208,118,153,111,177,160,121,55,33,184,60,27,111,40,7,93,241,9,
+    226,40,125,181,36,173,116,190,43,187,52,254,50,229,222,56,215,132,67,217,174,
+    121,24,94,240,163,56,12,36,212,2,40,94,102,126,206,52,40,32,218,59,86,166,
+    238,137,144,90,57,211,141,81,32,102,215,180,59,133,125,208,199,166,81,35,49,
+    24,88,100,127,90,145,237,150,249,227,123,120,98,230,12,106,72,201,127,54,94,
+    164,204,23,158,3,230,232,181,95,251,98,6,28,115,46,153,241,233,254,152,176,
+    114,12,148,24,234,185,204,177,189,70,14,73,181,232,245,63,226,14,138,249,101,
+    56,222,188,78,127,191,174,232,182,207,67,162,111,248,192,202,65,96,237,206,
+    52,220,63,50,108,82,185,169,29,148,30,75,74,16,156,229,166,96,102,214,145,77,
+    225,218,180,54,109,61,62,119,144,231,72,105,61,201,245,219,192,63,160,242,
+    247,112,64,199,65,248,252,59,145,150,212,151,166,223,237,121,135,13,122,111,
+    22,117,115,166,64,143,10,40,13,5,240,22,38,235,32,107,194,41>>,
+
+    MalOCSPResponseDer =
+    <<48,130,7,6,10,1,0,160,130,6,255,48,130,6,251,6,9,43,6,1,5,5,7,48,1,1,4,130,6,
+    236,48,130,6,232,48,130,1,11,161,129,137,48,129,134,49,17,48,15,6,3,85,4,3,
+    12,8,98,46,115,101,114,118,101,114,49,19,48,17,6,3,85,4,11,12,10,69,114,108,
+    97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,12,11,69,114,105,99,115,115,
+    111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,12,
+    9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,
+    1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,
+    110,46,115,101,24,15,50,48,50,48,48,52,50,56,48,56,51,50,48,53,90,48,81,48,
+    79,48,58,48,9,6,5,43,14,3,2,26,5,0,4,20,227,147,252,182,155,101,129,45,194,
+    162,22,93,127,46,112,193,196,28,241,232,4,20,99,34,37,88,164,188,98,22,125,
+    252,71,72,246,115,141,222,108,19,122,168,2,1,7,128,0,24,15,50,48,50,48,48,52,
+    50,56,48,56,51,50,48,53,90,161,25,48,23,48,21,6,9,43,6,1,5,5,7,48,1,2,4,8,
+    226,210,104,247,153,233,71,246,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,
+    130,1,1,0,85,82,43,226,38,172,139,105,77,248,24,250,244,154,2,174,232,141,52,
+    93,102,37,177,31,59,105,104,242,117,238,102,93,61,56,24,47,69,169,184,234,
+    109,204,5,64,109,101,23,197,234,6,250,223,95,175,131,138,227,66,123,199,182,
+    57,102,47,221,72,112,208,1,4,128,209,235,108,64,209,31,128,37,130,176,132,
+    203,119,24,188,187,254,8,167,54,80,28,208,26,118,236,149,184,182,25,236,252,
+    158,253,167,143,114,14,184,198,168,56,195,44,16,38,255,112,124,81,201,255,
+    132,143,98,119,135,23,232,10,184,54,150,227,131,212,81,101,158,152,82,252,
+    156,28,30,163,203,145,11,179,105,230,187,132,119,186,189,67,198,165,48,106,
+    114,75,151,128,108,28,44,121,195,162,222,25,45,99,46,84,116,125,51,72,191,
+    250,186,71,78,21,222,219,232,143,233,226,56,163,23,51,170,69,152,223,0,63,8,
+    236,219,175,18,165,88,166,125,71,31,53,40,12,133,64,250,30,190,113,10,187,38,
+    171,17,210,170,126,198,232,195,224,228,1,246,75,140,139,121,229,17,153,115,
+    199,68,227,171,176,163,117,171,160,130,4,193,48,130,4,189,48,130,4,185,48,
+    130,3,161,160,3,2,1,2,2,1,9,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,48,129,
+    131,49,14,48,12,6,3,85,4,3,12,5,111,116,112,67,65,49,19,48,17,6,3,85,4,11,12,
+    10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,12,11,69,114,
+    105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,
+    6,3,85,4,7,12,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,
+    134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,
+    99,115,115,111,110,46,115,101,48,30,23,13,50,48,48,52,50,56,48,56,51,50,48,
+    53,90,23,13,51,48,48,51,48,55,48,56,51,50,48,53,90,48,129,134,49,17,48,15,6,
+    3,85,4,3,12,8,98,46,115,101,114,118,101,114,49,19,48,17,6,3,85,4,11,12,10,69,
+    114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,12,11,69,114,105,99,
+    115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,
+    4,7,12,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,
+    13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,
+    115,111,110,46,115,101,48,130,1,34,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,
+    3,130,1,15,0,48,130,1,10,2,130,1,1,0,188,248,42,161,172,252,200,52,180,217,
+    145,59,193,72,33,176,213,106,37,81,119,251,205,254,70,196,171,127,79,157,147,
+    235,14,61,25,162,207,134,25,239,35,62,57,10,214,115,231,71,203,226,198,73,
+    223,222,199,165,82,67,33,78,176,116,241,192,97,169,143,164,219,152,40,115,
+    229,242,128,97,98,183,217,199,35,127,146,94,20,115,0,250,200,39,9,255,230,
+    216,80,140,6,133,251,39,96,240,176,184,34,1,134,247,126,237,255,130,170,98,
+    242,140,104,105,95,48,75,115,135,229,89,191,180,179,123,198,232,228,220,249,
+    113,86,186,212,176,194,66,14,164,236,219,138,254,80,57,118,232,163,192,94,78,
+    224,100,124,206,199,81,105,54,222,26,245,170,147,184,192,237,77,143,154,180,
+    79,42,107,75,77,81,215,19,75,8,160,106,199,196,66,53,16,233,184,175,85,167,
+    148,12,232,248,113,61,89,14,156,199,128,83,40,214,228,83,9,36,72,188,25,29,
+    47,172,78,114,191,120,240,227,234,255,194,61,132,57,1,141,131,227,64,152,209,
+    205,63,24,172,223,194,254,97,133,255,192,133,148,237,178,115,2,3,1,0,1,163,
+    130,1,49,48,130,1,45,48,9,6,3,85,29,19,4,2,48,0,48,11,6,3,85,29,15,4,4,3,2,5,
+    224,48,29,6,3,85,29,14,4,22,4,20,63,72,140,0,84,13,114,48,50,31,9,241,231,
+    177,20,184,8,114,244,29,48,129,179,6,3,85,29,35,4,129,171,48,129,168,128,20,
+    99,34,37,88,164,188,98,22,125,252,71,72,246,115,141,222,108,19,122,168,161,
+    129,140,164,129,137,48,129,134,49,17,48,15,6,3,85,4,3,12,8,101,114,108,97,
+    110,103,67,65,49,19,48,17,6,3,85,4,11,12,10,69,114,108,97,110,103,32,79,84,
+    80,49,20,48,18,6,3,85,4,10,12,11,69,114,105,99,115,115,111,110,32,65,66,49,
+    18,48,16,6,3,85,4,7,12,9,83,116,111,99,107,104,111,108,109,49,11,48,9,6,3,85,
+    4,6,19,2,83,69,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,
+    101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,130,
+    1,1,48,27,6,3,85,29,17,4,20,48,18,130,16,104,111,115,116,46,101,120,97,109,
+    112,108,101,46,99,111,109,48,33,6,3,85,29,18,4,26,48,24,129,22,112,101,116,
+    101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,
+    13,6,9,42,134,72,134,247,13,1,1,5,5,0,3,130,1,1,0,86,112,29,225,102,143,193,
+    55,126,115,187,208,118,153,111,177,160,121,55,33,184,60,27,111,40,7,93,241,9,
+    226,40,125,181,36,173,116,190,43,187,52,254,50,229,222,56,215,132,67,217,174,
+    121,24,94,240,163,56,12,36,212,2,40,94,102,126,206,52,40,32,218,59,86,166,
+    238,137,144,90,57,211,141,81,32,102,215,180,59,133,125,208,199,166,81,35,49,
+    24,88,100,127,90,145,237,150,249,227,123,120,98,230,12,106,72,201,127,54,94,
+    164,204,23,158,3,230,232,181,95,251,98,6,28,115,46,153,241,233,254,152,176,
+    114,12,148,24,234,185,204,177,189,70,14,73,181,232,245,63,226,14,138,249,101,
+    56,222,188,78,127,191,174,232,182,207,67,162,111,248,192,202,65,96,237,206,
+    52,220,63,50,108,82,185,169,29,148,30,75,74,16,156,229,166,96,102,214,145,77,
+    225,218,180,54,109,61,62,119,144,231,72,105,61,201,245,219,192,63,160,242,
+    247,112,64,199,65,248,252,59,145,150,212,151,166,223,237,121,135,13,122,111,
+    22,117,115,166,64,143,10,40,13,5,240,22,38,235,32,107,194,41>>,
+
+    ResponderIDer =
+    <<161,129,135,48,129,132,49,17,48,15,6,3,85,4,3,12,8,98,46,
+      115,101,114,118,101,114,49,18,48,16,6,3,85,4,11,12,10,69,
+      114,108,97,110,103,79,84,80,49,19,48,17,6,3,85,4,10,12,11,
+      69,114,105,99,115,115,111,110,65,66,49,11,48,9,6,3,85,4,6,
+      19,2,83,69,49,18,48,16,6,3,85,4,7,12,9,83,116,111,99,107,
+      104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,
+      22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,
+      99,115,115,111,110,46,115,101>>,
+
+    Cert =
+    #'Certificate'{
+    tbsCertificate = #'TBSCertificate'{
+        version = v3,
+        serialNumber = 9,
+        signature = {'AlgorithmIdentifier',{1,2,840,113549,1,1,5},<<5,0>>},
+        issuer = {rdnSequence,
+            [[{'AttributeTypeAndValue',{2,5,4,3},<<12,5,111,116,112,67,65>>}],
+            [{'AttributeTypeAndValue',{2,5,4,11},<<"\f\nErlangOTP">>}],
+            [{'AttributeTypeAndValue',{2,5,4,10},<<"\f\vEricssonAB">>}],
+            [{'AttributeTypeAndValue',{2,5,4,6},<<19,2,83,69>>}],
+            [{'AttributeTypeAndValue',{2,5,4,7},<<"\f\tStockholm">>}],
+            [{'AttributeTypeAndValue',
+            {1,2,840,113549,1,9,1},
+            <<22,22,112,101,116,101,114,64,101,114,105,120,46,101,
+            114,105,99,115,115,111,110,46,115,101>>}]]},
+        validity = {'Validity',{utcTime,"200428083205Z"},{utcTime,"300307083205Z"}},
+        subject = {rdnSequence,
+            [[{'AttributeTypeAndValue',{2,5,4,3},<<"\f\bb.server">>}],
+            [{'AttributeTypeAndValue',{2,5,4,11},<<"\f\nErlangOTP">>}],
+            [{'AttributeTypeAndValue',{2,5,4,10},<<"\f\vEricssonAB">>}],
+            [{'AttributeTypeAndValue',{2,5,4,6},<<19,2,83,69>>}],
+            [{'AttributeTypeAndValue',{2,5,4,7},<<"\f\tStockholm">>}],
+            [{'AttributeTypeAndValue',
+            {1,2,840,113549,1,9,1},
+            <<22,22,112,101,116,101,114,64,101,114,105,120,46,101,
+            114,105,99,115,115,111,110,46,115,101>>}]]},
+        subjectPublicKeyInfo = {'SubjectPublicKeyInfo',
+            {'AlgorithmIdentifier',{1,2,840,113549,1,1,1},<<5,0>>},
+            <<48,130,1,10,2,130,1,1,0,188,248,42,161,172,252,200,52,180,217,
+            145,59,193,72,33,176,213,106,37,81,119,251,205,254,70,196,171,
+            127,79,157,147,235,14,61,25,162,207,134,25,239,35,62,57,10,214,
+            115,231,71,203,226,198,73,223,222,199,165,82,67,33,78,176,116,
+            241,192,97,169,143,164,219,152,40,115,229,242,128,97,98,183,217,
+            199,35,127,146,94,20,115,0,250,200,39,9,255,230,216,80,140,6,
+            133,251,39,96,240,176,184,34,1,134,247,126,237,255,130,170,98,
+            242,140,104,105,95,48,75,115,135,229,89,191,180,179,123,198,232,
+            228,220,249,113,86,186,212,176,194,66,14,164,236,219,138,254,80,
+            57,118,232,163,192,94,78,224,100,124,206,199,81,105,54,222,26,
+            245,170,147,184,192,237,77,143,154,180,79,42,107,75,77,81,215,
+            19,75,8,160,106,199,196,66,53,16,233,184,175,85,167,148,12,232,
+            248,113,61,89,14,156,199,128,83,40,214,228,83,9,36,72,188,25,29,
+            47,172,78,114,191,120,240,227,234,255,194,61,132,57,1,141,131,
+            227,64,152,209,205,63,24,172,223,194,254,97,133,255,192,133,148,
+            237,178,115,2,3,1,0,1>>},
+        issuerUniqueID = asn1_NOVALUE,
+        subjectUniqueID = asn1_NOVALUE,
+        extensions = [{'Extension',{2,5,29,19},false,<<48,0>>},
+            {'Extension',{2,5,29,15},false,<<3,2,5,224>>},
+            {'Extension',
+            {2,5,29,14},
+           false,
+            <<4,20,63,72,140,0,84,13,114,48,50,31,9,241,231,177,20,184,8,114,
+            244,29>>},
+            {'Extension',
+            {2,5,29,35},
+            false,
+            <<48,129,168,128,20,99,34,37,88,164,188,98,22,125,252,71,72,246,
+            115,141,222,108,19,122,168,161,129,140,164,129,137,48,129,134,
+            49,17,48,15,6,3,85,4,3,12,8,101,114,108,97,110,103,67,65,49,19,
+            48,17,6,3,85,4,11,12,10,69,114,108,97,110,103,32,79,84,80,49,
+            20,48,18,6,3,85,4,10,12,11,69,114,105,99,115,115,111,110,32,65,
+            66,49,18,48,16,6,3,85,4,7,12,9,83,116,111,99,107,104,111,108,
+            109,49,11,48,9,6,3,85,4,6,19,2,83,69,49,37,48,35,6,9,42,134,72,
+            134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,
+            46,101,114,105,99,115,115,111,110,46,115,101,130,1,1>>},
+            {'Extension',
+            {2,5,29,17},
+            false,
+            <<48,18,130,16,104,111,115,116,46,101,120,97,109,112,108,101,46,
+            99,111,109>>},
+            {'Extension',
+            {2,5,29,18},
+            false,
+            <<48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,
+            114,105,99,115,115,111,110,46,115,101>>}]},
+    signatureAlgorithm = {'AlgorithmIdentifier',{1,2,840,113549,1,1,5},<<5,0>>},
+    signature = <<86,112,29,225,102,143,193,55,126,115,187,208,118,153,111,177,160,121,55,
+    33,184,60,27,111,40,7,93,241,9,226,40,125,181,36,173,116,190,43,187,52,
+    254,50,229,222,56,215,132,67,217,174,121,24,94,240,163,56,12,36,212,2,
+    40,94,102,126,206,52,40,32,218,59,86,166,238,137,144,90,57,211,141,81,
+    32,102,215,180,59,133,125,208,199,166,81,35,49,24,88,100,127,90,145,237,
+    150,249,227,123,120,98,230,12,106,72,201,127,54,94,164,204,23,158,3,230,
+    232,181,95,251,98,6,28,115,46,153,241,233,254,152,176,114,12,148,24,234,
+    185,204,177,189,70,14,73,181,232,245,63,226,14,138,249,101,56,222,188,
+    78,127,191,174,232,182,207,67,162,111,248,192,202,65,96,237,206,52,220,
+    63,50,108,82,185,169,29,148,30,75,74,16,156,229,166,96,102,214,145,77,
+    225,218,180,54,109,61,62,119,144,231,72,105,61,201,245,219,192,63,160,
+    242,247,112,64,199,65,248,252,59,145,150,212,151,166,223,237,121,135,13,
+    122,111,22,117,115,166,64,143,10,40,13,5,240,22,38,235,32,107,194,41>>},
+
+    %% test of the exported functions
+    ct:pal("Check pubkey_ocsp:verify_ocsp_response/3~n"),
+    {ok, SingleResponseGood} =
+        pubkey_ocsp:verify_ocsp_response(OCSPResponseDer, [Cert], Nonce),
+    {error, ocsp_response_bad_signature} =
+        pubkey_ocsp:verify_ocsp_response(MalOCSPResponseDer, [Cert], Nonce),
+    {error, nonce_mismatch} =
+        pubkey_ocsp:verify_ocsp_response(OCSPResponseDer, [Cert], <<1,2,3>>),
+    ct:pal("pubkey_ocsp:verify_ocsp_response/3...ok~n"),
+
+    ct:pal("Check pubkey_ocsp:decode_ocsp_response/1~n"),
+    {ok, #'BasicOCSPResponse'{}} =
+        pubkey_ocsp:decode_ocsp_response(OCSPResponseDer),
+    ct:pal("pubkey_ocsp:decode_ocsp_response/1...ok~n"),
+
+    ct:pal("Check pubkey_ocsp:get_ocsp_responder_id/1~n"),
+    ResponderIDer =
+        pubkey_ocsp:get_ocsp_responder_id(Cert),
+    ct:pal("pubkey_ocsp:get_ocsp_responder_id/1...ok~n"),
+
+    ct:pal("Check pubkey_ocsp:get_nonce_extn/1~n"),
+    undefined =
+        pubkey_ocsp:get_nonce_extn(undefined),
+    NonceExtension =
+        pubkey_ocsp:get_nonce_extn(Nonce),
+    ct:pal("pubkey_ocsp:get_nonce_extn/1...ok~n").
\ No newline at end of file
