[前][次][番号順一覧][スレッド一覧]

ruby-changes:43383

From: rhe <ko1@a...>
Date: Sun, 19 Jun 2016 21:26:32 +0900 (JST)
Subject: [ruby-changes:43383] rhe:r55457 (trunk): openssl: add OpenSSL::OCSP::SingleResponse

rhe	2016-06-19 21:26:27 +0900 (Sun, 19 Jun 2016)

  New Revision: 55457

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=55457

  Log:
    openssl: add OpenSSL::OCSP::SingleResponse
    
    * ext/openssl/ossl_ocsp.c: Add OCSP::SingleResponse that represents an
      OCSP SingleResponse structure. Also add two new methods #responses
      and #find_response to OCSP::BasicResponse. A BasicResponse has one or
      more SingleResponse. We have OCSP::BasicResponse#status that returns
      them as an array of arrays, each containing the content of a
      SingleResponse, but this is not useful. When validating an OCSP
      response, we need to look into the each SingleResponse and check their
      validity but it is not simple. For example, when validating for a
      certificate 'cert', the code would be like:
    
        # certid_target is an OpenSSL::OCSP::CertificateId for cert
        basic = res.basic
        result = basic.status.any? do |ary|
          ary[0].cmp(certid_target) &&
            ary[4] <= Time.now && (!ary[5] || Time.now <= ary[5])
        end
    
      Adding OCSP::SingleResponse at the same time allows exposing
      OCSP_check_validity(). With this, the code above can be rewritten as:
    
        basic = res.basic
        single = basic.find_response(certid_target)
        result = single.check_validity
    
    * test/openssl/test_ocsp.rb: Test this.

  Modified files:
    trunk/ChangeLog
    trunk/ext/openssl/ossl_ocsp.c
    trunk/test/openssl/test_ocsp.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 55456)
+++ ChangeLog	(revision 55457)
@@ -1,3 +1,31 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sun Jun 19 21:25:43 2016  Kazuki Yamaguchi  <k@r...>
+
+	* ext/openssl/ossl_ocsp.c: Add OCSP::SingleResponse that represents an
+	  OCSP SingleResponse structure. Also add two new methods #responses
+	  and #find_response to OCSP::BasicResponse. A BasicResponse has one or
+	  more SingleResponse. We have OCSP::BasicResponse#status that returns
+	  them as an array of arrays, each containing the content of a
+	  SingleResponse, but this is not useful. When validating an OCSP
+	  response, we need to look into the each SingleResponse and check their
+	  validity but it is not simple. For example, when validating for a
+	  certificate 'cert', the code would be like:
+
+	    # certid_target is an OpenSSL::OCSP::CertificateId for cert
+	    basic = res.basic
+	    result = basic.status.any? do |ary|
+	      ary[0].cmp(certid_target) &&
+	        ary[4] <= Time.now && (!ary[5] || Time.now <= ary[5])
+	    end
+
+	  Adding OCSP::SingleResponse at the same time allows exposing
+	  OCSP_check_validity(). With this, the code above can be rewritten as:
+
+	    basic = res.basic
+	    single = basic.find_response(certid_target)
+	    result = single.check_validity
+
+	* test/openssl/test_ocsp.rb: Test this.
+
 Sun Jun 19 18:40:19 2016  Kazuki Yamaguchi  <k@r...>
 
 	* ext/openssl/ossl_ocsp.c (ossl_ocspbres_add_status): Allow specifying
Index: ext/openssl/ossl_ocsp.c
===================================================================
--- ext/openssl/ossl_ocsp.c	(revision 55456)
+++ ext/openssl/ossl_ocsp.c	(revision 55457)
@@ -57,6 +57,21 @@ https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L57
     GetOCSPBasicRes((obj), (res)); \
 } while (0)
 
