Skip to content

Commit aa15924

Browse files
committed
Instantiate both the private and public keys when setting parameters.
The rsa_n and rsa_e parameter fields are used to instantiate both the private and public keys, but are nulled after use in generatePrivateKeyIfParams() and generatePublicKeyIfParams(). This meant that once one of the keys had been created, the other could not be. The RSA object could not then be used for both private and public functions. If a private or public key has already been instantiated, use the key as the source for the n and e parameters in generatePrivateKeyIfParams() and generatePublicKeyIfParams().
1 parent b8bac99 commit aa15924

File tree

2 files changed

+77
-19
lines changed

2 files changed

+77
-19
lines changed

src/main/java/org/jruby/ext/openssl/PKeyRSA.java

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -648,17 +648,20 @@ public synchronized IRubyObject get_q() {
648648
return getRuntime().getNil();
649649
}
650650

651-
@JRubyMethod(name="e")
652-
public synchronized IRubyObject get_e() {
651+
private synchronized BigInteger getPublicExponent() {
653652
RSAPublicKey key;
654-
BigInteger e;
655653
if ((key = publicKey) != null) {
656-
e = key.getPublicExponent();
657-
} else if(privateKey != null) {
658-
e = privateKey.getPublicExponent();
654+
return key.getPublicExponent();
655+
} else if (privateKey != null) {
656+
return privateKey.getPublicExponent();
659657
} else {
660-
e = rsa_e;
658+
return rsa_e;
661659
}
660+
}
661+
662+
@JRubyMethod(name="e")
663+
public synchronized IRubyObject get_e() {
664+
BigInteger e = getPublicExponent();
662665
if (e != null) {
663666
return BN.newBN(getRuntime(), e);
664667
}
@@ -679,17 +682,20 @@ public synchronized IRubyObject set_e(final ThreadContext context, IRubyObject v
679682
return value;
680683
}
681684

682-
@JRubyMethod(name="n")
683-
public synchronized IRubyObject get_n() {
685+
private synchronized BigInteger getModulus() {
684686
RSAPublicKey key;
685-
BigInteger n;
686687
if ((key = publicKey) != null) {
687-
n = key.getModulus();
688-
} else if(privateKey != null) {
689-
n = privateKey.getModulus();
688+
return key.getModulus();
689+
} else if (privateKey != null) {
690+
return privateKey.getModulus();
690691
} else {
691-
n = rsa_n;
692+
return rsa_n;
692693
}
694+
}
695+
696+
@JRubyMethod(name="n")
697+
public synchronized IRubyObject get_n() {
698+
BigInteger n = getModulus();
693699
if (n != null) {
694700
return BN.newBN(getRuntime(), n);
695701
}
@@ -715,8 +721,12 @@ private void generatePublicKeyIfParams(final ThreadContext context) {
715721

716722
if ( publicKey != null ) throw newRSAError(runtime, "illegal modification");
717723

718-
BigInteger e, n;
719-
if ( (e = rsa_e) != null && (n = rsa_n) != null ) {
724+
// Don't access the rsa_n and rsa_e fields directly. They may have
725+
// already been consumed and cleared by generatePrivateKeyIfParams.
726+
BigInteger _rsa_n = getModulus();
727+
BigInteger _rsa_e = getPublicExponent();
728+
729+
if (_rsa_n != null && _rsa_e != null) {
720730
final KeyFactory rsaFactory;
721731
try {
722732
rsaFactory = SecurityHelper.getKeyFactory("RSA");
@@ -726,7 +736,7 @@ private void generatePublicKeyIfParams(final ThreadContext context) {
726736
}
727737

728738
try {
729-
publicKey = (RSAPublicKey) rsaFactory.generatePublic(new RSAPublicKeySpec(n, e));
739+
publicKey = (RSAPublicKey) rsaFactory.generatePublic(new RSAPublicKeySpec(_rsa_n, _rsa_e));
730740
}
731741
catch (InvalidKeySpecException ex) {
732742
throw newRSAError(runtime, "invalid parameters");
@@ -741,7 +751,12 @@ private void generatePrivateKeyIfParams(final ThreadContext context) {
741751

742752
if ( privateKey != null ) throw newRSAError(runtime, "illegal modification");
743753

744-
if (rsa_e != null && rsa_n != null && rsa_p != null && rsa_q != null && rsa_d != null && rsa_dmp1 != null && rsa_dmq1 != null && rsa_iqmp != null) {
754+
// Don't access the rsa_n and rsa_e fields directly. They may have
755+
// already been consumed and cleared by generatePublicKeyIfParams.
756+
BigInteger _rsa_n = getModulus();
757+
BigInteger _rsa_e = getPublicExponent();
758+
759+
if (_rsa_n != null && _rsa_e != null && rsa_p != null && rsa_q != null && rsa_d != null && rsa_dmp1 != null && rsa_dmq1 != null && rsa_iqmp != null) {
745760
final KeyFactory rsaFactory;
746761
try {
747762
rsaFactory = SecurityHelper.getKeyFactory("RSA");
@@ -752,7 +767,7 @@ private void generatePrivateKeyIfParams(final ThreadContext context) {
752767

753768
try {
754769
privateKey = (RSAPrivateCrtKey) rsaFactory.generatePrivate(
755-
new RSAPrivateCrtKeySpec(rsa_n, rsa_e, rsa_d, rsa_p, rsa_q, rsa_dmp1, rsa_dmq1, rsa_iqmp)
770+
new RSAPrivateCrtKeySpec(_rsa_n, _rsa_e, rsa_d, rsa_p, rsa_q, rsa_dmp1, rsa_dmq1, rsa_iqmp)
756771
);
757772
}
758773
catch (InvalidKeySpecException e) {

src/test/ruby/rsa/test_rsa.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,47 @@ def test_rsa_public_encrypt
4747
# }
4848
end
4949

50+
def test_rsa_param_accessors
51+
key_file = File.join(File.dirname(__FILE__), 'private_key.pem')
52+
key = OpenSSL::PKey::RSA.new(File.read(key_file))
53+
54+
[:e, :n, :d, :p, :q, :iqmp, :dmp1, :dmq1].each do |param|
55+
rsa = OpenSSL::PKey::RSA.new
56+
assert_nil(rsa.send(param))
57+
value = key.send(param)
58+
rsa.send("#{param}=", value)
59+
assert_equal(value, rsa.send(param), param)
60+
end
61+
end
62+
63+
def test_rsa_from_params_public_first
64+
key_file = File.join(File.dirname(__FILE__), 'private_key.pem')
65+
key = OpenSSL::PKey::RSA.new(File.read(key_file))
66+
67+
rsa = OpenSSL::PKey::RSA.new
68+
rsa.e, rsa.n = key.e, key.n
69+
assert_nothing_raised { rsa.public_encrypt('Test string') }
70+
[:e, :n].each {|param| assert_equal(key.send(param), rsa.send(param)) }
71+
72+
rsa.d, rsa.p, rsa.q, rsa.iqmp, rsa.dmp1, rsa.dmq1 = key.d, key.p, key.q, key.iqmp, key.dmp1, key.dmq1
73+
assert_nothing_raised { rsa.private_encrypt('Test string') }
74+
[:e, :n, :d, :p, :q, :iqmp, :dmp1, :dmq1].each do |param|
75+
assert_equal(key.send(param), rsa.send(param), param)
76+
end
77+
end
78+
79+
def test_rsa_from_params_private_first
80+
key_file = File.join(File.dirname(__FILE__), 'private_key.pem')
81+
key = OpenSSL::PKey::RSA.new(File.read(key_file))
82+
83+
rsa = OpenSSL::PKey::RSA.new
84+
rsa.d, rsa.p, rsa.q, rsa.iqmp, rsa.dmp1, rsa.dmq1 = key.d, key.p, key.q, key.iqmp, key.dmp1, key.dmq1
85+
rsa.e, rsa.n = key.e, key.n
86+
assert_nothing_raised { rsa.public_encrypt('Test string') }
87+
assert_nothing_raised { rsa.private_encrypt('Test string') }
88+
[:e, :n, :d, :p, :q, :iqmp, :dmp1, :dmq1].each do |param|
89+
assert_equal(key.send(param), rsa.send(param), param)
90+
end
91+
end
92+
5093
end

0 commit comments

Comments
 (0)