Skip to content

Commit 9b3de2b

Browse files
committed
[compat] support PKey::DSA#sign_raw and verify_raw
1 parent dacede1 commit 9b3de2b

File tree

3 files changed

+82
-3
lines changed

3 files changed

+82
-3
lines changed

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

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,8 @@ public RubyString public_to_pem(ThreadContext context) {
440440
public IRubyObject syssign(IRubyObject data) {
441441
final Ruby runtime = getRuntime();
442442

443-
DSAPrivateKey privateKey;
444-
if ((privateKey = this.privateKey) == null) {
443+
DSAPrivateKey privateKey = this.privateKey;
444+
if (privateKey == null) {
445445
throw newDSAError(runtime, "Private DSA key needed!");
446446
}
447447

@@ -454,13 +454,55 @@ public IRubyObject syssign(IRubyObject data) {
454454
}
455455
}
456456

457+
// In OpenSSL, sign_raw/verify_raw are base-class PKey methods that use EVP_PKEY_sign /
458+
// EVP_PKEY_verify (low-level, no-hashing operations).
459+
// When the digest argument is non-nil, EVP_PKEY_CTX_set_signature_md is called, but for DSA
460+
// this only affects input-length validation inside OpenSSL - does not hash the data.
461+
//
462+
// In JCA, "NONEwithDSA" is the direct equivalent: it accepts already-hashed bytes and signs
463+
// them without any further digest step.
464+
// The digest argument therefore does not influence the JCA algorithm and is intentionally unused.
465+
@JRubyMethod(name = "sign_raw")
466+
public IRubyObject sign_raw(ThreadContext context, IRubyObject digest, IRubyObject data) {
467+
DSAPrivateKey privateKey = this.privateKey;
468+
if (privateKey == null) {
469+
throw newDSAError(context.runtime, "Private DSA key needed!");
470+
}
471+
try {
472+
ByteList sign = sign("NONEwithDSA", privateKey, data.convertToString().getByteList());
473+
return RubyString.newString(context.runtime, sign);
474+
}
475+
catch (GeneralSecurityException ex) {
476+
throw newDSAError(context.runtime, ex.getMessage());
477+
}
478+
}
479+
480+
@JRubyMethod(name = "verify_raw")
481+
public IRubyObject verify_raw(IRubyObject digest, IRubyObject sign, IRubyObject data) {
482+
final Ruby runtime = getRuntime();
483+
ByteList sigBytes = convertToString(runtime, sign, "OpenSSL::PKey::PKeyError", "invalid signature").getByteList();
484+
ByteList dataBytes = convertToString(runtime, data, "OpenSSL::PKey::PKeyError", "invalid data").getByteList();
485+
try {
486+
return runtime.newBoolean(verify("NONEwithDSA", getPublicKey(), dataBytes, sigBytes));
487+
}
488+
catch (NoSuchAlgorithmException e) {
489+
throw newPKeyError(runtime, e.getMessage());
490+
}
491+
catch (SignatureException e) {
492+
throw newPKeyError(runtime, "invalid signature");
493+
}
494+
catch (InvalidKeyException e) {
495+
throw newPKeyError(runtime, "invalid key");
496+
}
497+
}
498+
457499
@JRubyMethod // ossl_dsa_verify
458500
public IRubyObject sysverify(IRubyObject data, IRubyObject sign) {
459501
final Ruby runtime = getRuntime();
460502
ByteList sigBytes = convertToString(runtime, sign, "OpenSSL::PKey::DSAError", "invalid signature").getByteList();
461503
ByteList dataBytes = convertToString(runtime, data, "OpenSSL::PKey::DSAError", "invalid data").getByteList();
462504
try {
463-
return runtime.newBoolean( verify("NONEwithDSA", getPublicKey(), dataBytes, sigBytes) );
505+
return runtime.newBoolean(verify("NONEwithDSA", getPublicKey(), dataBytes, sigBytes));
464506
}
465507
catch (NoSuchAlgorithmException e) {
466508
throw newDSAError(runtime, e.getMessage());

src/test/ruby/dsa/test_dsa.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,28 @@ def test_dsa_sys_sign_verify
118118
assert dsa.sysverify(digest, sig).eql?(true)
119119
end
120120

121+
def test_sign_verify_raw
122+
key = Fixtures.pkey("dsa2048")
123+
data = 'Sign me!'
124+
digest = OpenSSL::Digest.digest('SHA1', data)
125+
126+
invalid_sig = key.sign_raw(nil, digest.succ)
127+
128+
# Sign by #syssign
129+
sig = key.syssign(digest)
130+
assert_equal true, key.sysverify(digest, sig)
131+
assert_equal false, key.sysverify(digest, invalid_sig)
132+
assert_equal true, key.verify_raw(nil, sig, digest)
133+
assert_equal false, key.verify_raw(nil, invalid_sig, digest)
134+
135+
# Sign by #sign_raw
136+
sig = key.sign_raw(nil, digest)
137+
assert_equal true, key.sysverify(digest, sig)
138+
assert_equal false, key.sysverify(digest, invalid_sig)
139+
assert_equal true, key.verify_raw(nil, sig, digest)
140+
assert_equal false, key.verify_raw(nil, invalid_sig, digest)
141+
end
142+
121143
def test_DSAPrivateKey
122144
# OpenSSL DSAPrivateKey format; similar to RSAPrivateKey
123145
dsa512 = Fixtures.pkey("dsa512")
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIICXgIBADCCAjYGByqGSM44BAEwggIpAoIBAQDXZhJ/dQoWkQELzjzlx8FtIp96
3+
voCYe5NY0H8j0jz7GyHpXt41+MteqkZK3/Ah+cNR9uG8iEYArAZ71LcWotfee2Gz
4+
xdxozr9bRt0POYhO2YIsfMpBrEskPsDH2g/2nFV8l4OJgxU2qZUrF4PN5ha+Mu6u
5+
sVtN8hjvAvnbf4Pxn0b8NN9f4PJncroUa8acv5WsV85E1RW7NYCefggU4LytYIHg
6+
euRF9eY9gVCX5MkUgW2xODHIYJhwk/+5lJxG7qUsSahD/nPHO/yoWgdVHq2DkdTq
7+
KYXkAxx2PJcTBOHTglhE6mgCbEKp8vcfElnBWyCT6QykclZiPXXD2JV829J/Ah0A
8+
vYa+/G/gUZiomyejVje6UsGoCc+vInxmovOL8QKCAQEAhnKEigYPw6u8JY7v5iGo
9+
Ylz8qiMFYmaJCwevf3KCjWeEXuNO4OrKdfzkQl1tPuGLioYFfP1A2yGosjdUdLEB
10+
0JqnzlKxUp+G6RfBj+WYzbgc5hr7t0M+reAJh09/hDzqfxjcgiHstq7mpRXBP8Y7
11+
iu27s7TRYJNSAYRvWcXNSBEUym3mHBBbZn7VszYooSrn60/iZ8I+VY1UF/fgqhbj
12+
JfaaZNQCDO9K3Vb3rsXoYd8+bOZIen9uHB+pNjMqhpl4waysqrlpGFeeqdxivH6S
13+
vkrHLs6/eWVMnS08RdcryoCrI3Bm8mMBKQglDwKLnWLfzG565qEhslzyCd/l9k9a
14+
cwQfAh0Ao8/g72fSFmo04FizM7DZJSIPqDLjfZu9hLvUFA==
15+
-----END PRIVATE KEY-----

0 commit comments

Comments
 (0)