+#define NewOCSPSingleRes(klass) \
+    TypedData_Wrap_Struct((klass), &ossl_ocsp_singleresp_type, 0)
+#define SetOCSPSingleRes(obj, res) do { \
+    if(!(res)) ossl_raise(rb_eRuntimeError, "SingleResponse wasn't initialized!"); \
+    RTYPEDDATA_DATA(obj) = (res); \
+} while (0)
+#define GetOCSPSingleRes(obj, res) do { \
+    TypedData_Get_Struct((obj), OCSP_SINGLERESP, &ossl_ocsp_singleresp_type, (res)); \
+    if(!(res)) ossl_raise(rb_eRuntimeError, "SingleResponse wasn't initialized!"); \
+} while (0)
+#define SafeGetOCSPSingleRes(obj, res) do { \
+    OSSL_Check_Kind((obj), cOCSPSingleRes); \
+    GetOCSPSingleRes((obj), (res)); \
+} while (0)
+
 #define NewOCSPCertId(klass) \
     TypedData_Wrap_Struct((klass), &ossl_ocsp_certid_type, 0)
 #define SetOCSPCertId(obj, cid) do { \
@@ -77,6 +92,7 @@ VALUE eOCSPError; https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L92
 VALUE cOCSPReq;
 VALUE cOCSPRes;
 VALUE cOCSPBasicRes;
+VALUE cOCSPSingleRes;
 VALUE cOCSPCertId;
 
 static void
@@ -122,6 +138,20 @@ static const rb_data_type_t ossl_ocsp_ba https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L138
 };
 
 static void
+ossl_ocsp_singleresp_free(void *ptr)
+{
+    OCSP_SINGLERESP_free(ptr);
+}
+
+static const rb_data_type_t ossl_ocsp_singleresp_type = {
+    "OpenSSL/OCSP/SINGLERESP",
+    {
+	0, ossl_ocsp_singleresp_free,
+    },
+    0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static void
 ossl_ocsp_certid_free(void *ptr)
 {
     OCSP_CERTID_free(ptr);
@@ -842,11 +872,13 @@ ossl_ocspbres_add_status(VALUE self, VAL https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L872
  *   basic_response.status -> statuses
  *
  * Returns an Array of statuses for this response.  Each status contains a
- * CertificateId, the status (0 for good, 1 for revoked, 2 for unknown), the reason for
- * the status, the revocation time, the time of this update, the time for the
- * next update and a list of OpenSSL::X509::Extensions.
+ * CertificateId, the status (0 for good, 1 for revoked, 2 for unknown), the
+ * reason for the status, the revocation time, the time of this update, the time
+ * for the next update and a list of OpenSSL::X509::Extensions.
+ *
+ * This should be superseded by BasicResponse#responses and #find_response that
+ * return SingleResponse.
  */
-
 static VALUE
 ossl_ocspbres_get_status(VALUE self)
 {
@@ -892,6 +924,70 @@ ossl_ocspbres_get_status(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L924
     return ret;
 }
 
+static VALUE ossl_ocspsres_new(OCSP_SINGLERESP *);
+
+/*
+ * call-seq:
+ *   basic_response.responses -> Array of SingleResponse
+ *
+ * Returns an Array of SingleResponse for this BasicResponse.
+ */
+
+static VALUE
+ossl_ocspbres_get_responses(VALUE self)
+{
+    OCSP_BASICRESP *bs;
+    VALUE ret;
+    int count, i;
+
+    GetOCSPBasicRes(self, bs);
+    count = OCSP_resp_count(bs);
+    ret = rb_ary_new2(count);
+
+    for (i = 0; i < count; i++) {
+	OCSP_SINGLERESP *sres, *sres_new;
+
+	sres = OCSP_resp_get0(bs, i);
+	sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
+	if (!sres_new)
+	    ossl_raise(eOCSPError, "ASN1_item_dup");
+
+	rb_ary_push(ret, ossl_ocspsres_new(sres_new));
+    }
+
+    return ret;
+}
+
+
+/*
+ * call-seq:
+ *   basic_response.find_response(certificate_id) -> SingleResponse | nil
+ *
+ * Returns a SingleResponse whose CertId matches with +certificate_id+, or nil
+ * if this BasicResponse does not contain it.
+ */
+static VALUE
+ossl_ocspbres_find_response(VALUE self, VALUE target)
+{
+    OCSP_BASICRESP *bs;
+    OCSP_SINGLERESP *sres, *sres_new;
+    OCSP_CERTID *id;
+    int n;
+
+    SafeGetOCSPCertId(target, id);
+    GetOCSPBasicRes(self, bs);
+
+    if ((n = OCSP_resp_find(bs, id, -1)) == -1)
+	return Qnil;
+
+    sres = OCSP_resp_get0(bs, n);
+    sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
+    if (!sres_new)
+	ossl_raise(eOCSPError, "ASN1_item_dup");
+
+    return ossl_ocspsres_new(sres_new);
+}
+
 /*
  * call-seq:
  *   basic_response.sign(cert, key, certs = nil, flags = 0, digest = nil) -> self
@@ -995,6 +1091,295 @@ ossl_ocspbres_to_der(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L1091
 }
 
 /*
+ * OCSP::SingleResponse
+ */
+static VALUE
+ossl_ocspsres_new(OCSP_SINGLERESP *sres)
+{
+    VALUE obj;
+
+    obj = NewOCSPSingleRes(cOCSPSingleRes);
+    SetOCSPSingleRes(obj, sres);
+
+    return obj;
+}
+
+static VALUE
+ossl_ocspsres_alloc(VALUE klass)
+{
+    OCSP_SINGLERESP *sres;
+    VALUE obj;
+
+    obj = NewOCSPSingleRes(klass);
+    if (!(sres = OCSP_SINGLERESP_new()))
+	ossl_raise(eOCSPError, NULL);
+    SetOCSPSingleRes(obj, sres);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *   OpenSSL::OCSP::SingleResponse.new(der_string) -> SingleResponse
+ *
+ * Creates a new SingleResponse from +der_string+.
+ */
+static VALUE
+ossl_ocspsres_initialize(VALUE self, VALUE arg)
+{
+    OCSP_SINGLERESP *res;
+    const unsigned char *p;
+
+    arg = ossl_to_der_if_possible(arg);
+    StringValue(arg);
+    GetOCSPSingleRes(self, res);
+
+    p = (unsigned char*)RSTRING_PTR(arg);
+    if (!d2i_OCSP_SINGLERESP(&res, &p, RSTRING_LEN(arg)))
+	ossl_raise(eOCSPError, "d2i_OCSP_SINGLERESP");
+
+    return self;
+}
+
+static VALUE
+ossl_ocspsres_initialize_copy(VALUE self, VALUE other)
+{
+    OCSP_SINGLERESP *sres, *sres_old, *sres_new;
+
+    rb_check_frozen(self);
+    GetOCSPSingleRes(self, sres_old);
+    SafeGetOCSPSingleRes(other, sres);
+
+    sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
+    if (!sres_new)
+	ossl_raise(eOCSPError, "ASN1_item_dup");
+
+    SetOCSPSingleRes(self, sres_new);
+    OCSP_SINGLERESP_free(sres_old);
+
+    return self;
+}
+
+/*
+ * call-seq:
+ *   single_response.check_validity(nsec = 0, maxsec = -1) -> true | false
+ *
+ * Checks the validity of thisUpdate and nextUpdate fields of this
+ * SingleResponse. This checks the current time is within the range thisUpdate
+ * to nextUpdate.
+ *
+ * It is possible that the OCSP request takes a few seconds or the time is not
+ * accurate. To avoid rejecting a valid response, this method allows the times
+ * to be within +nsec+ of the current time.
+ *
+ * Some responders don't set the nextUpdate field. This may cause a very old
+ * response to be considered valid. The +maxsec+ parameter can be used to limit
+ * the age of responses.
+ */
+static VALUE
+ossl_ocspsres_check_validity(int argc, VALUE *argv, VALUE self)
+{
+    OCSP_SINGLERESP *sres;
+    ASN1_GENERALIZEDTIME *this_update, *next_update;
+    VALUE nsec_v, maxsec_v;
+    int nsec, maxsec, status, ret;
+
+    rb_scan_args(argc, argv, "02", &nsec_v, &maxsec_v);
+    nsec = NIL_P(nsec_v) ? 0 : NUM2INT(nsec_v);
+    maxsec = NIL_P(maxsec_v) ? -1 : NUM2INT(maxsec_v);
+
+    GetOCSPSingleRes(self, sres);
+    status = OCSP_single_get0_status(sres, NULL, NULL, &this_update, &next_update);
+    if (status < 0)
+	ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+    ret = OCSP_check_validity(this_update, next_update, nsec, maxsec);
+
+    if (ret)
+	return Qtrue;
+    else {
+	ossl_clear_error();
+	return Qfalse;
+    }
+}
+
+/*
+ * call-seq:
+ *   single_response.certid -> CertificateId
+ *
+ * Returns the CertificateId for which this SingleResponse is.
+ */
+static VALUE
+ossl_ocspsres_get_certid(VALUE self)
+{
+    OCSP_SINGLERESP *sres;
+    OCSP_CERTID *id;
+
+    GetOCSPSingleRes(self, sres);
+    id = OCSP_CERTID_dup(OCSP_SINGLERESP_get0_id(sres));
+
+    return ossl_ocspcertid_new(id);
+}
+
+/*
+ * call-seq:
+ *   single_response.cert_status -> Integer
+ *
+ * Returns the status of the certificate identified by the certid.
+ * The return value may be one of these constant:
+ *
+ * - V_CERTSTATUS_GOOD
+ * - V_CERTSTATUS_REVOKED
+ * - V_CERTSTATUS_UNKNOWN
+ *
+ * When the status is V_CERTSTATUS_REVOKED, the time at which the certificate
+ * was revoked can be retrieved by #revocation_time.
+ */
+static VALUE
+ossl_ocspsres_get_cert_status(VALUE self)
+{
+    OCSP_SINGLERESP *sres;
+    int status;
+
+    GetOCSPSingleRes(self, sres);
+    status = OCSP_single_get0_status(sres, NULL, NULL, NULL, NULL);
+    if (status < 0)
+	ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+    return INT2NUM(status);
+}
+
+/*
+ * call-seq:
+ *   single_response.this_update -> Time
+ */
+static VALUE
+ossl_ocspsres_get_this_update(VALUE self)
+{
+    OCSP_SINGLERESP *sres;
+    int status;
+    ASN1_GENERALIZEDTIME *time;
+
+    GetOCSPSingleRes(self, sres);
+    status = OCSP_single_get0_status(sres, NULL, NULL, &time, NULL);
+    if (status < 0)
+	ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+    return asn1time_to_time(time); /* will handle NULL */
+}
+
+/*
+ * call-seq:
+ *   single_response.next_update -> Time | nil
+ */
+static VALUE
+ossl_ocspsres_get_next_update(VALUE self)
+{
+    OCSP_SINGLERESP *sres;
+    int status;
+    ASN1_GENERALIZEDTIME *time;
+
+    GetOCSPSingleRes(self, sres);
+    status = OCSP_single_get0_status(sres, NULL, NULL, NULL, &time);
+    if (status < 0)
+	ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+    return asn1time_to_time(time);
+}
+
+/*
+ * call-seq:
+ *   single_response.revocation_time -> Time | nil
+ */
+static VALUE
+ossl_ocspsres_get_revocation_time(VALUE self)
+{
+    OCSP_SINGLERESP *sres;
+    int status;
+    ASN1_GENERALIZEDTIME *time;
+
+    GetOCSPSingleRes(self, sres);
+    status = OCSP_single_get0_status(sres, NULL, &time, NULL, NULL);
+    if (status < 0)
+	ossl_raise(eOCSPError, "OCSP_single_get0_status");
+    if (status != V_OCSP_CERTSTATUS_REVOKED)
+	ossl_raise(eOCSPError, "certificate is not revoked");
+
+    return asn1time_to_time(time);
+}
+
+/*
+ * call-seq:
+ *   single_response.revocation_reason -> Integer | nil
+ */
+static VALUE
+ossl_ocspsres_get_revocation_reason(VALUE self)
+{
+    OCSP_SINGLERESP *sres;
+    int status, reason;
+
+    GetOCSPSingleRes(self, sres);
+    status = OCSP_single_get0_status(sres, &reason, NULL, NULL, NULL);
+    if (status < 0)
+	ossl_raise(eOCSPError, "OCSP_single_get0_status");
+    if (status != V_OCSP_CERTSTATUS_REVOKED)
+	ossl_raise(eOCSPError, "certificate is not revoked");
+
+    return INT2NUM(reason);
+}
+
+/*
+ * call-seq:
+ *   single_response.extensions -> Array of X509::Extension
+ */
+static VALUE
+ossl_ocspsres_get_extensions(VALUE self)
+{
+    OCSP_SINGLERESP *sres;
+    X509_EXTENSION *ext;
+    int count, i;
+    VALUE ary;
+
+    GetOCSPSingleRes(self, sres);
+
+    count = OCSP_SINGLERESP_get_ext_count(sres);
+    ary = rb_ary_new2(count);
+    for (i = 0; i < count; i++) {
+	ext = OCSP_SINGLERESP_get_ext(sres, i);
+	rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */
+    }
+
+    return ary;
+}
+
+/*
+ * call-seq:
+ *   single_response.to_der -> String
+ *
+ * Encodes this SingleResponse into a DER-encoded string.
+ */
+static VALUE
+ossl_ocspsres_to_der(VALUE self)
+{
+    OCSP_SINGLERESP *sres;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetOCSPSingleRes(self, sres);
+    if ((len = i2d_OCSP_SINGLERESP(sres, NULL)) <= 0)
+	ossl_raise(eOCSPError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if (i2d_OCSP_SINGLERESP(sres, &p) <= 0)
+	ossl_raise(eOCSPError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+
+/*
  * OCSP::CertificateId
  */
 static VALUE
@@ -1313,7 +1698,7 @@ Init_ossl_ocsp(void) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L1698
      *   store = OpenSSL::X509::Store.new
      *   store.set_default_paths
      *
-     *   unless response.verify [], store then
+     *   unless response_basic.verify [], store then
      *     raise 'response is not signed by a trusted certificate'
      *   end
      *
@@ -1329,27 +1714,28 @@ Init_ossl_ocsp(void) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L1714
      *
      *   p request.check_nonce basic_response #=> value from -1 to 3
      *
-     * Then extract the status information from the basic response.  (You can
-     * check multiple certificates in a request, but for this example we only
-     * submitted one.)
-     *
-     *   response_certificate_id, status, reason, revocation_time,
-     *     this_update, next_update, extensions = basic_response.status
+     * Then extract the status information for the certificate from the basic
+     * response.
      *
-     * Then check the various fields.
+     *   single_response = basic_response.find_response(certificate_id)
      *
-     *   unless response_certificate_id == certificate_id then
-     *     raise 'certificate id mismatch'
+     *   unless single_response
+     *     raise 'basic_response does not have the status for the certificiate'
      *   end
      *
-     *   now = Time.now
+     * Then check the validity. A status issued in the future must be rejected.
      *
-     *   if this_update > now then
-     *     raise 'update date is in the future'
+     *   unless single_response.check_validity
+     *     raise 'this_update is in the future or next_update time has passed'
      *   end
      *
-     *   if now > next_update then
-     *     raise 'next update time has passed'
+     *   case single_response.cert_status
+     *   when OpenSSL::OCSP::V_CERTSTATUS_GOOD
+     *     puts 'certificate is still valid'
+     *   when OpenSSL::OCSP::V_CERTSTATUS_REVOKED
+     *     puts "certificate has been revoked at #{single_response.revocation_time}"
+     *   when OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
+     *     puts 'responder doesn't know about the certificate'
      *   end
      */
 
@@ -1409,11 +1795,32 @@ Init_ossl_ocsp(void) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L1795
     rb_define_method(cOCSPBasicRes, "add_nonce", ossl_ocspbres_add_nonce, -1);
     rb_define_method(cOCSPBasicRes, "add_status", ossl_ocspbres_add_status, 7);
     rb_define_method(cOCSPBasicRes, "status", ossl_ocspbres_get_status, 0);
+    rb_define_method(cOCSPBasicRes, "responses", ossl_ocspbres_get_responses, 0);
+    rb_define_method(cOCSPBasicRes, "find_response", ossl_ocspbres_find_response, 1);
     rb_define_method(cOCSPBasicRes, "sign", ossl_ocspbres_sign, -1);
     rb_define_method(cOCSPBasicRes, "verify", ossl_ocspbres_verify, -1);
     rb_define_method(cOCSPBasicRes, "to_der", ossl_ocspbres_to_der, 0);
 
     /*
+     * An OpenSSL::OCSP::SingleResponse represents an OCSP SingleResponse
+     * structure, which contains the basic information of the status of the
+     * certificate.
+     */
+    cOCSPSingleRes = rb_define_class_under(mOCSP, "SingleResponse", rb_cObject);
+    rb_define_alloc_func(cOCSPSingleRes, ossl_ocspsres_alloc);
+    rb_define_copy_func(cOCSPSingleRes, ossl_ocspsres_initialize_copy);
+    rb_define_method(cOCSPSingleRes, "initialize", ossl_ocspsres_initialize, 1);
+    rb_define_method(cOCSPSingleRes, "check_validity", ossl_ocspsres_check_validity, -1);
+    rb_define_method(cOCSPSingleRes, "certid", ossl_ocspsres_get_certid, 0);
+    rb_define_method(cOCSPSingleRes, "cert_status", ossl_ocspsres_get_cert_status, 0);
+    rb_define_method(cOCSPSingleRes, "this_update", ossl_ocspsres_get_this_update, 0);
+    rb_define_method(cOCSPSingleRes, "next_update", ossl_ocspsres_get_next_update, 0);
+    rb_define_method(cOCSPSingleRes, "revocation_time", ossl_ocspsres_get_revocation_time, 0);
+    rb_define_method(cOCSPSingleRes, "revocation_reason", ossl_ocspsres_get_revocation_reason, 0);
+    rb_define_method(cOCSPSingleRes, "extensions", ossl_ocspsres_get_extensions, 0);
+    rb_define_method(cOCSPSingleRes, "to_der", ossl_ocspsres_to_der, 0);
+
+    /*
      * An OpenSSL::OCSP::CertificateId identifies a certificate to the CA so
      * that a status check can be performed.
      */
Index: test/openssl/test_ocsp.rb
===================================================================
--- test/openssl/test_ocsp.rb	(revision 55456)
+++ test/openssl/test_ocsp.rb	(revision 55457)
@@ -162,6 +162,58 @@ class OpenSSL::TestOCSP < OpenSSL::TestC https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ocsp.rb#L162
     assert_equal bres.to_der, bres.dup.to_der
   end
 
+  def test_basic_response_response_operations
+    bres = OpenSSL::OCSP::BasicResponse.new
+    now = Time.at(Time.now.to_i)
+    cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+    cid2 = OpenSSL::OCSP::CertificateId.new(@cert2, @ca_cert, OpenSSL::Digest::SHA1.new)
+    cid3 = OpenSSL::OCSP::CertificateId.new(@ca_cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+    bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, now - 400, -300, nil, nil)
+    bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, [])
+
+    assert_equal 2, bres.responses.size
+    single = bres.responses.first
+    assert_equal cid1.to_der, single.certid.to_der
+    assert_equal OpenSSL::OCSP::V_CERTSTATUS_REVOKED, single.cert_status
+    assert_equal OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, single.revocation_reason
+    assert_equal now - 400, single.revocation_time
+    assert_equal now - 300, single.this_update
+    assert_equal nil, single.next_update
+    assert_equal [], single.extensions
+
+    assert_equal cid2.to_der, bres.find_response(cid2).certid.to_der
+    assert_equal nil, bres.find_response(cid3)
+  end
+
+  def test_single_response_der
+    bres = OpenSSL::OCSP::BasicResponse.new
+    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)
+    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, nil)
+    single = bres.responses[0]
+    der = single.to_der
+    asn1 = OpenSSL::ASN1.decode(der)
+    assert_equal :CONTEXT_SPECIFIC, asn1.value[1].tag_class
+    assert_equal 0, asn1.value[1].tag # good
+    assert_equal der, OpenSSL::OCSP::SingleResponse.new(der).to_der
+  end
+
+  def test_single_response_check_validity
+    bres = OpenSSL::OCSP::BasicResponse.new
+    cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+    cid2 = OpenSSL::OCSP (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]