Skip to content

Commit 2fbb259

Browse files
committed
avoid (unnecessary) byte[] copies in PKey#sign/verify
1 parent 3805a2f commit 2fbb259

File tree

3 files changed

+56
-31
lines changed

3 files changed

+56
-31
lines changed

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

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import org.jruby.ext.openssl.x509store.PEMInputOutput;
6565
import static org.jruby.ext.openssl.OpenSSL.*;
6666
import org.jruby.ext.openssl.impl.CipherSpec;
67+
import org.jruby.util.ByteList;
6768

6869
/**
6970
* @author <a href="mailto:[email protected]">Ola Bini</a>
@@ -187,6 +188,8 @@ public IRubyObject initialize(ThreadContext context) {
187188

188189
public String getAlgorithm() { return "NONE"; }
189190

191+
public boolean isPrivateKey() { return getPrivateKey() != null; }
192+
190193
public abstract RubyString to_der() ;
191194

192195
public abstract RubyString to_pem(final IRubyObject[] args) ;
@@ -198,54 +201,66 @@ public RubyString export(final IRubyObject[] args) {
198201

199202
@JRubyMethod(name = "sign")
200203
public IRubyObject sign(IRubyObject digest, IRubyObject data) {
201-
if (!this.callMethod(getRuntime().getCurrentContext(), "private?").isTrue()) {
202-
throw getRuntime().newArgumentError("Private key is needed.");
204+
final Ruby runtime = getRuntime();
205+
if ( ! isPrivateKey() ) {
206+
throw runtime.newArgumentError("Private key is needed.");
203207
}
204208
String digAlg = ((Digest) digest).getShortAlgorithm();
205209
try {
206-
Signature signature = SecurityHelper.getSignature(digAlg + "WITH" + getAlgorithm());
207-
signature.initSign(getPrivateKey());
208-
byte[] inp = data.convertToString().getBytes();
209-
signature.update(inp);
210-
byte[] sigge = signature.sign();
211-
return RubyString.newString(getRuntime(), sigge);
210+
ByteList sign = sign(digAlg + "WITH" + getAlgorithm(), getPrivateKey(), data.convertToString().getByteList());
211+
return RubyString.newString(runtime, sign);
212212
}
213-
catch (GeneralSecurityException gse) {
214-
throw newPKeyError(getRuntime(), gse.getMessage());
213+
catch (GeneralSecurityException ex) {
214+
throw newPKeyError(runtime, ex.getMessage());
215215
}
216216
}
217217

218+
static ByteList sign(final String signAlg, final PrivateKey privateKey, final ByteList data)
219+
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
220+
Signature signature = SecurityHelper.getSignature(signAlg);
221+
signature.initSign( privateKey );
222+
signature.update( data.getUnsafeBytes(), data.getBegin(), data.getRealSize() );
223+
return new ByteList(signature.sign(), false);
224+
}
225+
218226
@JRubyMethod(name = "verify")
219-
public IRubyObject verify(IRubyObject digest, IRubyObject sig, IRubyObject data) {
227+
public IRubyObject verify(IRubyObject digest, IRubyObject sign, IRubyObject data) {
228+
final Ruby runtime = getRuntime();
220229
if ( ! (digest instanceof Digest) ) {
221-
throw newPKeyError(getRuntime(), "invalid digest");
230+
throw newPKeyError(runtime, "invalid digest");
222231
}
223-
if ( ! (sig instanceof RubyString) ) {
224-
throw newPKeyError(getRuntime(), "invalid signature");
225-
}
226-
if ( ! (data instanceof RubyString) ) {
227-
throw newPKeyError(getRuntime(), "invalid data");
228-
}
229-
byte[] sigBytes = ((RubyString) sig).getBytes();
230-
byte[] dataBytes = ((RubyString) data).getBytes();
232+
ByteList sigBytes = convertToString(runtime, sign, "OpenSSL::PKey::PKeyError", "invalid signature").getByteList();
233+
ByteList dataBytes = convertToString(runtime, data, "OpenSSL::PKey::PKeyError", "invalid data").getByteList();
231234
String algorithm = ((Digest) digest).getShortAlgorithm() + "WITH" + getAlgorithm();
232-
boolean valid;
233235
try {
234-
Signature signature = SecurityHelper.getSignature(algorithm);
235-
signature.initVerify(getPublicKey());
236-
signature.update(dataBytes);
237-
valid = signature.verify(sigBytes);
236+
return runtime.newBoolean( verify(algorithm, getPublicKey(), dataBytes, sigBytes) );
238237
}
239238
catch (NoSuchAlgorithmException e) {
240-
throw newPKeyError(getRuntime(), "unsupported algorithm: " + algorithm);
239+
throw newPKeyError(runtime, "unsupported algorithm: " + algorithm);
241240
}
242241
catch (SignatureException e) {
243-
throw newPKeyError(getRuntime(), "invalid signature");
242+
throw newPKeyError(runtime, "invalid signature");
244243
}
245244
catch (InvalidKeyException e) {
246-
throw newPKeyError(getRuntime(), "invalid key");
245+
throw newPKeyError(runtime, "invalid key");
246+
}
247+
}
248+
249+
static RubyString convertToString(final Ruby runtime, final IRubyObject str, final String errorType, final CharSequence errorMsg) {
250+
try {
251+
return str.convertToString();
247252
}
248-
return getRuntime().newBoolean(valid);
253+
catch (RaiseException ex) { // to_str conversion failed
254+
throw Utils.newError(runtime, (RubyClass) runtime.getClassFromPath(errorType), errorMsg == null ? null : errorMsg.toString());
255+
}
256+
}
257+
258+
static boolean verify(final String signAlg, final PublicKey publicKey, final ByteList data, final ByteList sign)
259+
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
260+
Signature signature = SecurityHelper.getSignature(signAlg);
261+
signature.initVerify(publicKey);
262+
signature.update(data.getUnsafeBytes(), data.getBegin(), data.getRealSize());
263+
return signature.verify(sign.getUnsafeBytes(), sign.getBegin(), sign.getRealSize());
249264
}
250265

251266
// shared Helpers for PKeyRSA / PKEyDSA :

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,12 +274,17 @@ public RubyBoolean public_p() {
274274
return getRuntime().newBoolean(dh_y != null);
275275
}
276276

277+
@Override
278+
public boolean isPrivateKey() {
279+
return dh_x != null /* || haveEngine */;
280+
}
281+
277282
@JRubyMethod(name = "private?")
278283
public RubyBoolean private_p() {
279284
// FIXME! need to figure out what it means in MRI/OSSL code to
280285
// claim a DH is private if an engine is present -- doesn't really
281286
// map to Java implementation.
282-
return getRuntime().newBoolean(dh_x != null /* || haveEngine */);
287+
return getRuntime().newBoolean(isPrivateKey());
283288
}
284289

285290
@Override

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,14 @@ public RubyBoolean public_p() {
322322
return publicKey != null ? getRuntime().getTrue() : getRuntime().getFalse();
323323
}
324324

325+
@Override
326+
public boolean isPrivateKey() {
327+
return privateKey != null;
328+
}
329+
325330
@JRubyMethod(name = "private?")
326331
public RubyBoolean private_p() {
327-
return privateKey != null ? getRuntime().getTrue() : getRuntime().getFalse();
332+
return getRuntime().newBoolean(isPrivateKey());
328333
}
329334

330335
@Override

0 commit comments

Comments
 (0)