Skip to content

Commit 968bff9

Browse files
committed
[fix] OpenSSL::X509::Request#verify with DSA public key
this was a regression introduced in JOSSL 0.14.4
1 parent ceeacba commit 968bff9

File tree

3 files changed

+98
-8
lines changed

3 files changed

+98
-8
lines changed

src/main/java/org/jruby/ext/openssl/impl/PKCS10Request.java

+20-8
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,15 @@
4545
import java.security.spec.InvalidKeySpecException;
4646
import java.util.Enumeration;
4747

48+
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
4849
import org.bouncycastle.asn1.ASN1Sequence;
4950
import org.bouncycastle.asn1.ASN1Set;
5051
import org.bouncycastle.asn1.DERBitString;
5152
import org.bouncycastle.asn1.DLSequence;
5253
import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
54+
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
5355
import org.bouncycastle.asn1.x500.X500Name;
5456
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
55-
import org.bouncycastle.operator.DefaultAlgorithmNameFinder;
5657
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
5758
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
5859
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -212,15 +213,26 @@ private String getPublicKeyAlgorithm() {
212213
throw new IllegalStateException("no public key info");
213214
}
214215

215-
final AlgorithmIdentifier algId = publicKeyInfo.getAlgorithm();
216-
// NOTE: BC's DefaultAlgorithmNameFinder does not handle the EC oid
217-
if (X9ObjectIdentifiers.id_ecPublicKey.equals(algId.getAlgorithm())) {
216+
assert publicKeyInfo.getAlgorithm() != null : "null algorithm for public key info: " + publicKeyInfo;
217+
final ASN1ObjectIdentifier algOID = publicKeyInfo.getAlgorithm().getAlgorithm();
218+
assert algOID != null;
219+
220+
if (PKCSObjectIdentifiers.rsaEncryption.getId().equals(algOID.getId())) {
221+
return "RSA";
222+
}
223+
if (X9ObjectIdentifiers.id_ecPublicKey.getId().equals(algOID.getId())) {
218224
return "ECDSA";
219225
}
220-
// e.g. PKCSObjectIdentifiers.rsaEncryption -> "RSA"
221-
final String algName = new DefaultAlgorithmNameFinder().getAlgorithmName(algId);
222-
assert algId.getAlgorithm().getId() != algName : "could not resolve name for oid: " + algId.getAlgorithm();
223-
return algName;
226+
if (X9ObjectIdentifiers.id_dsa.getId().equals(algOID.getId())) {
227+
return "DSA";
228+
}
229+
230+
// final String algName = new DefaultAlgorithmNameFinder().getAlgorithmName(algId);
231+
// assert algId.getAlgorithm().getId() != algName : "could not resolve name for oid: " + algId.getAlgorithm();
232+
// return algName;
233+
234+
assert false : "unexpected public key algorithm oid: " + algOID.getId();
235+
return null;
224236
}
225237

226238
public PublicKey generatePublicKey() throws NoSuchAlgorithmException,

src/test/ruby/fixtures/pkey/dsa256

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-----BEGIN DSA PRIVATE KEY-----
2+
MIH3AgEAAkEAhk2libbY2a8y2Pt21+YPYGZeW6wzaW2yfj5oiClXro9XMR7XWLkE
3+
9B7XxLNFCS2gmCCdMsMW1HulaHtLFQmB2wIVAM43JZrcgpu6ajZ01VkLc93gu/Ed
4+
AkAOhujZrrKV5CzBKutKLb0GVyVWmdC7InoNSMZEeGU72rT96IjM59YzoqmD0pGM
5+
3I1o4cGqg1D1DfM1rQlnN1eSAkBq6xXfEDwJ1mLNxF6q8Zm/ugFYWR5xcX/3wFiT
6+
b4+EjHP/DbNh9Vm5wcfnDBJ1zKvrMEf2xqngYdrV/3CiGJeKAhRvL57QvJZcQGvn
7+
ISNX5cMzFHRW3Q==
8+
-----END DSA PRIVATE KEY-----

src/test/ruby/x509/test_x509req.rb

+70
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,59 @@
22

33
class TestX509Request < TestCase
44

5+
def setup!
6+
@rsa1024 = Fixtures.pkey("rsa1024")
7+
@rsa2048 = Fixtures.pkey("rsa2048")
8+
@dsa256 = Fixtures.pkey("dsa256")
9+
@dsa512 = Fixtures.pkey("dsa512")
10+
@dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou")
11+
end
12+
private :setup!
13+
14+
def test_public_key; setup!
15+
req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256'))
16+
assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der)
17+
req = OpenSSL::X509::Request.new(req.to_der)
18+
assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der)
19+
20+
req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256'))
21+
assert_equal(@dsa512.public_key.to_der, req.public_key.to_der)
22+
req = OpenSSL::X509::Request.new(req.to_der)
23+
assert_equal(@dsa512.public_key.to_der, req.public_key.to_der)
24+
end
25+
26+
def test_sign_and_verify_rsa_sha1; setup!
27+
req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1'))
28+
assert_equal(true, req.verify(@rsa1024))
29+
assert_equal(false, req.verify(@rsa2048))
30+
assert_equal(false, request_error_returns_false { req.verify(@dsa256) })
31+
assert_equal(false, request_error_returns_false { req.verify(@dsa512) })
32+
# req.version = 1
33+
# assert_equal(false, req.verify(@rsa1024))
34+
#rescue OpenSSL::X509::RequestError # RHEL 9 disables SHA1
35+
end
36+
37+
def test_sign_and_verify_rsa_md5; setup!
38+
req = issue_csr(0, @dn, @rsa2048, OpenSSL::Digest.new('MD5'))
39+
assert_equal(false, req.verify(@rsa1024))
40+
assert_equal(true, req.verify(@rsa2048))
41+
assert_equal(false, request_error_returns_false { req.verify(@dsa256) })
42+
assert_equal(false, request_error_returns_false { req.verify(@dsa512) })
43+
req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBar")
44+
assert_equal(false, req.verify(@rsa2048))
45+
#rescue OpenSSL::X509::RequestError # RHEL7 disables MD5
46+
end
47+
48+
def test_sign_and_verify_dsa; setup!
49+
req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256'))
50+
assert_equal(false, request_error_returns_false { req.verify(@rsa1024) })
51+
assert_equal(false, request_error_returns_false { req.verify(@rsa2048) })
52+
assert_equal(false, req.verify(@dsa256))
53+
assert_equal(true, req.verify(@dsa512))
54+
req.public_key = @rsa1024.public_key
55+
assert_equal(false, req.verify(@dsa512))
56+
end
57+
558
def test_csr_request_extensions
659
key = OpenSSL::PKey::RSA.new(512)
760
csr = OpenSSL::X509::Request.new
@@ -77,6 +130,23 @@ def test_to_der_new_from_der; require 'base64'
77130
OpenSSL::X509::Request.new(decoded) #=> OpenSSL::X509::RequestError: invalid certificate request data
78131
end
79132

133+
private
134+
135+
def issue_csr(ver, dn, key, digest)
136+
req = OpenSSL::X509::Request.new
137+
req.version = ver
138+
req.subject = dn
139+
req.public_key = key.public_key
140+
req.sign(key, digest)
141+
req
142+
end
143+
144+
def request_error_returns_false
145+
yield
146+
rescue OpenSSL::X509::RequestError
147+
false
148+
end
149+
80150
TEST_KEY_RSA1024 = <<-_end_of_pem_
81151
-----BEGIN RSA PRIVATE KEY-----
82152
MIICXgIBAAKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7Cx

0 commit comments

Comments
 (0)