Skip to content

Commit 23b1cef

Browse files
committed
[compat] support PKey::EC#sign_raw and verify_raw
1 parent a56b251 commit 23b1cef

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,48 @@ public IRubyObject dsa_verify_asn1(final ThreadContext context, final IRubyObjec
527527
}
528528
}
529529

530+
// sign_raw(digest, data) -- signs pre-hashed (raw) bytes with the EC private key.
531+
// Produces a DER-encoded ASN.1 SEQUENCE [r, s], identical to dsa_sign_asn1.
532+
// The digest argument is accepted for API parity with RSA/DSA sign_raw but is unused;
533+
// ECDSASigner operates directly on the supplied bytes without additional hashing.
534+
@JRubyMethod(name = "sign_raw")
535+
public IRubyObject sign_raw(final ThreadContext context, final IRubyObject digest, final IRubyObject data) {
536+
return dsa_sign_asn1(context, data);
537+
}
538+
539+
// verify_raw(digest, signature, data) -- verifies a DER-encoded ECDSA signature over raw bytes.
540+
// Returns true/false; returns false (rather than raising) for a malformed or invalid signature.
541+
// Argument order matches PKey#verify_raw convention: (digest, signature, data), unlike
542+
// dsa_verify_asn1 which takes (data, signature).
543+
@JRubyMethod(name = "verify_raw")
544+
public IRubyObject verify_raw(final ThreadContext context, final IRubyObject digest,
545+
final IRubyObject sign, final IRubyObject data) {
546+
final Ruby runtime = context.runtime;
547+
try {
548+
final ECNamedCurveParameterSpec params = getParameterSpec();
549+
550+
final ECDSASigner signer = new ECDSASigner();
551+
signer.init(false, new ECPublicKeyParameters(
552+
EC5Util.convertPoint(publicKey.getParams(), publicKey.getW()),
553+
new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH())
554+
));
555+
556+
ASN1Primitive vec = new ASN1InputStream(sign.convertToString().getBytes()).readObject();
557+
if (!(vec instanceof ASN1Sequence)) return runtime.getFalse();
558+
559+
ASN1Sequence seq = (ASN1Sequence) vec;
560+
ASN1Integer r = ASN1Integer.getInstance(seq.getObjectAt(0));
561+
ASN1Integer s = ASN1Integer.getInstance(seq.getObjectAt(1));
562+
563+
boolean verified = signer.verifySignature(data.convertToString().getBytes(), r.getPositiveValue(), s.getPositiveValue());
564+
return runtime.newBoolean(verified);
565+
}
566+
catch (IOException | IllegalArgumentException | IllegalStateException ex) {
567+
debugStackTrace(runtime, ex);
568+
return runtime.getFalse();
569+
}
570+
}
571+
530572
@JRubyMethod(name = "dh_compute_key")
531573
public IRubyObject dh_compute_key(final ThreadContext context, final IRubyObject point) {
532574
try {

src/test/ruby/ec/test_ec.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,14 @@ def test_dsa_sign_verify_all
521521
end
522522
end
523523

524+
def assert_sign_verify_false_or_error
525+
ret = yield
526+
rescue => e
527+
assert_kind_of(OpenSSL::PKey::PKeyError, e)
528+
else
529+
assert_equal(false, ret)
530+
end
531+
524532
def test_sign_verify_raw
525533
key = Fixtures.pkey("p256")
526534
data1 = "foo"
@@ -530,10 +538,21 @@ def test_sign_verify_raw
530538

531539
# Sign by #dsa_sign_asn1
532540
sig = key.dsa_sign_asn1(data1)
541+
assert_equal true, key.dsa_verify_asn1(data1, sig)
542+
assert_equal false, key.dsa_verify_asn1(data2, sig)
543+
assert_sign_verify_false_or_error { key.dsa_verify_asn1(data1, malformed_sig) }
544+
assert_equal true, key.verify_raw(nil, sig, data1)
545+
assert_equal false, key.verify_raw(nil, sig, data2)
546+
assert_sign_verify_false_or_error { key.verify_raw(nil, malformed_sig, data1) }
533547

548+
# Sign by #sign_raw
549+
sig = key.sign_raw(nil, data1)
534550
assert_equal true, key.dsa_verify_asn1(data1, sig)
535551
assert_equal false, key.dsa_verify_asn1(data2, sig)
536-
assert_raise(OpenSSL::PKey::ECError) { key.dsa_verify_asn1(data1, malformed_sig) }
552+
assert_sign_verify_false_or_error { key.dsa_verify_asn1(data1, malformed_sig) }
553+
assert_equal true, key.verify_raw(nil, sig, data1)
554+
assert_equal false, key.verify_raw(nil, sig, data2)
555+
assert_sign_verify_false_or_error { key.verify_raw(nil, malformed_sig, data1) }
537556
end
538557

539558
def test_new_from_der

0 commit comments

Comments
 (0)