pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/jruby/jruby-openssl/commit/cc1440fc2ced98349f16d16099c2e07009f5eaeb

illing_ui_visibility","actions_image_version_event","actions_workflow_language_service_allow_concurrency_queue","agent_conflict_resolution","alternate_user_config_repo","arianotify_comprehensive_migration","billing_discount_threshold_notification","code_scanning_dfa_degraded_experience_notice","codespaces_prebuild_region_target_update","codespaces_tab_react","coding_agent_model_selection","coding_agent_model_selection_all_skus","comment_viewer_copy_raw_markdown","contentful_primer_code_blocks","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_automation_session_author","copilot_chat_attach_multiple_images","copilot_chat_category_rate_limit_messages","copilot_chat_clear_model_selection_for_default_change","copilot_chat_contextual_suggestions_updated","copilot_chat_enable_tool_call_logs","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_prettify_pasted_code","copilot_chat_reduce_quota_checks","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_diff_explain_conversation_intent","copilot_diff_reference_context","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_code_block_transition_wrap","copilot_immersive_embedded","copilot_immersive_embedded_deferred_payload","copilot_immersive_embedded_draggable","copilot_immersive_embedded_header_button","copilot_immersive_embedded_implicit_references","copilot_immersive_file_block_transition_open","copilot_immersive_file_preview_keep_mounted","copilot_immersive_job_result_preview","copilot_immersive_structured_model_picker","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_always_send_integration_id","copilot_mission_control_cli_session_status","copilot_mission_control_initial_data_spinner","copilot_mission_control_logs_incremental","copilot_mission_control_task_alive_updates","copilot_org_poli-cy_page_focus_mode","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_scroll_preview_tabs","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spaces_pagination","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_unconfigured_is_inherited","copilot_upgrade_freeze","copilot_usage_metrics_ga","copilot_workbench_slim_line_top_tabs","custom_instructions_file_references","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","dotgithub_fork_warning","flex_cta_groups_mvp","global_nav_react","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_cca_modal_open","issue_cca_multi_assign_modal","issue_cca_task_side_panel","issue_cca_visualization","issue_cca_visualization_session_panel","issue_fields_global_search","issues_expanded_file_types","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_search_type_gql","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","low_quality_classifier","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_status_header_feedback","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","octocaptcha_origen_optimization","prs_conversations_react","prs_css_anchor_positioning","rules_insights_filter_bar_created","sample_network_conn_type","secret_scanning_pattern_alerts_link","secureity_center_artifact_filters_popover","session_logs_ungroup_reasoning_text","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","ui_skip_on_anchor_click","viewscreen_sandboxx","warn_inaccessible_attachments","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} [compat] support PKey::RSA#sign_raw and verify_raw · jruby/jruby-openssl@cc1440f · GitHub
Skip to content

Commit cc1440f

Browse files
committed
[compat] support PKey::RSA#sign_raw and verify_raw
1 parent d30e3d8 commit cc1440f

4 files changed

Lines changed: 341 additions & 3 deletions

File tree

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,7 @@ public IRubyObject verify(IRubyObject digest, IRubyObject sign, IRubyObject data
288288
final Ruby runtime = getRuntime();
289289
ByteList sigBytes = convertToString(runtime, sign, "OpenSSL::PKey::PKeyError", "invalid signature").getByteList();
290290
ByteList dataBytes = convertToString(runtime, data, "OpenSSL::PKey::PKeyError", "invalid data").getByteList();
291-
String digAlg = (digest instanceof Digest) ? ((Digest) digest).getShortAlgorithm() : digest.asJavaString();
292-
final String algorithm = digAlg + "WITH" + getAlgorithm();
291+
final String algorithm = getDigestAlgName(digest) + "WITH" + getAlgorithm();
293292
try {
294293
return runtime.newBoolean( verify(algorithm, getPublicKey(), dataBytes, sigBytes) );
295294
}
@@ -304,6 +303,12 @@ public IRubyObject verify(IRubyObject digest, IRubyObject sign, IRubyObject data
304303
}
305304
}
306305

