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

ruby-changes:19989

From: emboss <ko1@a...>
Date: Mon, 13 Jun 2011 05:43:51 +0900 (JST)
Subject: [ruby-changes:19989] emboss:r32036 (trunk): * ext/openssl/ossl_pkey.c: added PKey.read module function that allow

emboss	2011-06-13 05:39:38 +0900 (Mon, 13 Jun 2011)

  New Revision: 32036

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=32036

  Log:
    * ext/openssl/ossl_pkey.c: added PKey.read module function that allow
      reading arbitrary public/private keys from DER-/PEM-encoded File or
      string instances.
    * ext/openssl/ossl_pkey_dh.c: improved documentation.
    * test/openssl/utils.rb: added EC test key.
    * test/openssl/test_pkey_rsa.rb
      test/openssl/test_pkey_dsa.rb: Test PKey.read. Reuse keys from 
      OpenSSL::TestUtils.
    * test/openssl/test_pkey_ec.rb: Created test file for EC tests.
      Test PKey.read.
      [Ruby 1.9 - Feature #4424] [ruby-core:35330]

  Added files:
    trunk/test/openssl/test_pkey_ec.rb
  Modified files:
    trunk/ChangeLog
    trunk/ext/openssl/ossl_pkey.c
    trunk/ext/openssl/ossl_pkey_dh.c
    trunk/test/openssl/test_pkey_dsa.rb
    trunk/test/openssl/test_pkey_rsa.rb
    trunk/test/openssl/utils.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 32035)
+++ ChangeLog	(revision 32036)
@@ -1,3 +1,17 @@
+Mon Jun 13 05:17:29 2011  Martin Bosslet  <Martin.Bosslet@g...>
+
+	* ext/openssl/ossl_pkey.c: added PKey.read module function that allows
+	  reading arbitrary public/private keys from DER-/PEM-encoded File or
+	  string instances.
+	* ext/openssl/ossl_pkey_dh.c: improved documentation.
+	* test/openssl/utils.rb: added EC test key.
+	* test/openssl/test_pkey_rsa.rb
+	  test/openssl/test_pkey_dsa.rb: Test PKey.read. Reuse keys from 
+	  OpenSSL::TestUtils.
+	* test/openssl/test_pkey_ec.rb: Created test file for EC tests.
+	  Test PKey.read.
+	  [Ruby 1.9 - Feature #4424] [ruby-core:35330]
+
 Mon Jun 13 04:42:24 2011  Koichi Sasada  <ko1@a...>
 
 	* ext/objspace/objspace.c (total_i): fix to skip no ruby objects.
@@ -85,8 +99,7 @@
 
 Sun Jun 12 09:32:13 2011  Nobuyoshi Nakada  <nobu@r...>
 
-	* atomic.h (ATOMIC_OR): _InterlockedOr is not available on migw.
-
+	* atomic.h (ATOMIC_OR): _InterlockedOr is not available on migw.h
 	* gc.c (rb_gc_set_params): VM_OBJSPACE is disabled on mignw.
 
 Sun Jun 12 01:07:09 2011  Tadayoshi Funaba  <tadf@d...>
Index: ext/openssl/ossl_pkey.c
===================================================================
--- ext/openssl/ossl_pkey.c	(revision 32035)
+++ ext/openssl/ossl_pkey.c	(revision 32036)
@@ -18,6 +18,9 @@
 VALUE ePKeyError;
 ID id_private_q;
 
+#define reset_bio(b)		(void)BIO_reset((b)); \
+				(void)ERR_get_error();
+
 /*
  * callback for generating keys
  */
@@ -85,6 +88,54 @@
     return ossl_pkey_new(pkey);
 }
 
+/*
+ *  call-seq:
+ *     OpenSSL::PKey.read(string [, pwd ] ) -> PKey
+ *     OpenSSL::PKey.read(file [, pwd ]) -> PKey
+ *
+ * === Parameters
+ * * +string+ is a DER- or PEM-encoded string containing an arbitrary private
+ * or public key.
+ * * +file+ is an instance of +File+ containing a DER- or PEM-encoded
+ * arbitrary private or public key.
+ * * +pwd+ is an optional password in case +string+ or +file+ is an encrypted
+ * PEM resource.
+ */
+static VALUE 
+ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
+{
+     FILE *fp;
+     EVP_PKEY *pkey;
+     BIO *bio;
+     VALUE data, pass;
+     char *passwd = NULL;
+
+     rb_scan_args(argc, argv, "11", &data, &pass);
+
+     bio = ossl_obj2bio(data);
+     if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) {
+	reset_bio(bio);
+	if (!NIL_P(pass)) {
+	    passwd = StringValuePtr(pass);
+	}
+	if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, passwd))) {
+	    reset_bio(bio);
+	    if (!(pkey = d2i_PUBKEY_bio(bio, NULL))) {
+		reset_bio(bio);
+		if (!NIL_P(pass)) {
+		    passwd = StringValuePtr(pass);
+		}
+		pkey = PEM_read_bio_PUBKEY(bio, NULL, ossl_pem_passwd_cb, passwd);
+	    }
+	}
+    }
+
+    BIO_free(bio);
+    if (!pkey)
+	ossl_raise(rb_eArgError, "Could not parse PKey");
+    return ossl_pkey_new(pkey);
+}
+
 EVP_PKEY *
 GetPKeyPtr(VALUE obj)
 {
@@ -330,6 +381,8 @@
      */
     cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
 
+    rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
+
     rb_define_alloc_func(cPKey, ossl_pkey_alloc);
     rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
 
Index: ext/openssl/ossl_pkey_dh.c
===================================================================
--- ext/openssl/ossl_pkey_dh.c	(revision 32035)
+++ ext/openssl/ossl_pkey_dh.c	(revision 32036)
@@ -338,15 +338,17 @@
  *  call-seq:
  *     dh.public_key -> aDH
  *
- * Returns a new DH instance that carries just the public information.
- * If the current instance has also private information, this will no
+ * Returns a new DH instance that carries just the public information, i.e.
+ * the prime +p+ and the generator +g+, but no public/private key yet. Such
+ * a pair may be generated using DH#generate_key!.
+ * If the current instance already contains private information, this will no
  * longer be present in the new instance. This feature is helpful for
  * publishing the public information without leaking any of the private
  * information.
  *
  * === Example
  *  dh = OpenSSL::PKey::DH.new(2048) # has public and private information
- *  pub_key = dh.public_key # has only the public part available
+ *  pub_key = dh.public_key # contains only prime and generator
  *  pub_key_der = pub_key.to_der # it's safe to publish this
  */
 static VALUE
@@ -394,10 +396,15 @@
 
 /*
  *  call-seq:
- *     dh.generate_key -> self
+ *     dh.generate_key! -> self
  *
- * Generates a private key unless one already exists. It also computes the
- * public key for the generated private key.
+ * Generates a private and public key unless one already exists.
+ *
+ * === Example
+ *   dh = OpenSSL::PKey::DH.new(2048)
+ *   public_key = dh.public_key #contains no private/public key yet
+ *   public_key.generate_key!
+ *   puts public_key.private? # => true
  */
 static VALUE
 ossl_dh_generate_key(VALUE self)
Index: test/openssl/test_pkey_ec.rb
===================================================================
--- test/openssl/test_pkey_ec.rb	(revision 0)
+++ test/openssl/test_pkey_ec.rb	(revision 32036)
@@ -0,0 +1,68 @@
+require_relative 'utils'
+
+if defined?(OpenSSL)
+
+class OpenSSL::TestPKeyEC < Test::Unit::TestCase
+  def test_new
+    group = OpenSSL::PKey::EC::Group.new('prime256v1')
+    ec = OpenSSL::PKey::EC.new(group)
+    ec.generate_key
+    assert(ec.private_key?)
+    assert(ec.public_key?)
+  end
+
+  def test_read_private_key_der
+    ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1
+    der = ec.to_der
+    ec2 = OpenSSL::PKey.read(der)
+    assert(ec2.private_key?)
+    assert_equal(der, ec2.to_der)
+  end
+
+  def test_read_private_key_pem
+    ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1
+    pem = ec.to_pem
+    ec2 = OpenSSL::PKey.read(pem)
+    assert(ec2.private_key?)
+    assert_equal(pem, ec2.to_pem)
+  end
+
+  def test_read_public_key_der
+    ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1
+    group = OpenSSL::PKey::EC::Group.new('prime256v1')
+    ec2 = OpenSSL::PKey::EC.new(group)
+    ec2.public_key = ec.public_key
+    der = ec2.to_der
+    ec3 = OpenSSL::PKey.read(der)
+    assert(!ec3.private_key?)
+    assert_equal(der, ec3.to_der)
+  end
+
+  def test_read_public_key_pem
+    ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1
+    group = OpenSSL::PKey::EC::Group.new('prime256v1')
+    ec2 = OpenSSL::PKey::EC.new(group)
+    ec2.public_key = ec.public_key
+    pem = ec2.to_pem
+    ec3 = OpenSSL::PKey.read(pem)
+    assert(!ec3.private_key?)
+    assert_equal(pem, ec3.to_pem)
+  end
+
+  def test_read_private_key_pem_pw
+    ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1
+    pem = ec.to_pem(OpenSSL::Cipher.new('AES-128-CBC'), 'secret')
+    #callback form for password
+    ec2 = OpenSSL::PKey.read(pem) do
+      'secret'
+    end
+    assert(ec2.private_key?)
+    # pass password directly
+    ec2 = OpenSSL::PKey.read(pem, 'secret')
+    assert(ec2.private_key?)
+    #omit pem equality check, will be different due to cipher iv
+  end
+
+end
+
+end
Index: test/openssl/test_pkey_dsa.rb
===================================================================
--- test/openssl/test_pkey_dsa.rb	(revision 32035)
+++ test/openssl/test_pkey_dsa.rb	(revision 32036)
@@ -23,7 +23,7 @@
   end
 
   def test_sys_sign_verify
-    key = OpenSSL::PKey::DSA.new(256)
+    key = OpenSSL::TestUtils::TEST_KEY_DSA256
     data = 'Sign me!'
     digest = OpenSSL::Digest::SHA1.digest(data)
     sig = key.syssign(digest)
@@ -45,7 +45,7 @@
 end
 
   def test_digest_state_irrelevant_verify
-    key = OpenSSL::PKey::DSA.new(256)
+    key = OpenSSL::TestUtils::TEST_KEY_DSA256
     digest1 = OpenSSL::Digest::DSS1.new
     digest2 = OpenSSL::Digest::DSS1.new
     data = 'Sign me!'
@@ -128,7 +128,7 @@
   end
 
   def test_export_format_is_DSA_PUBKEY_pem
-    key = OpenSSL::PKey::DSA.new(256)
+    key = OpenSSL::TestUtils::TEST_KEY_DSA256
     pem = key.public_key.to_pem
     pem.gsub!(/^-+(\w|\s)+-+$/, "") # eliminate --------BEGIN...-------
     asn1 = OpenSSL::ASN1.decode(Base64.decode64(pem))
@@ -156,10 +156,56 @@
     assert_equal(key.pub_key, pub_key.value)
   end
 
+  def test_read_private_key_der
+    key = OpenSSL::TestUtils::TEST_KEY_DSA256
+    der = key.to_der
+    key2 = OpenSSL::PKey.read(der)
+    assert(key2.private?)
+    assert_equal(der, key2.to_der)
+  end
+
+  def test_read_private_key_pem
+    key = OpenSSL::TestUtils::TEST_KEY_DSA256
+    pem = key.to_pem
+    key2 = OpenSSL::PKey.read(pem)
+    assert(key2.private?)
+    assert_equal(pem, key2.to_pem)
+  end
+
+  def test_read_public_key_der
+    key = OpenSSL::TestUtils::TEST_KEY_DSA256.public_key
+    der = key.to_der
+    key2 = OpenSSL::PKey.read(der)
+    assert(!key2.private?)
+    assert_equal(der, key2.to_der)
+  end
+
+  def test_read_public_key_pem
+    key = OpenSSL::TestUtils::TEST_KEY_DSA256.public_key
+    pem = key.to_pem
+    key2 = OpenSSL::PKey.read(pem)
+    assert(!key2.private?)
+    assert_equal(pem, key2.to_pem)
+  end
+
+  def test_read_private_key_pem_pw
+    key = OpenSSL::TestUtils::TEST_KEY_DSA256
+    pem = key.to_pem(OpenSSL::Cipher.new('AES-128-CBC'), 'secret')
+    #callback form for password
+    key2 = OpenSSL::PKey.read(pem) do
+      'secret'
+    end
+    assert(key2.private?)
+    # pass password directly
+    key2 = OpenSSL::PKey.read(pem, 'secret')
+    assert(key2.private?)
+    #omit pem equality check, will be different due to cipher iv
+  end
+
   private
 
   def check_sign_verify(digest)
-    key = OpenSSL::PKey::DSA.new(256)
+    key = OpenSSL::TestUtils::TEST_KEY_DSA256
     data = 'Sign me!'
     sig = key.sign(digest, data)
     assert(key.verify(digest, sig, data))
Index: test/openssl/utils.rb
===================================================================
--- test/openssl/utils.rb	(revision 32035)
+++ test/openssl/utils.rb	(revision 32036)
@@ -80,6 +80,14 @@
 -----END DSA PRIVATE KEY-----
   _end_of_pem_
 
+  TEST_KEY_EC_P256V1 = OpenSSL::PKey::EC.new <<-_end_of_pem_
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49
+AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt
+CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg==
+-----END EC PRIVATE KEY-----
+  _end_of_pem_
+
   module_function
 
   def issue_cert(dn, key, serial, not_before, not_after, extensions,
Index: test/openssl/test_pkey_rsa.rb
===================================================================
--- test/openssl/test_pkey_rsa.rb	(revision 32035)
+++ test/openssl/test_pkey_rsa.rb	(revision 32036)
@@ -49,7 +49,7 @@
   end
 
   def test_sign_verify
-    key = OpenSSL::PKey::RSA.new(512)
+    key = OpenSSL::TestUtils::TEST_KEY_RSA1024
     digest = OpenSSL::Digest::SHA1.new
     data = 'Sign me!'
     sig = key.sign(digest, data)
@@ -57,7 +57,7 @@
   end
 
   def test_digest_state_irrelevant_sign
-    key = OpenSSL::PKey::RSA.new(512)
+    key = OpenSSL::TestUtils::TEST_KEY_RSA1024
     digest1 = OpenSSL::Digest::SHA1.new
     digest2 = OpenSSL::Digest::SHA1.new
     data = 'Sign me!'
@@ -68,7 +68,7 @@
   end
 
   def test_digest_state_irrelevant_verify
-    key = OpenSSL::PKey::RSA.new(512)
+    key = OpenSSL::TestUtils::TEST_KEY_RSA1024
     digest1 = OpenSSL::Digest::SHA1.new
     digest2 = OpenSSL::Digest::SHA1.new
     data = 'Sign me!'
@@ -164,6 +164,47 @@
     check_PUBKEY(asn1, key)
   end
 
+  def test_read_private_key_der
+    der = OpenSSL::TestUtils::TEST_KEY_RSA1024.to_der
+    key = OpenSSL::PKey.read(der)
+    assert(key.private?)
+    assert_equal(der, key.to_der)
+  end
+
+  def test_read_private_key_pem
+    pem = OpenSSL::TestUtils::TEST_KEY_RSA1024.to_pem
+    key = OpenSSL::PKey.read(pem)
+    assert(key.private?)
+    assert_equal(pem, key.to_pem)
+  end
+
+  def test_read_public_key_der
+    der = OpenSSL::TestUtils::TEST_KEY_RSA1024.public_key.to_der
+    key = OpenSSL::PKey.read(der)
+    assert(!key.private?)
+    assert_equal(der, key.to_der)
+  end
+
+  def test_read_public_key_pem
+    pem = OpenSSL::TestUtils::TEST_KEY_RSA1024.public_key.to_pem
+    key = OpenSSL::PKey.read(pem)
+    assert(!key.private?)
+    assert_equal(pem, key.to_pem)
+  end
+
+  def test_read_private_key_pem_pw
+    pem = OpenSSL::TestUtils::TEST_KEY_RSA1024.to_pem(OpenSSL::Cipher.new('AES-128-CBC'), 'secret')
+    #callback form for password
+    key = OpenSSL::PKey.read(pem) do
+      'secret'
+    end
+    assert(key.private?)
+    # pass password directly
+    key = OpenSSL::PKey.read(pem, 'secret')
+    assert(key.private?)
+    #omit pem equality check, will be different due to cipher iv
+  end
+
   private
 
   def check_PUBKEY(asn1, key)

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

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