mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@32036 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
7b614a53dd
commit
bbb3cfb12b
7 changed files with 251 additions and 15 deletions
17
ChangeLog
17
ChangeLog
|
@ -1,3 +1,17 @@
|
|||
Mon Jun 13 05:17:29 2011 Martin Bosslet <Martin.Bosslet@googlemail.com>
|
||||
|
||||
* 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@atdot.net>
|
||||
|
||||
* ext/objspace/objspace.c (total_i): fix to skip no ruby objects.
|
||||
|
@ -85,8 +99,7 @@ Sun Jun 12 11:16:59 2011 Tanaka Akira <akr@fsij.org>
|
|||
|
||||
Sun Jun 12 09:32:13 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* 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@dotrb.org>
|
||||
|
|
|
@ -18,6 +18,9 @@ VALUE cPKey;
|
|||
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 @@ ossl_pkey_new_from_file(VALUE filename)
|
|||
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 @@ Init_ossl_pkey()
|
|||
*/
|
||||
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);
|
||||
|
||||
|
|
|
@ -338,15 +338,17 @@ ossl_dh_to_text(VALUE self)
|
|||
* 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 @@ ossl_dh_check_params(VALUE self)
|
|||
|
||||
/*
|
||||
* 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)
|
||||
|
|
|
@ -23,7 +23,7 @@ class OpenSSL::TestPKeyDSA < Test::Unit::TestCase
|
|||
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 @@ if (OpenSSL::OPENSSL_VERSION_NUMBER > 0x10000000)
|
|||
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 @@ YNMbNw==
|
|||
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 @@ YNMbNw==
|
|||
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))
|
||||
|
|
68
test/openssl/test_pkey_ec.rb
Normal file
68
test/openssl/test_pkey_ec.rb
Normal file
|
@ -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
|
|
@ -49,7 +49,7 @@ class OpenSSL::TestPKeyRSA < Test::Unit::TestCase
|
|||
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 @@ class OpenSSL::TestPKeyRSA < Test::Unit::TestCase
|
|||
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 @@ class OpenSSL::TestPKeyRSA < Test::Unit::TestCase
|
|||
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 @@ AwEAAQ==
|
|||
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)
|
||||
|
|
|
@ -80,6 +80,14 @@ Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S
|
|||
-----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,
|
||||
|
|
Loading…
Reference in a new issue