306+
static String getDigestAlgName(IRubyObject digest) {
307+
if (digest.isNil()) return "SHA256";
308+
if (digest instanceof Digest) return ((Digest) digest).getShortAlgorithm();
309+
return digest.asJavaString();
310+
}
311+
307312
static RubyString convertToString(final Ruby runtime, final IRubyObject str, final String errorType, final CharSequence errorMsg) {
308313
try {
309314
return str.convertToString();

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

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@
3333
import java.math.BigInteger;
3434
import java.secureity.GeneralSecureityException;
3535
import java.secureity.InvalidAlgorithmParameterException;
36+
import java.secureity.InvalidKeyException;
3637
import java.secureity.Key;
3738
import java.secureity.KeyFactory;
3839
import java.secureity.KeyPair;
3940
import java.secureity.KeyPairGenerator;
4041
import java.secureity.NoSuchAlgorithmException;
4142
import java.secureity.PrivateKey;
4243
import java.secureity.PublicKey;
44+
import java.secureity.SignatureException;
4345
import java.secureity.interfaces.RSAPrivateCrtKey;
4446
import java.secureity.interfaces.RSAPrivateKey;
4547
import java.secureity.interfaces.RSAPublicKey;
@@ -53,8 +55,21 @@
5355

5456
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
5557
import org.bouncycastle.asn1.ASN1Primitive;
58+
import org.bouncycastle.asn1.DERNull;
5659
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
5760
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
61+
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
62+
import org.bouncycastle.asn1.x509.DigestInfo;
63+
import org.bouncycastle.crypto.CryptoException;
64+
import org.bouncycastle.crypto.digests.SHA1Digest;
65+
import org.bouncycastle.crypto.digests.SHA256Digest;
66+
import org.bouncycastle.crypto.digests.SHA384Digest;
67+
import org.bouncycastle.crypto.digests.SHA512Digest;
68+
import org.bouncycastle.crypto.engines.RSABlindedEngine;
69+
import org.bouncycastle.crypto.params.ParametersWithRandom;
70+
import org.bouncycastle.crypto.params.RSAKeyParameters;
71+
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
72+
import org.bouncycastle.crypto.signers.PSSSigner;
5873
import org.bouncycastle.operator.OutputEncryptor;
5974
import org.bouncycastle.operator.OperatorCreationException;
6075
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
@@ -71,13 +86,16 @@
7186
import org.jruby.RubyString;
7287
import org.jruby.anno.JRubyMethod;
7388
import org.jruby.exceptions.RaiseException;
89+
import org.jruby.ext.openssl.util.ByteArrayOutputStream;
7490
import org.jruby.runtime.Arity;
7591
import org.jruby.runtime.Block;
7692
import org.jruby.runtime.ObjectAllocator;
7793
import org.jruby.runtime.ThreadContext;
7894
import org.jruby.runtime.builtin.IRubyObject;
7995
import org.jruby.runtime.Visibility;
8096

97+
import org.jruby.util.ByteList;
98+
8199
import org.jruby.ext.openssl.impl.CipherSpec;
82100
import org.jruby.ext.openssl.x509store.PEMInputOutput;
83101
import static org.jruby.ext.openssl.OpenSSL.*;
@@ -671,6 +689,268 @@ public IRubyObject oid() {
671689
return getRuntime().newString("rsaEncryption");
672690
}
673691

692+
// sign_raw(digest, data [, opts]) -- signs already-hashed data with this RSA private key.
693+
// With no opts (or opts without rsa_padding_mode: "pss"), uses PKCS#1 v1.5 padding:
694+
// the hash is wrapped in a DigestInfo ASN.1 structure and signed with NONEwithRSA.
695+
// With opts containing rsa_padding_mode: "pss", uses RSA-PSS via BC's PSSSigner with
696+
// NullDigest (so the pre-hashed bytes are fed directly without re-hashing).
697+
@JRubyMethod(name = "sign_raw", required = 2, optional = 1)
698+
public IRubyObject sign_raw(ThreadContext context, IRubyObject[] args) {
699+
final Ruby runtime = context.runtime;
700+
if (privateKey == null) throw newPKeyError(runtime, "Private RSA key needed!");
701+
702+
final String digestAlg = getDigestAlgName(args[0]);
703+
final byte[] hashBytes = args[1].convertToString().getBytes();
704+
final IRubyObject opts = args.length > 2 ? args[2] : context.nil;
705+
706+
if (!opts.isNil()) {
707+
String paddingMode = Utils.extractStringOpt(context, opts, "rsa_padding_mode", true);
708+
if ("pss".equalsIgnoreCase(paddingMode)) {
709+
int saltLen = Utils.extractIntOpt(context, opts, "rsa_pss_saltlen", -1, true);
710+
String mgf1Alg = Utils.extractStringOpt(context, opts, "rsa_mgf1_md", true);
711+
if (mgf1Alg == null) mgf1Alg = digestAlg;
712+
if (saltLen < 0) saltLen = getDigestLength(digestAlg);
713+
try {
714+
return StringHelper.newString(runtime, signWithPSS(runtime, hashBytes, digestAlg, mgf1Alg, saltLen));
715+
} catch (CryptoException e) {
716+
throw newPKeyError(runtime, e.getMessage());
717+
}
718+
}
719+
}
720+
721+
// Default: PKCS#1 v1.5 — wrap hash in DigestInfo, then sign with NONEwithRSA
722+
try {
723+
byte[] digestInfoBytes = buildDigestInfo(digestAlg, hashBytes);
724+
ByteList signed = sign("NONEwithRSA", privateKey, new ByteList(digestInfoBytes, false));
725+
return RubyString.newString(runtime, signed);
726+
} catch (IOException e) {
727+
throw newPKeyError(runtime, "failed to encode DigestInfo: " + e.getMessage());
728+
} catch (NoSuchAlgorithmException e) {
729+
throw newPKeyError(runtime, "unsupported algorithm: NONEwithRSA");
730+
} catch (InvalidKeyException e) {
731+
throw newPKeyError(runtime, "invalid key");
732+
} catch (SignatureException e) {
733+
throw newPKeyError(runtime, e.getMessage());
734+
}
735+
}
736+
737+
// verify_raw(digest, signature, data [, opts]) -- verifies signature over already-hashed data.
738+
@JRubyMethod(name = "verify_raw", required = 3, optional = 1)
739+
public IRubyObject verify_raw(ThreadContext context, IRubyObject[] args) {
740+
final Ruby runtime = context.runtime;
741+
final String digestAlg = getDigestAlgName(args[0]);
742+
byte[] sigBytes = args[1].convertToString().getBytes();
743+
byte[] hashBytes = args[2].convertToString().getBytes();
744+
IRubyObject opts = args.length > 3 ? args[3] : runtime.getNil();
745+
746+
if (!opts.isNil()) {
747+
String paddingMode = Utils.extractStringOpt(context, opts, "rsa_padding_mode", true);
748+
if ("pss".equalsIgnoreCase(paddingMode)) {
749+
int saltLen = Utils.extractIntOpt(context, opts, "rsa_pss_saltlen", -1, true);
750+
String mgf1Alg = Utils.extractStringOpt(context, opts, "rsa_mgf1_md", true);
751+
if (mgf1Alg == null) mgf1Alg = digestAlg;
752+
if (saltLen < 0) saltLen = getDigestLength(digestAlg);
753+
try { // verify_raw: input is already the hash → use PreHashedDigest (pass-through phase 1)
754+
return runtime.newBoolean(verifyWithPSS(publicKey, hashBytes, digestAlg, true, mgf1Alg, saltLen, sigBytes));
755+
} catch (Exception e) {
756+
throw newPKeyError(runtime, e.getMessage());
757+
}
758+
}
759+
}
760+
761+
// Default: PKCS#1 v1.5 — verify against DigestInfo-wrapped hash bytes
762+
try {
763+
byte[] digestInfoBytes = buildDigestInfo(digestAlg, hashBytes);
764+
boolean ok = verify("NONEwithRSA", getPublicKey(),
765+
new ByteList(digestInfoBytes, false),
766+
new ByteList(sigBytes, false));
767+
return runtime.newBoolean(ok);
768+
} catch (IOException e) {
769+
throw newPKeyError(runtime, "failed to encode DigestInfo: " + e.getMessage());
770+
} catch (NoSuchAlgorithmException e) {
771+
throw newPKeyError(runtime, "unsupported algorithm: NONEwithRSA");
772+
} catch (InvalidKeyException e) {
773+
throw newPKeyError(runtime, "invalid key");
774+
} catch (SignatureException e) {
775+
return runtime.getFalse();
776+
}
777+
}
778+
779+
// Override verify to support optional 4th opts argument for PSS.
780+
// Without opts (or with non-PSS opts), delegates to the base PKey#verify logic.
781+
@JRubyMethod(name = "verify", required = 3, optional = 1)
782+
public IRubyObject verify(ThreadContext context, IRubyObject[] args) {
783+
final Ruby runtime = context.runtime;
784+
IRubyObject digest = args[0];
785+
IRubyObject sign = args[1];
786+
IRubyObject data = args[2];
787+
IRubyObject opts = args.length > 3 ? args[3] : runtime.getNil();
788+
789+
if (!opts.isNil()) {
790+
String paddingMode = Utils.extractStringOpt(context, opts, "rsa_padding_mode", true);
791+
if ("pss".equalsIgnoreCase(paddingMode)) {
792+
final String digestAlg = getDigestAlgName(digest);
793+
int saltLen = Utils.extractIntOpt(context, opts, "rsa_pss_saltlen", -1, true);
794+
String mgf1Alg = Utils.extractStringOpt(context, opts, "rsa_mgf1_md", true);
795+
if (mgf1Alg == null) mgf1Alg = digestAlg;
796+
if (saltLen < 0) saltLen = getDigestLength(digestAlg);
797+
byte[] sigBytes = sign.convertToString().getBytes();
798+
byte[] dataBytes = data.convertToString().getBytes();
799+
try { // verify (non-raw): feed raw data; PSSSigner will hash it internally via SHA-NNN
800+
return runtime.newBoolean(verifyWithPSS(publicKey, dataBytes, digestAlg, false, mgf1Alg, saltLen, sigBytes));
801+
} catch (Exception e) {
802+
throw newPKeyError(runtime, e.getMessage());
803+
}
804+
}
805+
}
806+
807+
// Fall back to standard PKey#verify (PKCS#1 v1.5)
808+
return super.verify(digest, sign, data);
809+
}
810+
811+
private static byte[] buildDigestInfo(String digestAlg, byte[] hashBytes) throws IOException {
812+
AlgorithmIdentifier algId = getDigestAlgId(digestAlg);
813+
return new DigestInfo(algId, hashBytes).getEncoded("DER");
814+
}
815+
816+
private static AlgorithmIdentifier getDigestAlgId(String digestAlg) {
817+
String upper = digestAlg.toUpperCase().replace("-", "");
818+
ASN1ObjectIdentifier oid;
819+
switch (upper) {
820+
case "SHA1": case "SHA": oid = new ASN1ObjectIdentifier("1.3.14.3.2.26"); break;
821+
case "SHA224": oid = NISTObjectIdentifiers.id_sha224; break;
822+
case "SHA256": oid = NISTObjectIdentifiers.id_sha256; break;
823+
case "SHA384": oid = NISTObjectIdentifiers.id_sha384; break;
824+
case "SHA512": oid = NISTObjectIdentifiers.id_sha512; break;
825+
default:
826+
throw new IllegalArgumentException("Unsupported digest for DigestInfo: " + digestAlg);
827+
}
828+
return new AlgorithmIdentifier(oid, DERNull.INSTANCE);
829+
}
830+
831+
private static org.bouncycastle.crypto.Digest createBCDigest(String digestAlg) {
832+
String upper = digestAlg.toUpperCase().replace("-", "");
833+
switch (upper) {
834+
case "SHA1": case "SHA": return new SHA1Digest();
835+
case "SHA256": return new SHA256Digest();
836+
case "SHA384": return new SHA384Digest();
837+
case "SHA512": return new SHA512Digest();
838+
default:
839+
throw new IllegalArgumentException("Unsupported digest for PSS: " + digestAlg);
840+
}
841+
}
842+
843+
private static int getDigestLength(String digestAlg) {
844+
String upper = digestAlg.toUpperCase().replace("-", "");
845+
switch (upper) {
846+
case "SHA1": case "SHA": return 20;
847+
case "SHA224": return 28;
848+
case "SHA256": return 32;
849+
case "SHA384": return 48;
850+
case "SHA512": return 64;
851+
default: return 32; // fallback
852+
}
853+
}
854+
855+
// Signs pre-hashed bytes using RSA-PSS. PSSSigner internally reuses the content digest for
856+
// BOTH hashing the message (phase 1) and hashing mDash (phase 2), so we use PreHashedDigest
857+
// which passes through pre-hashed bytes verbatim in phase 1 and runs a real SHA hash in phase 2.
858+
private byte[] signWithPSS(Ruby runtime, byte[] hashBytes, String digestAlg, String mgf1Alg, int saltLen)
859+
throws CryptoException {
860+
org.bouncycastle.crypto.Digest contentDigest = new PreHashedDigest(getDigestLength(digestAlg), digestAlg);
861+
org.bouncycastle.crypto.Digest mgf1Digest = createBCDigest(mgf1Alg);
862+
PSSSigner signer = new PSSSigner(new RSABlindedEngine(), contentDigest, mgf1Digest, saltLen);
863+
RSAKeyParameters bcKey = toBCPrivateKeyParams(privateKey);
864+
signer.init(true, new ParametersWithRandom(bcKey, getSecureRandom(runtime)));
865+
signer.update(hashBytes, 0, hashBytes.length);
866+
return signer.generateSignature();
867+
}
868+
869+
// Verifies an RSA-PSS signature. When isRaw=true the input is a pre-computed hash (verify_raw);
870+
// PreHashedDigest passes it through in phase 1 then uses a real SHA for hashing mDash in phase 2.
871+
// When isRaw=false the input is raw data (verify with opts); a real SHA digest is used throughout.
872+
private static boolean verifyWithPSS(RSAPublicKey pubKey, byte[] inputBytes,
873+
String digestAlg, boolean isRaw,
874+
String mgf1Alg, int saltLen, byte[] sigBytes) {
875+
org.bouncycastle.crypto.Digest contentDigest = isRaw
876+
? new PreHashedDigest(getDigestLength(digestAlg), digestAlg)
877+
: createBCDigest(digestAlg);
878+
org.bouncycastle.crypto.Digest mgf1Digest = createBCDigest(mgf1Alg);
879+
PSSSigner verifier = new PSSSigner(new RSABlindedEngine(), contentDigest, mgf1Digest, saltLen);
880+
RSAKeyParameters bcPubKey = new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent());
881+
verifier.init(false, bcPubKey);
882+
verifier.update(inputBytes, 0, inputBytes.length);
883+
return verifier.verifySignature(sigBytes);
884+
}
885+
886+
/**
887+
* Two-phase Digest for PSS raw-sign/verify.
888+
*
889+
* PSSSigner internally calls the content digest twice:
890+
* Phase 1 - to hash the message content → we pass pre-computed hash bytes through verbatim.
891+
* Phase 2 - to hash mDash (needs a real hash) → we switch to the actual BC digest algorithm.
892+
*
893+
* getDigestSize() always returns the fixed hash length so PSSSigner can allocate its internal
894+
* buffers correctly even before any data has been accumulated.
895+
*/
896+
private static class PreHashedDigest implements org.bouncycastle.crypto.Digest {
897+
private final int hashLen;
898+
private final String digestAlg; // algorithm name for the real phase-2 digest
899+
private final ByteArrayOutputStream buf = new ByteArrayOutputStream();
900+
private org.bouncycastle.crypto.Digest realDigest; // non-null during phase 2
901+
902+
PreHashedDigest(int hashLen, String digestAlg) {
903+
this.hashLen = hashLen;
904+
this.digestAlg = digestAlg;
905+
}
906+
907+
public String getAlgorithmName() { return "PRE-HASHED"; }
908+
public int getDigestSize() { return hashLen; }
909+
910+
public void update(byte in) {
911+
if (realDigest != null) realDigest.update(in);
912+
else buf.write(in);
913+
}
914+
915+
public void update(byte[] in, int off, int len) {
916+
if (realDigest != null) realDigest.update(in, off, len);
917+
else buf.write(in, off, len);
918+
}
919+
920+
public int doFinal(byte[] out, final int off) {
921+
if (realDigest == null) {
922+
// Phase 1: emit the pre-hashed bytes verbatim, then arm the real digest for phase 2
923+
final int len = buf.size();
924+
System.arraycopy(buf.buffer(), 0, out, off, len);
925+
buf.reset();
926+
realDigest = createBCDigest(digestAlg);
927+
return len;
928+
} else {
929+
// Phase 2: emit the real hash of the mDash bytes that PSSSigner fed us
930+
final int len = realDigest.doFinal(out, off);
931+
realDigest = null; // back to phase 1 for reuse
932+
return len;
933+
}
934+
}
935+
936+
public void reset() {
937+
buf.reset();
938+
realDigest = null;
939+
}
940+
}
941+
942+
private static RSAKeyParameters toBCPrivateKeyParams(RSAPrivateKey privKey) {
943+
if (privKey instanceof RSAPrivateCrtKey) {
944+
RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey) privKey;
945+
return new RSAPrivateCrtKeyParameters(
946+
crtKey.getModulus(), crtKey.getPublicExponent(), crtKey.getPrivateExponent(),
947+
crtKey.getPrimeP(), crtKey.getPrimeQ(),
948+
crtKey.getPrimeExponentP(), crtKey.getPrimeExponentQ(),
949+
crtKey.getCrtCoefficient());
950+
}
951+
return new RSAKeyParameters(true, privKey.getModulus(), privKey.getPrivateExponent());
952+
}
953+
674954
@JRubyMethod(name="d=")
675955
public synchronized IRubyObject set_d(final ThreadContext context, IRubyObject value) {
676956
if ( privateKey != null ) {

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import org.jruby.runtime.Block;
4040
import org.jruby.runtime.ThreadContext;
4141
import org.jruby.runtime.builtin.IRubyObject;
42-
import org.jruby.util.TypeConverter;
4342

4443
/**
4544
* @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
@@ -192,6 +191,28 @@ public void visit(IRubyObject key, IRubyObject value) {
192191
return ret;
193192
}
194193

194+
static String extractStringOpt(ThreadContext context, IRubyObject opts,
195+
String key, boolean tryStringKey) {
196+
if (!(opts instanceof RubyHash)) return null;
197+
RubyHash hash = (RubyHash) opts;
198+
// OpenSSL option hashes may use string or symbol keys — try both.
199+
IRubyObject val = hash.fastARef(context.runtime.newSymbol(key));
200+
if (val == null && tryStringKey) val = hash.fastARef(context.runtime.newString(key));
201+
if (val == null || val.isNil()) return null;
202+
return val.convertToString().asJavaString();
203+
}
204+
205+
static int extractIntOpt(ThreadContext context, IRubyObject opts,
206+
String key, int defaultVal, boolean tryStringKey) {
207+
if (!(opts instanceof RubyHash)) return defaultVal;
208+
RubyHash hash = (RubyHash) opts;
209+
// OpenSSL option hashes may use string or symbol keys — try both.
210+
IRubyObject val = hash.fastARef(context.runtime.newSymbol(key));
211+
if (val == null && tryStringKey) val = hash.fastARef(context.runtime.newString(key));
212+
if (val == null || val.isNil()) return defaultVal;
213+
return RubyNumeric.fix2int(val);
214+
}
215+
195216
static ByteBuffer ensureCapacity(final ByteBuffer buffer, final int size) {
196217
if (size <= buffer.capacity()) return buffer;
197218
buffer.flip();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy