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

ruby-changes:43335

From: rhe <ko1@a...>
Date: Tue, 14 Jun 2016 21:41:00 +0900 (JST)
Subject: [ruby-changes:43335] rhe:r55409 (trunk): openssl: add missing #to_der to OCSP::{CertificateId, BasicResponse}

rhe	2016-06-14 21:40:55 +0900 (Tue, 14 Jun 2016)

  New Revision: 55409

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

  Log:
    openssl: add missing #to_der to OCSP::{CertificateId,BasicResponse}
    
    * ext/openssl/ossl_ocsp.c (ossl_ocspbres_to_der, ossl_ocspcid_to_der):
      Implement #to_der methods for OCSP::BasicResponse and
      OCSP::CertificateId.
    
      (ossl_ocspreq_initialize, ossl_ocspres_initialize): Use GetOCSP*()
      instead of raw DATA_PTR().
    
      (ossl_ocspbres_initialize, ossl_ocspcid_initialize): Allow
      initializing from DER string.
    
      (Init_ossl_ocsp): Define new #to_der methods.
    
    * test/openssl/test_ocsp.rb: Test these changes. Also add missing tests
      for OCSP::{Response,Request}#to_der.

  Modified files:
    trunk/ChangeLog
    trunk/ext/openssl/ossl_ocsp.c
    trunk/test/openssl/test_ocsp.rb
Index: test/openssl/test_ocsp.rb
===================================================================
--- test/openssl/test_ocsp.rb	(revision 55408)
+++ test/openssl/test_ocsp.rb	(revision 55409)
@@ -8,6 +8,10 @@ class OpenSSL::TestOCSP < OpenSSL::TestC https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ocsp.rb#L8
     ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA")
     ca_key = OpenSSL::TestUtils::TEST_KEY_RSA1024
     ca_serial = 0xabcabcabcabc
+    ca_exts = [
+      ["basicConstraints", "CA:TRUE", true],
+      ["keyUsage", "cRLSign,keyCertSign", true],
+    ]
 
     subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert")
     @key = OpenSSL::TestUtils::TEST_KEY_RSA1024
@@ -17,9 +21,17 @@ class OpenSSL::TestOCSP < OpenSSL::TestC https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ocsp.rb#L21
     dgst = OpenSSL::Digest::SHA1.new
 
     @ca_cert = OpenSSL::TestUtils.issue_cert(
-       ca_subj, ca_key, ca_serial, now, now+3600, [], nil, nil, dgst)
+       ca_subj, ca_key, ca_serial, now, now+3600, ca_exts, nil, nil, dgst)
     @cert = OpenSSL::TestUtils.issue_cert(
-       subj, @key, serial, now, now+3600, [], @ca_cert, nil, dgst)
+       subj, @key, serial, now, now+3600, [], @ca_cert, ca_key, dgst)
+
+    @key2 = OpenSSL::TestUtils::TEST_KEY_RSA2048
+    cert2_exts = [
+      ["extendedKeyUsage", "OCSPSigning", true],
+    ]
+    @cert2 = OpenSSL::TestUtils.issue_cert(
+       OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert2"),
+       @key2, serial+1, now, now+3600, cert2_exts, @ca_cert, ca_key, "SHA256")
   end
 
   def test_new_certificate_id
@@ -34,6 +46,30 @@ class OpenSSL::TestOCSP < OpenSSL::TestC https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ocsp.rb#L46
     assert_equal @cert.serial, cid.serial
   end if defined?(OpenSSL::Digest::SHA256)
 
+  def test_certificate_id_der
+    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) # hash algorithm defaults to SHA-1
+    der = cid.to_der
+    asn1 = OpenSSL::ASN1.decode(der)
+    assert_equal OpenSSL::ASN1.ObjectId("SHA1").to_der, asn1.value[0].value[0].to_der
+    assert_equal OpenSSL::Digest::SHA1.digest(@cert.issuer.to_der), asn1.value[1].value
+    assert_equal OpenSSL::Digest::SHA1.digest(OpenSSL::ASN1.decode(@ca_cert.to_der).value[0].value[6].value[1].value), asn1.value[2].value
+    assert_equal @cert.serial, asn1.value[3].value
+    assert_equal der, OpenSSL::OCSP::CertificateId.new(der).to_der
+  end
+
+  def test_request_der
+    request = OpenSSL::OCSP::Request.new
+    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+    request.add_certid(cid)
+    request.sign(@cert, @key, [@ca_cert], 0)
+    asn1 = OpenSSL::ASN1.decode(request.to_der)
+    assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der
+    assert_equal OpenSSL::ASN1.ObjectId("sha1WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der
+    assert_equal @cert.to_der, asn1.value[1].value[0].value[2].value[0].value[0].to_der
+    assert_equal @ca_cert.to_der, asn1.value[1].value[0].value[2].value[0].value[1].to_der
+    assert_equal asn1.to_der, OpenSSL::OCSP::Request.new(asn1.to_der).to_der
+  end
+
   def test_new_ocsp_request
     request = OpenSSL::OCSP::Request.new
     cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
@@ -43,6 +79,33 @@ class OpenSSL::TestOCSP < OpenSSL::TestC https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ocsp.rb#L79
     # in current implementation not same instance of certificate id, but should contain same data
     assert_equal cid.serial, request.certid.first.serial
   end
+
+  def test_basic_response_der
+    bres = OpenSSL::OCSP::BasicResponse.new
+    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])
+    bres.add_nonce("NONCE")
+    bres.sign(@cert2, @key2, [@ca_cert], 0)
+    der = bres.to_der
+    asn1 = OpenSSL::ASN1.decode(der)
+    assert_equal cid.to_der, asn1.value[0].value.find { |a| a.class == OpenSSL::ASN1::Sequence }.value[0].value[0].to_der
+    assert_equal OpenSSL::ASN1.Sequence([@cert2, @ca_cert]).to_der, asn1.value[3].value[0].to_der
+    assert_equal der, OpenSSL::OCSP::BasicResponse.new(der).to_der
+  end
+
+  def test_response_der
+    bres = OpenSSL::OCSP::BasicResponse.new
+    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
+    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])
+    bres.sign(@cert2, @key2, [@ca_cert], 0)
+    res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres)
+    der = res.to_der
+    asn1 = OpenSSL::ASN1.decode(der)
+    assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, asn1.value[0].value
+    assert_equal OpenSSL::ASN1.ObjectId("basicOCSPResponse").to_der, asn1.value[1].value[0].value[0].to_der
+    assert_equal bres.to_der, asn1.value[1].value[0].value[1].value
+    assert_equal der, OpenSSL::OCSP::Response.new(der).to_der
+  end
 end
 
 end
Index: ext/openssl/ossl_ocsp.c
===================================================================
--- ext/openssl/ossl_ocsp.c	(revision 55408)
+++ ext/openssl/ossl_ocsp.c	(revision 55409)
@@ -180,15 +180,13 @@ ossl_ocspreq_initialize(int argc, VALUE https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L180
 
     rb_scan_args(argc, argv, "01", &arg);
     if(!NIL_P(arg)){
-	OCSP_REQUEST *req = DATA_PTR(self), *x;
+	OCSP_REQUEST *req;
+	GetOCSPReq(self, req);
 	arg = ossl_to_der_if_possible(arg);
 	StringValue(arg);
-	p = (unsigned char*)RSTRING_PTR(arg);
-	x = d2i_OCSP_REQUEST(&req, &p, RSTRING_LEN(arg));
-	DATA_PTR(self) = req;
-	if(!x){
+	p = (unsigned char *)RSTRING_PTR(arg);
+	if (!d2i_OCSP_REQUEST(&req, &p, RSTRING_LEN(arg)))
 	    ossl_raise(eOCSPError, "cannot load DER encoded request");
-	}
     }
 
     return self;
@@ -463,15 +461,13 @@ ossl_ocspres_initialize(int argc, VALUE https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L461
 
     rb_scan_args(argc, argv, "01", &arg);
     if(!NIL_P(arg)){
-	OCSP_RESPONSE *res = DATA_PTR(self), *x;
+	OCSP_RESPONSE *res;
+	GetOCSPRes(self, res);
 	arg = ossl_to_der_if_possible(arg);
 	StringValue(arg);
 	p = (unsigned char *)RSTRING_PTR(arg);
-	x = d2i_OCSP_RESPONSE(&res, &p, RSTRING_LEN(arg));
-	DATA_PTR(self) = res;
-	if(!x){
+	if (!d2i_OCSP_RESPONSE(&res, &p, RSTRING_LEN(arg)))
 	    ossl_raise(eOCSPError, "cannot load DER encoded response");
-	}
     }
 
     return self;
@@ -584,14 +580,29 @@ ossl_ocspbres_alloc(VALUE klass) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L580
 
 /*
  * call-seq:
- *   OpenSSL::OCSP::BasicResponse.new(*) -> basic_response
+ *   OpenSSL::OCSP::BasicResponse.new(der_string = nil) -> basic_response
  *
- * Creates a new BasicResponse and ignores all arguments.
+ * Creates a new BasicResponse. If +der_string+ is given, decodes +der_string+
+ * as DER.
  */
 
 static VALUE
 ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
 {
+    VALUE arg;
+    const unsigned char *p;
+
+    rb_scan_args(argc, argv, "01", &arg);
+    if (!NIL_P(arg)) {
+	OCSP_BASICRESP *res;
+	GetOCSPBasicRes(self, res);
+	arg = ossl_to_der_if_possible(arg);
+	StringValue(arg);
+	p = (unsigned char *)RSTRING_PTR(arg);
+	if (!d2i_OCSP_BASICRESP(&res, &p, RSTRING_LEN(arg)))
+	    ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP");
+    }
+
     return self;
 }
 
@@ -856,6 +867,32 @@ ossl_ocspbres_verify(int argc, VALUE *ar https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L867
 }
 
 /*
+ * call-seq:
+ *   basic_response.to_der -> String
+ *
+ * Encodes this basic response into a DER-encoded string.
+ */
+static VALUE
+ossl_ocspbres_to_der(VALUE self)
+{
+    OCSP_BASICRESP *res;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetOCSPBasicRes(self, res);
+    if ((len = i2d_OCSP_BASICRESP(res, NULL)) <= 0)
+	ossl_raise(eOCSPError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if (i2d_OCSP_BASICRESP(res, &p) <= 0)
+	ossl_raise(eOCSPError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+/*
  * OCSP::CertificateId
  */
 static VALUE
@@ -875,10 +912,14 @@ ossl_ocspcid_alloc(VALUE klass) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L912
 /*
  * call-seq:
  *   OpenSSL::OCSP::CertificateId.new(subject, issuer, digest = nil) -> certificate_id
+ *   OpenSSL::OCSP::CertificateId.new(der_string)                    -> certificate_id
  *
  * Creates a new OpenSSL::OCSP::CertificateId for the given +subject+ and
  * +issuer+ X509 certificates.  The +digest+ is used to compute the
  * certificate ID and must be an OpenSSL::Digest instance.
+ *
+ * If only one argument is given, decodes it as DER representation of a
+ * certificate ID.
  */
 
 static VALUE
@@ -889,7 +930,17 @@ ossl_ocspcid_initialize(int argc, VALUE https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L930
     VALUE subject, issuer, digest;
     const EVP_MD *md;
 
-    if (rb_scan_args(argc, argv, "21", &subject, &issuer, &digest) == 0) {
+    GetOCSPCertId(self, id);
+    if (rb_scan_args(argc, argv, "12", &subject, &issuer, &digest) == 1) {
+	VALUE arg;
+	const unsigned char *p;
+
+	arg = ossl_to_der_if_possible(subject);
+	StringValue(arg);
+	p = (unsigned char *)RSTRING_PTR(arg);
+	if (!d2i_OCSP_CERTID(&id, &p, RSTRING_LEN(arg)))
+	    ossl_raise(eOCSPError, "d2i_OCSP_CERTID");
+
 	return self;
     }
 
@@ -904,9 +955,8 @@ ossl_ocspcid_initialize(int argc, VALUE https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L955
     }
     if(!newid)
 	ossl_raise(eOCSPError, NULL);
-    GetOCSPCertId(self, id);
     OCSP_CERTID_free(id);
-    RDATA(self)->data = newid;
+    SetOCSPCertId(self, newid);
 
     return self;
 }
@@ -971,6 +1021,32 @@ ossl_ocspcid_get_serial(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L1021
     return asn1integer_to_num(serial);
 }
 
+/*
+ * call-seq:
+ *   certificate_id.to_der -> String
+ *
+ * Encodes this certificate identifier into a DER-encoded string.
+ */
+static VALUE
+ossl_ocspcid_to_der(VALUE self)
+{
+    OCSP_CERTID *id;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetOCSPCertId(self, id);
+    if ((len = i2d_OCSP_CERTID(id, NULL)) <= 0)
+	ossl_raise(eOCSPError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if (i2d_OCSP_CERTID(id, &p) <= 0)
+	ossl_raise(eOCSPError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
 void
 Init_ossl_ocsp(void)
 {
@@ -1138,6 +1214,7 @@ Init_ossl_ocsp(void) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L1214
     rb_define_method(cOCSPBasicRes, "status", ossl_ocspbres_get_status, 0);
     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::CertificateId identifies a certificate to the CA so
@@ -1150,6 +1227,7 @@ Init_ossl_ocsp(void) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ocsp.c#L1227
     rb_define_method(cOCSPCertId, "cmp", ossl_ocspcid_cmp, 1);
     rb_define_method(cOCSPCertId, "cmp_issuer", ossl_ocspcid_cmp_issuer, 1);
     rb_define_method(cOCSPCertId, "serial", ossl_ocspcid_get_serial, 0);
+    rb_define_method(cOCSPCertId, "to_der", ossl_ocspcid_to_der, 0);
 
     /* Internal error in issuer */
     rb_define_const(mOCSP, "RESPONSE_STATUS_INTERNALERROR", INT2NUM(OCSP_RESPONSE_STATUS_INTERNALERROR));
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 55408)
+++ ChangeLog	(revision 55409)
@@ -1,3 +1,20 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Jun 14 21:40:42 2016  Kazuki Yamaguchi  <k@r...>
+
+	* ext/openssl/ossl_ocsp.c (ossl_ocspbres_to_der, ossl_ocspcid_to_der):
+	  Implement #to_der methods for OCSP::BasicResponse and
+	  OCSP::CertificateId.
+
+	  (ossl_ocspreq_initialize, ossl_ocspres_initialize): Use GetOCSP*()
+	  instead of raw DATA_PTR().
+
+	  (ossl_ocspbres_initialize, ossl_ocspcid_initialize): Allow
+	  initializing from DER string.
+
+	  (Init_ossl_ocsp): Define new #to_der methods.
+
+	* test/openssl/test_ocsp.rb: Test these changes. Also add missing tests
+	  for OCSP::{Response,Request}#to_der.
+
 Tue Jun 14 21:35:00 2016  Kazuki Yamaguchi  <k@r...>
 
 	* ext/openssl/openssl_missing.h (DH_set0_pqg, RSA_set0_key):

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

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