diff --git a/8140597-Postpone-the-initial-mark-request-until-the-.patch b/8140597-Postpone-the-initial-mark-request-until-the-.patch new file mode 100755 index 0000000000000000000000000000000000000000..6ae854241ff98e6a8d280ac80511ce40876c2b7f --- /dev/null +++ b/8140597-Postpone-the-initial-mark-request-until-the-.patch @@ -0,0 +1,116 @@ +From c0bd92ca26dc2979f8be2f0a0477b1a945fe84ea Mon Sep 17 00:00:00 2001 +Date: Mon, 8 Feb 2021 09:47:28 +0800 +Subject: 8140597: Postpone the initial mark request until the + current mixed GC phase has finished. + +DTS/AR: DTS202102030LAZOBP1G00 +Summary: : +LLT: jtreg +Patch Type: backport +Bug url: https://dts-szv.clouddragon.huawei.com/DTSPortal/ticket/DTS202102030LAZOBP1G00 +--- + .../gc_implementation/g1/g1CollectedHeap.cpp | 1 - + .../g1/g1CollectorPolicy.cpp | 37 +++++++------------ + .../g1/g1CollectorPolicy.hpp | 2 + + 3 files changed, 16 insertions(+), 24 deletions(-) + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +index 722e59857..47d8000a0 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +@@ -2564,7 +2564,6 @@ void G1CollectedHeap::collect(GCCause::Cause cause) { + return; + } else { + if (cause == GCCause::_gc_locker || cause == GCCause::_wb_young_gc +- || cause == GCCause::_g1_periodic_collection + DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) { + + // Schedule a standard evacuation pause. We're setting word_size +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +index 05a270d26..ebf2619f9 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +@@ -921,8 +921,12 @@ void G1CollectorPolicy::record_concurrent_pause() { + } + } + ++bool G1CollectorPolicy::about_to_start_mixed_phase() const { ++ return _g1->concurrent_mark()->cmThread()->during_cycle() || _last_young_gc; ++} ++ + bool G1CollectorPolicy::need_to_start_conc_mark(const char* source, size_t alloc_word_size) { +- if (_g1->concurrent_mark()->cmThread()->during_cycle()) { ++ if (about_to_start_mixed_phase()) { + return false; + } + +@@ -1068,16 +1072,10 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, Evacua + if (_last_young_gc) { + // This is supposed to to be the "last young GC" before we start + // doing mixed GCs. Here we decide whether to start mixed GCs or not. +- +- if (!last_pause_included_initial_mark) { +- if (next_gc_should_be_mixed("start mixed GCs", ++ assert(!last_pause_included_initial_mark, "The last young GC is not allowed to be an initial mark GC"); ++ if (next_gc_should_be_mixed("start mixed GCs", + "do not start mixed GCs")) { +- set_gcs_are_young(false); +- } +- } else { +- ergo_verbose0(ErgoMixedGCs, +- "do not start mixed GCs", +- ergo_format_reason("concurrent cycle is about to start")); ++ set_gcs_are_young(false); + } + _last_young_gc = false; + } +@@ -1488,6 +1486,9 @@ void G1CollectorPolicy::update_survivors_policy(GCTracer &tracer) { + + bool G1CollectorPolicy::force_initial_mark_if_outside_cycle( + GCCause::Cause gc_cause) { ++ // We actually check whether we are marking here and not if we are in a ++ // reclamation phase. This means that we will schedule a concurrent mark ++ // even while we are still in the process of reclaiming memory. + bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle(); + if (!during_cycle) { + ergo_verbose1(ErgoConcCycles, +@@ -1523,20 +1524,10 @@ G1CollectorPolicy::decide_on_conc_mark_initiation() { + // gone over the initiating threshold and we should start a + // concurrent marking cycle. So we might initiate one. + +- bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle(); +- if (!during_cycle) { +- // The concurrent marking thread is not "during a cycle", i.e., +- // it has completed the last one. So we can go ahead and +- // initiate a new cycle. +- ++ if (!about_to_start_mixed_phase() && gcs_are_young()) { ++ // Initiate a new initial mark only if there is no marking or reclamation going ++ // on. + set_during_initial_mark_pause(); +- // We do not allow mixed GCs during marking. +- if (!gcs_are_young()) { +- set_gcs_are_young(true); +- ergo_verbose0(ErgoMixedGCs, +- "end mixed GCs", +- ergo_format_reason("concurrent cycle is about to start")); +- } + + // And we can now clear initiate_conc_mark_if_possible() as + // we've already acted on it. +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +index 1c9180704..6438e5e90 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +@@ -706,6 +706,8 @@ public: + + bool need_to_start_conc_mark(const char* source, size_t alloc_word_size = 0); + ++ bool about_to_start_mixed_phase() const; ++ + // Record the start and end of an evacuation pause. + void record_collection_pause_start(double start_time_sec, GCTracer &tracer); + void record_collection_pause_end(double pause_time_ms, EvacuationInfo& evacuation_info); +-- +2.19.0 + diff --git a/8160425.patch b/8160425.patch index 529a556b9216c96c049fd7d185254753e411776f..8aac0c810e9da7abab50b0fb2c819ca3bac31f25 100644 --- a/8160425.patch +++ b/8160425.patch @@ -4,8 +4,6 @@ Subject: 8160425: Vectorization with signalling NaN returns wrong result Summary: : Should not use doubles/floats for vector constants in the C code -LLT: huawei/test/gc/zgc/DTS2020032004776.java -Bug url: https://bugs.openjdk.java.net/browse/JDK-8160425 https://gitlab.huawei.com/huaweijdk/jdk8u-dev/issues/2213 --- hotspot/src/cpu/sparc/vm/sparc.ad | 10 +-- hotspot/src/cpu/x86/vm/x86.ad | 10 +-- diff --git a/8168996-backport-of-C2-crash-at-postaloc.cpp-140-ass.patch b/8168996-backport-of-C2-crash-at-postaloc.cpp-140-ass.patch new file mode 100755 index 0000000000000000000000000000000000000000..627bb7997425b7e10cee50a1f89757b31c2b457c --- /dev/null +++ b/8168996-backport-of-C2-crash-at-postaloc.cpp-140-ass.patch @@ -0,0 +1,32 @@ +From 9b140509c32b5878c1abdc16ec0edfd3e9f2f600 Mon Sep 17 00:00:00 2001 +Date: Fri, 29 Jan 2021 09:34:07 +0800 +Subject: 8168996: backport of C2 crash at postaloc.cpp:140 : + assert(false) failed: unexpected yanked node + +DTS/AR: DTS2021012903VX2SP0H00 +Summary: : Prevent MemBarAcquire from keeping a LoadNNode alive by adding it to the worklist if it is the only user of a DecodeNNode. +LLT: NA +Patch Type: backport +Bug url: https://bugs.openjdk.java.net/browse/JDK-8168996 +--- + hotspot/src/share/vm/opto/node.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp +index 60b390c09..a0d9acca4 100644 +--- a/hotspot/src/share/vm/opto/node.cpp ++++ b/hotspot/src/share/vm/opto/node.cpp +@@ -1168,8 +1168,8 @@ bool Node::has_special_unique_user() const { + if( this->is_Store() ) { + // Condition for back-to-back stores folding. + return n->Opcode() == op && n->in(MemNode::Memory) == this; +- } else if (this->is_Load()) { +- // Condition for removing an unused LoadNode from the MemBarAcquire precedence input ++ } else if (this->is_Load() || this->is_DecodeN()) { ++ // Condition for removing an unused LoadNode or DecodeNNode from the MemBarAcquire precedence input + return n->Opcode() == Op_MemBarAcquire; + } else if( op == Op_AddL ) { + // Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y)) +-- +2.19.0 + diff --git a/8203699.patch b/8203699.patch index c549623d7b2a796b2f4fbbb05f2f01cfcdeb25da..02dd88ac4db63332d26926a327065d36715698e9 100644 --- a/8203699.patch +++ b/8203699.patch @@ -33,12 +33,10 @@ new file mode 100644 index 000000000..8ab268b57 --- /dev/null +++ b/jdk/test/java/lang/invoke/lookup/TestDefenderMethodLookup.java -@@ -0,0 +1,166 @@ +@@ -0,0 +1,164 @@ +/* + * @test -+ * @author zhangli + * @bug 8203699 -+ * @summary see https://code.huawei.com/HuaweiJDK/JVM-team/JVM/issues/1368 + * @run testng/othervm test.java.lang.invoke.lookup.TestDefenderMethodLookup + */ + diff --git a/8214418-half-closed-SSLEngine-status-may-cause-appli.patch b/8214418-half-closed-SSLEngine-status-may-cause-appli.patch new file mode 100755 index 0000000000000000000000000000000000000000..e073e44f23d83a668d4ea140af624102aff76f29 --- /dev/null +++ b/8214418-half-closed-SSLEngine-status-may-cause-appli.patch @@ -0,0 +1,84 @@ +From 7419e8c4fd5b858c43378cffc55b45845f845191 Mon Sep 17 00:00:00 2001 +Date: Mon, 8 Mar 2021 09:28:45 +0800 +Subject: 8214418: half-closed SSLEngine status may cause + application dead loop + +DTS/AR: DTS20210308033J8XP0F00 +Summary: : half-closed SSLEngine status may cause application dead loop +LLT: NA +Patch Type: backport +Bug url: https://hg.openjdk.java.net/jdk-updates/jdk11u-dev/rev/6852be0de227 +--- + .../classes/sun/security/ssl/Ciphertext.java | 2 -- + .../classes/sun/security/ssl/SSLEngineImpl.java | 15 ++++++++++++++- + .../sun/security/ssl/TransportContext.java | 8 +------- + 3 files changed, 15 insertions(+), 10 deletions(-) + +diff --git a/jdk/src/share/classes/sun/security/ssl/Ciphertext.java b/jdk/src/share/classes/sun/security/ssl/Ciphertext.java +index 842db23af..5f95102b4 100644 +--- a/jdk/src/share/classes/sun/security/ssl/Ciphertext.java ++++ b/jdk/src/share/classes/sun/security/ssl/Ciphertext.java +@@ -31,8 +31,6 @@ import javax.net.ssl.SSLEngineResult.HandshakeStatus; + * Ciphertext + */ + final class Ciphertext { +- static final Ciphertext CIPHERTEXT_NULL = new Ciphertext(); +- + final byte contentType; + final byte handshakeType; + final long recordSN; +diff --git a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java +index 7906e5181..ef64c7b4e 100644 +--- a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java ++++ b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java +@@ -227,6 +227,19 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { + hsStatus = ciphertext.handshakeStatus; + } else { + hsStatus = getHandshakeStatus(); ++ if (ciphertext == null && !conContext.isNegotiated && ++ conContext.isInboundClosed() && ++ hsStatus == HandshakeStatus.NEED_WRAP) { ++ // Even the outboud is open, no futher data could be wrapped as: ++ // 1. the outbound is empty ++ // 2. no negotiated connection ++ // 3. the inbound has closed, cannot complete the handshake ++ // ++ // Mark the engine as closed if the handshake status is ++ // NEED_WRAP. Otherwise, it could lead to dead loops in ++ // applications. ++ status = Status.CLOSED; ++ } + } + + int deltaSrcs = srcsRemains; +@@ -258,7 +271,7 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { + } + + if (ciphertext == null) { +- return Ciphertext.CIPHERTEXT_NULL; ++ return null; + } + + // Is the handshake completed? +diff --git a/jdk/src/share/classes/sun/security/ssl/TransportContext.java b/jdk/src/share/classes/sun/security/ssl/TransportContext.java +index e9ffb3802..77a3c3bd5 100644 +--- a/jdk/src/share/classes/sun/security/ssl/TransportContext.java ++++ b/jdk/src/share/classes/sun/security/ssl/TransportContext.java +@@ -576,13 +576,7 @@ class TransportContext implements ConnectionContext { + } else if (!isOutboundClosed()) { + // Special case that the inbound was closed, but outbound open. + return HandshakeStatus.NEED_WRAP; +- } +- } else if (isOutboundClosed() && !isInboundClosed()) { +- // Special case that the outbound was closed, but inbound open. +- return HandshakeStatus.NEED_UNWRAP; +- } else if (!isOutboundClosed() && isInboundClosed()) { +- // Special case that the inbound was closed, but outbound open. +- return HandshakeStatus.NEED_WRAP; ++ } // Otherwise, both inbound and outbound are closed. + } + + return HandshakeStatus.NOT_HANDSHAKING; +-- +2.19.0 + diff --git a/8214535-support-Jmap-parallel.patch b/8214535-support-Jmap-parallel.patch new file mode 100755 index 0000000000000000000000000000000000000000..04e0516d0119ea4d450b6f0b43ab118ad6b7d320 --- /dev/null +++ b/8214535-support-Jmap-parallel.patch @@ -0,0 +1,1047 @@ +From 7566ad6d188b9f40b828dae1d814bcdd54967d25 Mon Sep 17 00:00:00 2001 +Date: Tue, 16 Mar 2021 06:02:47 +0000 +Subject: [PATCH 2/3] backport JDK-8214535 to support Jmap parallel + +--- + .../gc_implementation/g1/g1CollectedHeap.cpp | 30 ++++++ + .../gc_implementation/g1/g1CollectedHeap.hpp | 7 +- + .../vm/gc_implementation/g1/heapRegion.hpp | 3 +- + .../parallelScavenge/parallelScavengeHeap.cpp | 75 ++++++++++++- + .../parallelScavenge/parallelScavengeHeap.hpp | 9 +- + .../parallelScavenge/psOldGen.cpp | 29 +++++ + .../parallelScavenge/psOldGen.hpp | 11 ++ + .../shared/vmGCOperations.cpp | 2 +- + .../shared/vmGCOperations.hpp | 4 +- + .../shenandoah/shenandoahHeap.cpp | 3 + + .../shenandoah/shenandoahHeap.hpp | 2 + + .../share/vm/gc_interface/collectedHeap.hpp | 19 +++- + .../src/share/vm/memory/genCollectedHeap.cpp | 4 + + .../src/share/vm/memory/genCollectedHeap.hpp | 3 +- + .../src/share/vm/memory/heapInspection.cpp | 102 ++++++++++++++++-- + .../src/share/vm/memory/heapInspection.hpp | 46 +++++++- + hotspot/src/share/vm/runtime/arguments.hpp | 12 +-- + .../src/share/vm/services/attachListener.cpp | 13 ++- + hotspot/src/share/vm/utilities/workgroup.hpp | 21 +++- + .../share/classes/sun/tools/jmap/JMap.java | 39 +++++-- + jdk/test/sun/tools/common/ApplicationSetup.sh | 12 ++- + jdk/test/sun/tools/jmap/ParallelInspection.sh | 79 ++++++++++++++ + 22 files changed, 480 insertions(+), 45 deletions(-) + create mode 100644 jdk/test/sun/tools/jmap/ParallelInspection.sh + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +index 47d8000a..5cb13535 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +@@ -59,6 +59,7 @@ + #include "gc_implementation/shared/gcTraceTime.hpp" + #include "gc_implementation/shared/isGCActiveMark.hpp" + #include "memory/allocation.hpp" ++#include "memory/heapInspection.hpp" + #include "memory/gcLocker.inline.hpp" + #include "memory/generationSpec.hpp" + #include "memory/iterator.hpp" +@@ -381,6 +382,11 @@ void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_region + reset_from_card_cache(start_idx, num_regions); + } + ++void G1CollectedHeap::run_task(AbstractGangTask* task) { ++ workers()->run_task(task); ++ reset_heap_region_claim_values(); ++} ++ + void G1CollectedHeap::push_dirty_cards_region(HeapRegion* hr) + { + // Claim the right to put the region on the dirty cards region list +@@ -2647,6 +2653,30 @@ void G1CollectedHeap::object_iterate(ObjectClosure* cl) { + heap_region_iterate(&blk); + } + ++class G1ParallelObjectIterator : public ParallelObjectIterator { ++private: ++ G1CollectedHeap* _heap; ++ uint _num_threads; ++ ++public: ++ G1ParallelObjectIterator(uint thread_num) : ++ _heap(G1CollectedHeap::heap()),_num_threads(thread_num) {} ++ ++ virtual void object_iterate(ObjectClosure* cl, uint worker_id) { ++ _heap->object_iterate_parallel(cl, worker_id,_num_threads); ++ } ++}; ++ ++ParallelObjectIterator* G1CollectedHeap::parallel_object_iterator(uint thread_num) { ++ return new G1ParallelObjectIterator(thread_num); ++} ++ ++void G1CollectedHeap::object_iterate_parallel(ObjectClosure* cl, uint worker_id, uint num_workers) { ++ IterateObjectClosureRegionClosure blk(cl); ++ heap_region_par_iterate_chunked(&blk, worker_id, num_workers, HeapRegion::ParInspectClaimValue); ++} ++ ++ + // Calls a SpaceClosure on a HeapRegion. + + class SpaceClosureRegionClosure: public HeapRegionClosure { +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +index bde0ca4d..f8c52e68 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +@@ -646,6 +646,8 @@ public: + G1Allocator* allocator() { + return _allocator; + } ++ // Runs the given AbstractGangTask with the current active workers. ++ virtual void run_task(AbstractGangTask* task); + + G1MonitoringSupport* g1mm() { + assert(_g1mm != NULL, "should have been initialized"); +@@ -1292,6 +1294,7 @@ public: + void cleanUpCardTable(); + + // Iteration functions. ++ void object_iterate_parallel(ObjectClosure* cl, uint worker_id, uint num_workers); + + // Iterate over all the ref-containing fields of all objects, calling + // "cl.do_oop" on each. +@@ -1299,7 +1302,7 @@ public: + + // Iterate over all objects, calling "cl.do_object" on each. + virtual void object_iterate(ObjectClosure* cl); +- ++ virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num); + virtual void safe_object_iterate(ObjectClosure* cl) { + object_iterate(cl); + } +@@ -1607,7 +1610,7 @@ public: + + // Perform any cleanup actions necessary before allowing a verification. + virtual void prepare_for_verify(); +- ++ virtual FlexibleWorkGang* get_safepoint_workers() { return _workers; } + // Perform verification. + + // vo == UsePrevMarking -> use "prev" marking information, +diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +index c16c906e..b58a3cc2 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +@@ -347,7 +347,8 @@ class HeapRegion: public G1OffsetTableContigSpace { + ParEvacFailureClaimValue = 6, + AggregateCountClaimValue = 7, + VerifyCountClaimValue = 8, +- ParMarkRootClaimValue = 9 ++ ParMarkRootClaimValue = 9, ++ ParInspectClaimValue = 10 + }; + + // All allocated blocks are occupied by objects in a HeapRegion +diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +index e13fefa2..cf281259 100644 +--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp ++++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +@@ -60,7 +60,12 @@ jint ParallelScavengeHeap::initialize() { + _collector_policy->initialize_all(); + + const size_t heap_size = _collector_policy->max_heap_byte_size(); +- ++ _workers = new FlexibleWorkGang("GC Thread",ParallelGCThreads, true, false); ++ if (_workers == NULL) { ++ vm_exit_during_initialization("Failed necessary allocation."); ++ } else { ++ _workers->initialize_workers(); ++ } + ReservedSpace heap_rs = Universe::reserve_heap(heap_size, _collector_policy->heap_alignment()); + MemTracker::record_virtual_memory_type((address)heap_rs.base(), mtJavaHeap); + +@@ -547,6 +552,71 @@ void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) { + old_gen()->object_iterate(cl); + } + ++// The HeapBlockClaimer is used during parallel iteration over the heap, ++// allowing workers to claim heap areas ("blocks"), gaining exclusive rights to these. ++// The eden and survivor spaces are treated as single blocks as it is hard to divide ++// these spaces. ++// The old space is divided into fixed-size blocks. ++class HeapBlockClaimer : public StackObj { ++ size_t _claimed_index; ++ ++public: ++ static const size_t InvalidIndex = SIZE_MAX; ++ static const size_t EdenIndex = 0; ++ static const size_t SurvivorIndex = 1; ++ static const size_t NumNonOldGenClaims = 2; ++ ++ HeapBlockClaimer() : _claimed_index(EdenIndex) { } ++ // Claim the block and get the block index. ++ size_t claim_and_get_block() { ++ size_t block_index; ++ block_index = Atomic::add(1u, reinterpret_cast(&_claimed_index)) - 1; ++ ++ PSOldGen* old_gen = ParallelScavengeHeap::heap()->old_gen(); ++ size_t num_claims = old_gen->num_iterable_blocks() + NumNonOldGenClaims; ++ ++ return block_index < num_claims ? block_index : InvalidIndex; ++ } ++}; ++ ++void ParallelScavengeHeap::object_iterate_parallel(ObjectClosure* cl, ++ HeapBlockClaimer* claimer) { ++ size_t block_index = claimer->claim_and_get_block(); ++ // Iterate until all blocks are claimed ++ if (block_index == HeapBlockClaimer::EdenIndex) { ++ young_gen()->eden_space()->object_iterate(cl); ++ block_index = claimer->claim_and_get_block(); ++ } ++ if (block_index == HeapBlockClaimer::SurvivorIndex) { ++ young_gen()->from_space()->object_iterate(cl); ++ young_gen()->to_space()->object_iterate(cl); ++ block_index = claimer->claim_and_get_block(); ++ } ++ while (block_index != HeapBlockClaimer::InvalidIndex) { ++ old_gen()->object_iterate_block(cl, block_index - HeapBlockClaimer::NumNonOldGenClaims); ++ block_index = claimer->claim_and_get_block(); ++ } ++} ++ ++class PSScavengeParallelObjectIterator : public ParallelObjectIterator { ++private: ++ ParallelScavengeHeap* _heap; ++ HeapBlockClaimer _claimer; ++ ++public: ++ PSScavengeParallelObjectIterator() : ++ _heap(ParallelScavengeHeap::heap()), ++ _claimer() {} ++ ++ virtual void object_iterate(ObjectClosure* cl, uint worker_id) { ++ _heap->object_iterate_parallel(cl, &_claimer); ++ } ++}; ++ ++ParallelObjectIterator* ParallelScavengeHeap::parallel_object_iterator(uint thread_num) { ++ return new PSScavengeParallelObjectIterator(); ++} ++ + + HeapWord* ParallelScavengeHeap::block_start(const void* addr) const { + if (young_gen()->is_in_reserved(addr)) { +@@ -622,6 +692,9 @@ void ParallelScavengeHeap::print_on_error(outputStream* st) const { + void ParallelScavengeHeap::gc_threads_do(ThreadClosure* tc) const { + PSScavenge::gc_task_manager()->threads_do(tc); + } ++void ParallelScavengeHeap::run_task(AbstractGangTask* task) { ++ _workers->run_task(task); ++} + + void ParallelScavengeHeap::print_gc_threads_on(outputStream* st) const { + PSScavenge::gc_task_manager()->print_threads_on(st); +diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp +index bf3a207c..96244cb4 100644 +--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp ++++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp +@@ -41,6 +41,7 @@ class GCHeapSummary; + class GCTaskManager; + class PSAdaptiveSizePolicy; + class PSHeapSummary; ++class HeapBlockClaimer; + + class ParallelScavengeHeap : public CollectedHeap { + friend class VMStructs; +@@ -55,7 +56,7 @@ class ParallelScavengeHeap : public CollectedHeap { + static ParallelScavengeHeap* _psh; + + GenerationSizer* _collector_policy; +- ++ FlexibleWorkGang* _workers; + // Collection of generations that are adjacent in the + // space reserved for the heap. + AdjoiningGenerations* _gens; +@@ -208,7 +209,9 @@ class ParallelScavengeHeap : public CollectedHeap { + void oop_iterate(ExtendedOopClosure* cl); + void object_iterate(ObjectClosure* cl); + void safe_object_iterate(ObjectClosure* cl) { object_iterate(cl); } +- ++ void object_iterate_parallel(ObjectClosure* cl, HeapBlockClaimer* claimer); ++ virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num); ++ virtual FlexibleWorkGang* get_safepoint_workers() { return _workers; } + HeapWord* block_start(const void* addr) const; + size_t block_size(const HeapWord* addr) const; + bool block_is_obj(const HeapWord* addr) const; +@@ -222,7 +225,7 @@ class ParallelScavengeHeap : public CollectedHeap { + virtual void print_gc_threads_on(outputStream* st) const; + virtual void gc_threads_do(ThreadClosure* tc) const; + virtual void print_tracing_info() const; +- ++ virtual void run_task(AbstractGangTask* task); + void verify(bool silent, VerifyOption option /* ignored */); + + void print_heap_change(size_t prev_used); +diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp +index 12d0d450..dd652553 100644 +--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp ++++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp +@@ -206,6 +206,35 @@ HeapWord* PSOldGen::allocate(size_t word_size) { + return res; + } + ++size_t PSOldGen::num_iterable_blocks() const { ++ return (object_space()->used_in_bytes() + IterateBlockSize - 1) / IterateBlockSize; ++} ++ ++void PSOldGen::object_iterate_block(ObjectClosure* cl, size_t block_index) { ++ size_t block_word_size = IterateBlockSize / HeapWordSize; ++ assert((block_word_size % (ObjectStartArray::block_size)) == 0, ++ "Block size not a multiple of start_array block"); ++ ++ MutableSpace *space = object_space(); ++ ++ HeapWord* begin = space->bottom() + block_index * block_word_size; ++ HeapWord* end = MIN2(space->top(), begin + block_word_size); ++ ++ if (!start_array()->object_starts_in_range(begin, end)) { ++ return; ++ } ++ ++ // Get object starting at or reaching into this block. ++ HeapWord* start = start_array()->object_start(begin); ++ if (start < begin) { ++ start += oop(start)->size(); ++ } ++ // Iterate all objects until the end. ++ for (HeapWord* p = start; p < end; p += oop(p)->size()) { ++ cl->do_object(oop(p)); ++ } ++} ++ + HeapWord* PSOldGen::expand_and_allocate(size_t word_size) { + expand(word_size*HeapWordSize); + if (GCExpandToAllocateDelayMillis > 0) { +diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp +index 90fa0d56..73738b95 100644 +--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp ++++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp +@@ -57,6 +57,9 @@ class PSOldGen : public CHeapObj { + const size_t _min_gen_size; + const size_t _max_gen_size; + ++ // Block size for parallel iteration ++ static const size_t IterateBlockSize = 1024 * 1024; ++ + // Used when initializing the _name field. + static inline const char* select_name(); + +@@ -170,6 +173,14 @@ class PSOldGen : public CHeapObj { + void oop_iterate_no_header(OopClosure* cl) { object_space()->oop_iterate_no_header(cl); } + void object_iterate(ObjectClosure* cl) { object_space()->object_iterate(cl); } + ++ // Number of blocks to be iterated over in the used part of old gen. ++ size_t num_iterable_blocks() const; ++ // Iterate the objects starting in block block_index within [bottom, top) of the ++ // old gen. The object just reaching into this block is not iterated over. ++ // A block is an evenly sized non-overlapping part of the old gen of ++ // IterateBlockSize bytes. ++ void object_iterate_block(ObjectClosure* cl, size_t block_index); ++ + // Debugging - do not use for time critical operations + virtual void print() const; + virtual void print_on(outputStream* st) const; +diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp +index 85059b82..d086a56c 100644 +--- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp ++++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp +@@ -188,7 +188,7 @@ void VM_GC_HeapInspection::doit() { + } + HeapInspection inspect(_csv_format, _print_help, _print_class_stats, + _columns); +- inspect.heap_inspection(_out); ++ inspect.heap_inspection(_out, _parallel_thread_num); + } + + +diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp +index cb070bd7..10d37522 100644 +--- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp ++++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp +@@ -132,18 +132,20 @@ class VM_GC_HeapInspection: public VM_GC_Operation { + private: + outputStream* _out; + bool _full_gc; ++ uint _parallel_thread_num; + bool _csv_format; // "comma separated values" format for spreadsheet. + bool _print_help; + bool _print_class_stats; + const char* _columns; + public: +- VM_GC_HeapInspection(outputStream* out, bool request_full_gc) : ++ VM_GC_HeapInspection(outputStream* out, bool request_full_gc, uint parallel_thread_num = 1) : + VM_GC_Operation(0 /* total collections, dummy, ignored */, + GCCause::_heap_inspection /* GC Cause */, + 0 /* total full collections, dummy, ignored */, + request_full_gc) { + _out = out; + _full_gc = request_full_gc; ++ _parallel_thread_num = parallel_thread_num; + _csv_format = false; + _print_help = false; + _print_class_stats = false; +diff --git a/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp b/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp +index eaf13322..2b45229c 100644 +--- a/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp ++++ b/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp +@@ -1112,6 +1112,9 @@ void ShenandoahHeap::gc_threads_do(ThreadClosure* tcl) const { + ShenandoahStringDedup::threads_do(tcl); + } + } ++void ShenandoahHeap::run_task(AbstractGangTask* task) { ++ workers()->run_task(task); ++} + + void ShenandoahHeap::print_tracing_info() const { + if (PrintGC || TraceGen0Time || TraceGen1Time) { +diff --git a/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.hpp b/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.hpp +index 8e3b9ee1..3cb92ed4 100644 +--- a/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.hpp ++++ b/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.hpp +@@ -192,6 +192,8 @@ public: + + void gc_threads_do(ThreadClosure* tcl) const; + ++ virtual void run_task(AbstractGangTask* task); ++ + // ---------- Heap regions handling machinery + // + private: +diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp +index 88632ddc..7af75fd6 100644 +--- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp ++++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp +@@ -25,6 +25,7 @@ + #ifndef SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_HPP + #define SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_HPP + ++#include "utilities/workgroup.hpp" + #include "gc_interface/gcCause.hpp" + #include "gc_implementation/shared/gcWhen.hpp" + #include "memory/allocation.hpp" +@@ -38,7 +39,7 @@ + // is an abstract class: there may be many different kinds of heaps. This + // class defines the functions that a heap must implement, and contains + // infrastructure common to all heaps. +- ++class AbstractGangTask; + class AdaptiveSizePolicy; + class BarrierSet; + class CollectorPolicy; +@@ -74,6 +75,12 @@ class GCHeapLog : public EventLogBase { + } + }; + ++class ParallelObjectIterator : public CHeapObj { ++public: ++ virtual void object_iterate(ObjectClosure* cl, uint worker_id) = 0; ++}; ++ ++ + // + // CollectedHeap + // SharedHeap +@@ -461,7 +468,7 @@ class CollectedHeap : public CHeapObj { + + // Does this heap support heap inspection (+PrintClassHistogram?) + virtual bool supports_heap_inspection() const = 0; +- ++ virtual FlexibleWorkGang* get_safepoint_workers() { return NULL; } + // Perform a collection of the heap; intended for use in implementing + // "System.gc". This probably implies as full a collection as the + // "CollectedHeap" supports. +@@ -514,7 +521,10 @@ class CollectedHeap : public CHeapObj { + // Iterate over all objects, calling "cl.do_object" on each. + virtual void object_iterate(ObjectClosure* cl) = 0; + +- // Similar to object_iterate() except iterates only ++ virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num) { ++ return NULL; ++ } ++ + // over live objects. + virtual void safe_object_iterate(ObjectClosure* cl) = 0; + +@@ -593,6 +603,9 @@ class CollectedHeap : public CHeapObj { + // Iterator for all GC threads (other than VM thread) + virtual void gc_threads_do(ThreadClosure* tc) const = 0; + ++ // Run given task. Possibly in parallel if the GC supports it. ++ virtual void run_task(AbstractGangTask* task) = 0; ++ + // Print any relevant tracing info that flags imply. + // Default implementation does nothing. + virtual void print_tracing_info() const = 0; +diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp +index bbe6370a..ed2c0afb 100644 +--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp ++++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp +@@ -1414,3 +1414,7 @@ void GenCollectedHeap::stop() { + } + #endif + } ++ ++void GenCollectedHeap::run_task(AbstractGangTask *task) { ++ ++} +diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.hpp b/hotspot/src/share/vm/memory/genCollectedHeap.hpp +index 6d0dd591..2c78ea15 100644 +--- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp ++++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp +@@ -120,6 +120,7 @@ public: + + // Returns JNI_OK on success + virtual jint initialize(); ++ + char* allocate(size_t alignment, + size_t* _total_reserved, int* _n_covered_regions, + ReservedSpace* heap_rs); +@@ -229,7 +230,7 @@ public: + // may not pack objects densely; a chunk may either be an object or a + // non-object. + virtual HeapWord* block_start(const void* addr) const; +- ++ virtual void run_task(AbstractGangTask* task); + // Requires "addr" to be the start of a chunk, and returns its size. + // "addr + size" is required to be the start of a new chunk, or the end + // of the active area of the heap. Assumes (and verifies in non-product +diff --git a/hotspot/src/share/vm/memory/heapInspection.cpp b/hotspot/src/share/vm/memory/heapInspection.cpp +index cc8f4fc0..7c44c50f 100644 +--- a/hotspot/src/share/vm/memory/heapInspection.cpp ++++ b/hotspot/src/share/vm/memory/heapInspection.cpp +@@ -28,6 +28,7 @@ + #include "memory/genCollectedHeap.hpp" + #include "memory/heapInspection.hpp" + #include "memory/resourceArea.hpp" ++#include "runtime/atomic.hpp" + #include "runtime/os.hpp" + #include "utilities/globalDefinitions.hpp" + #include "utilities/macros.hpp" +@@ -200,6 +201,41 @@ size_t KlassInfoTable::size_of_instances_in_words() const { + return _size_of_instances_in_words; + } + ++// Return false if the entry could not be recorded on account ++// of running out of space required to create a new entry. ++bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { ++ Klass* k = cie->klass(); ++ KlassInfoEntry* elt = lookup(k); ++ // elt may be NULL if it's a new klass for which we ++ // could not allocate space for a new entry in the hashtable. ++ if (elt != NULL) { ++ elt->set_count(elt->count() + cie->count()); ++ elt->set_words(elt->words() + cie->words()); ++ _size_of_instances_in_words += cie->words(); ++ return true; ++ } ++ return false; ++} ++ ++class KlassInfoTableMergeClosure : public KlassInfoClosure { ++private: ++ KlassInfoTable* _dest; ++ bool _success; ++public: ++ KlassInfoTableMergeClosure(KlassInfoTable* table) : _dest(table), _success(true) {} ++ void do_cinfo(KlassInfoEntry* cie) { ++ _success &= _dest->merge_entry(cie); ++ } ++ bool success() { return _success; } ++}; ++ ++// merge from table ++bool KlassInfoTable::merge(KlassInfoTable* table) { ++ KlassInfoTableMergeClosure closure(this); ++ table->iterate(&closure); ++ return closure.success(); ++} ++ + int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { + return (*e1)->compare(*e1,*e2); + } +@@ -461,7 +497,7 @@ class HistoClosure : public KlassInfoClosure { + class RecordInstanceClosure : public ObjectClosure { + private: + KlassInfoTable* _cit; +- size_t _missed_count; ++ uintx _missed_count; + BoolObjectClosure* _filter; + public: + RecordInstanceClosure(KlassInfoTable* cit, BoolObjectClosure* filter) : +@@ -475,7 +511,7 @@ class RecordInstanceClosure : public ObjectClosure { + } + } + +- size_t missed_count() { return _missed_count; } ++ uintx missed_count() { return _missed_count; } + + private: + bool should_visit(oop obj) { +@@ -483,17 +519,67 @@ class RecordInstanceClosure : public ObjectClosure { + } + }; + +-size_t HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *filter) { +- ResourceMark rm; ++// Heap inspection for every worker. ++// When native OOM hanppens for KlassInfoTable, set _success to false. ++void ParHeapInspectTask::work(uint worker_id) { ++ uintx missed_count = 0; ++ bool merge_success = true; ++ if (!Atomic::load(reinterpret_cast(&_success))) { ++ // other worker has failed on parallel iteration. ++ return; ++ } ++ KlassInfoTable cit(false); ++ if (cit.allocation_failed()) { ++ // fail to allocate memory, stop parallel mode ++ Atomic::store(false, reinterpret_cast(&_success)); ++ return; ++ } ++ RecordInstanceClosure ric(&cit, _filter); ++ _poi->object_iterate(&ric, worker_id); ++ missed_count = ric.missed_count(); ++ { ++ MutexLocker x(&_mutex); ++ merge_success = _shared_cit->merge(&cit); ++ } ++ if (merge_success) { ++ Atomic::add(missed_count, reinterpret_cast(&missed_count)); ++ } else { ++ Atomic::store(false, reinterpret_cast(&_success)); ++ } ++} + ++size_t HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *filter, uint parallel_thread_num) { ++ // Try parallel first. ++ if (parallel_thread_num > 1) { ++ ResourceMark rm; ++ FlexibleWorkGang* gang = Universe::heap()->get_safepoint_workers(); ++ if (gang != NULL) { ++ // The GC provided a WorkGang to be used during a safepoint. ++ // Can't run with more threads than provided by the WorkGang. ++ WithUpdatedActiveWorkers update_and_restore(gang, parallel_thread_num); ++ ParallelObjectIterator* poi = Universe::heap()->parallel_object_iterator(gang->active_workers()); ++ if (poi != NULL) { ++ // The GC supports parallel object iteration. ++ ParHeapInspectTask task(poi, cit, filter); ++ // Run task with the active workers. ++ Universe::heap()->run_task(&task); ++ delete poi; ++ if (task.success()) { ++ return task.missed_count(); ++ } ++ } ++ } ++ } ++ ++ ResourceMark rm; ++ // If no parallel iteration available, run serially. + RecordInstanceClosure ric(cit, filter); + Universe::heap()->object_iterate(&ric); + return ric.missed_count(); + } + +-void HeapInspection::heap_inspection(outputStream* st) { ++void HeapInspection::heap_inspection(outputStream* st, uint parallel_thread_num) { + ResourceMark rm; +- + if (_print_help) { + for (int c=0; cprint("%s:\n\t", name_table[c]); +@@ -514,9 +600,9 @@ void HeapInspection::heap_inspection(outputStream* st) { + + KlassInfoTable cit(_print_class_stats); + if (!cit.allocation_failed()) { +- size_t missed_count = populate_table(&cit); ++ uintx missed_count = populate_table(&cit, NULL, parallel_thread_num); + if (missed_count != 0) { +- st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT ++ st->print_cr("WARNING: Ran out of C-heap; undercounted " UINTX_FORMAT + " total instances in data below", + missed_count); + } +diff --git a/hotspot/src/share/vm/memory/heapInspection.hpp b/hotspot/src/share/vm/memory/heapInspection.hpp +index c5fec15c..d2fed80b 100644 +--- a/hotspot/src/share/vm/memory/heapInspection.hpp ++++ b/hotspot/src/share/vm/memory/heapInspection.hpp +@@ -25,11 +25,14 @@ + #ifndef SHARE_VM_MEMORY_HEAPINSPECTION_HPP + #define SHARE_VM_MEMORY_HEAPINSPECTION_HPP + ++#include "utilities/workgroup.hpp" + #include "memory/allocation.inline.hpp" + #include "oops/oop.inline.hpp" + #include "oops/annotations.hpp" + #include "utilities/macros.hpp" + ++class ParallelObjectIterator; ++ + #if INCLUDE_SERVICES + + +@@ -254,7 +257,8 @@ class KlassInfoTable: public StackObj { + void iterate(KlassInfoClosure* cic); + bool allocation_failed() { return _buckets == NULL; } + size_t size_of_instances_in_words() const; +- ++ bool merge(KlassInfoTable* table); ++ bool merge_entry(const KlassInfoEntry* cie); + friend class KlassInfoHisto; + }; + +@@ -366,11 +370,47 @@ class HeapInspection : public StackObj { + bool print_class_stats, const char *columns) : + _csv_format(csv_format), _print_help(print_help), + _print_class_stats(print_class_stats), _columns(columns) {} +- void heap_inspection(outputStream* st) NOT_SERVICES_RETURN; +- size_t populate_table(KlassInfoTable* cit, BoolObjectClosure* filter = NULL) NOT_SERVICES_RETURN_(0); ++ void heap_inspection(outputStream* st, uint parallel_thread_num = 1) NOT_SERVICES_RETURN; ++ size_t populate_table(KlassInfoTable* cit, BoolObjectClosure* filter = NULL, uint parallel_thread_num = 1) NOT_SERVICES_RETURN_(0); + static void find_instances_at_safepoint(Klass* k, GrowableArray* result) NOT_SERVICES_RETURN; + private: + void iterate_over_heap(KlassInfoTable* cit, BoolObjectClosure* filter = NULL); + }; + ++// Parallel heap inspection task. Parallel inspection can fail due to ++// a native OOM when allocating memory for TL-KlassInfoTable. ++// _success will be set false on an OOM, and serial inspection tried. ++class ParHeapInspectTask : public AbstractGangTask { ++private: ++ ParallelObjectIterator *_poi; ++ KlassInfoTable *_shared_cit; ++ BoolObjectClosure *_filter; ++ uintx _missed_count; ++ bool _success; ++ Mutex _mutex; ++ ++public: ++ ParHeapInspectTask(ParallelObjectIterator *poi, ++ KlassInfoTable *shared_cit, ++ BoolObjectClosure *filter) : ++ AbstractGangTask("Iterating heap"), ++ _poi(poi), ++ _shared_cit(shared_cit), ++ _filter(filter), ++ _missed_count(0), ++ _success(true), ++ _mutex(Mutex::leaf, "Parallel heap iteration data merge lock") {} ++ ++ uintx missed_count() const { ++ return _missed_count; ++ } ++ ++ bool success() { ++ return _success; ++ } ++ ++ virtual void work(uint worker_id); ++}; ++ ++ + #endif // SHARE_VM_MEMORY_HEAPINSPECTION_HPP +diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp +index 03f293e3..9dbe99ef 100644 +--- a/hotspot/src/share/vm/runtime/arguments.hpp ++++ b/hotspot/src/share/vm/runtime/arguments.hpp +@@ -424,12 +424,6 @@ class Arguments : AllStatic { + static ArgsRange check_memory_size(julong size, julong min_size); + static ArgsRange parse_memory_size(const char* s, julong* long_arg, + julong min_size); +- // Parse a string for a unsigned integer. Returns true if value +- // is an unsigned integer greater than or equal to the minimum +- // parameter passed and returns the value in uintx_arg. Returns +- // false otherwise, with uintx_arg undefined. +- static bool parse_uintx(const char* value, uintx* uintx_arg, +- uintx min_size); + + // methods to build strings from individual args + static void build_jvm_args(const char* arg); +@@ -478,6 +472,12 @@ class Arguments : AllStatic { + public: + // Parses the arguments, first phase + static jint parse(const JavaVMInitArgs* args); ++ // Parse a string for a unsigned integer. Returns true if value ++ // is an unsigned integer greater than or equal to the minimum ++ // parameter passed and returns the value in uintx_arg. Returns ++ // false otherwise, with uintx_arg undefined ++ static bool parse_uintx(const char* value, uintx* uintx_arg, ++ uintx min_size); + // Apply ergonomics + static jint apply_ergo(); + // Adjusts the arguments after the OS have adjusted the arguments +diff --git a/hotspot/src/share/vm/services/attachListener.cpp b/hotspot/src/share/vm/services/attachListener.cpp +index 0f51378d..d7529a44 100644 +--- a/hotspot/src/share/vm/services/attachListener.cpp ++++ b/hotspot/src/share/vm/services/attachListener.cpp +@@ -214,9 +214,11 @@ jint dump_heap(AttachOperation* op, outputStream* out) { + // + // Input arguments :- + // arg0: "-live" or "-all" ++// arg1: parallel thread number + static jint heap_inspection(AttachOperation* op, outputStream* out) { + bool live_objects_only = true; // default is true to retain the behavior before this change is made + const char* arg0 = op->arg(0); ++ uint parallel_thread_num = MAX2(1, (uint)os::initial_active_processor_count() * 3 / 8); + if (arg0 != NULL && (strlen(arg0) > 0)) { + if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) { + out->print_cr("Invalid argument to inspectheap operation: %s", arg0); +@@ -224,7 +226,16 @@ static jint heap_inspection(AttachOperation* op, outputStream* out) { + } + live_objects_only = strcmp(arg0, "-live") == 0; + } +- VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */); ++ const char* num_str = op->arg(1); ++ if (num_str != NULL && num_str[0] != '\0') { ++ uintx num; ++ if (!Arguments::parse_uintx(num_str, &num, 0)) { ++ out->print_cr("Invalid parallel thread number: [%s]", num_str); ++ return JNI_ERR; ++ } ++ parallel_thread_num = num == 0 ? parallel_thread_num : (uint)num; ++ } ++ VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, parallel_thread_num); + VMThread::execute(&heapop); + return JNI_OK; + } +diff --git a/hotspot/src/share/vm/utilities/workgroup.hpp b/hotspot/src/share/vm/utilities/workgroup.hpp +index dd956515..7e0fc973 100644 +--- a/hotspot/src/share/vm/utilities/workgroup.hpp ++++ b/hotspot/src/share/vm/utilities/workgroup.hpp +@@ -163,6 +163,7 @@ public: + virtual uint active_workers() const { + return _total_workers; + } ++ + bool terminate() const { + return _terminate; + } +@@ -325,6 +326,10 @@ class FlexibleWorkGang: public WorkGang { + _active_workers(UseDynamicNumberOfGCThreads ? 1U : ParallelGCThreads) {} + // Accessors for fields + virtual uint active_workers() const { return _active_workers; } ++ uint update_active_workers(uint v) { ++ _active_workers = MIN2(v, _active_workers); ++ return _active_workers; ++ } + void set_active_workers(uint v) { + assert(v <= _total_workers, + "Trying to set more workers active than there are"); +@@ -339,7 +344,21 @@ class FlexibleWorkGang: public WorkGang { + return _started_workers < _active_workers; + } + }; +- ++class WithUpdatedActiveWorkers : public StackObj { ++private: ++ FlexibleWorkGang* const _gang; ++ const uint _old_active_workers; ++public: ++ WithUpdatedActiveWorkers(FlexibleWorkGang* gang, uint requested_num_workers) : ++ _gang(gang), ++ _old_active_workers(gang->active_workers()) { ++ uint capped_num_workers = MIN2(requested_num_workers, gang->active_workers()); ++ gang->update_active_workers(capped_num_workers); ++ } ++ ~WithUpdatedActiveWorkers() { ++ _gang->set_active_workers(_old_active_workers); ++ } ++}; + // Work gangs in garbage collectors: 2009-06-10 + // + // SharedHeap - work gang for stop-the-world parallel collection. +diff --git a/jdk/src/share/classes/sun/tools/jmap/JMap.java b/jdk/src/share/classes/sun/tools/jmap/JMap.java +index 5d349fc0..e891b6c5 100644 +--- a/jdk/src/share/classes/sun/tools/jmap/JMap.java ++++ b/jdk/src/share/classes/sun/tools/jmap/JMap.java +@@ -47,7 +47,8 @@ public class JMap { + private static String HISTO_OPTION = "-histo"; + private static String LIVE_HISTO_OPTION = "-histo:live"; + private static String DUMP_OPTION_PREFIX = "-dump:"; +- ++ private static final String LIVE_OBJECTS_OPTION = "-live"; ++ private static final String ALL_OBJECTS_OPTION = "-all"; + // These options imply the use of a SA tool + private static String SA_TOOL_OPTIONS = + "-heap|-heap:format=b|-clstats|-finalizerinfo"; +@@ -134,10 +135,10 @@ public class JMap { + // Here we handle the built-in options + // As more options are added we should create an abstract tool class and + // have a table to map the options +- if (option.equals(HISTO_OPTION)) { +- histo(pid, false); +- } else if (option.equals(LIVE_HISTO_OPTION)) { +- histo(pid, true); ++ if (option.equals("-histo")) { ++ histo(pid, ""); ++ } else if (option.startsWith("-histo:")) { ++ histo(pid, option.substring("-histo:".length())); + } else if (option.startsWith(DUMP_OPTION_PREFIX)) { + dump(pid, option); + } else { +@@ -216,12 +217,26 @@ public class JMap { + return null; + } + +- private static final String LIVE_OBJECTS_OPTION = "-live"; +- private static final String ALL_OBJECTS_OPTION = "-all"; +- private static void histo(String pid, boolean live) throws IOException { ++ ++ private static void histo(String pid, String options) throws IOException { + VirtualMachine vm = attach(pid); +- InputStream in = ((HotSpotVirtualMachine)vm). +- heapHisto(live ? LIVE_OBJECTS_OPTION : ALL_OBJECTS_OPTION); ++ String parallel = null; ++ String liveopt = "-all"; ++ if (options.startsWith("live")) { ++ liveopt = "-live"; ++ } ++ String[] subopts = options.split(","); ++ for (int i = 0; i < subopts.length; i++) { ++ String subopt = subopts[i]; ++ if (subopt.startsWith("parallel=")) { ++ parallel = subopt.substring("parallel=".length()); ++ if (parallel == null) { ++ System.err.println("Fail: no number provided in option: '" + subopt + "'"); ++ System.exit(1); ++ } ++ } ++ } ++ InputStream in = ((HotSpotVirtualMachine)vm).heapHisto(liveopt,parallel); + drain(vm, in); + } + +@@ -360,6 +375,10 @@ public class JMap { + System.err.println(" -heap to print java heap summary"); + System.err.println(" -histo[:live] to print histogram of java object heap; if the \"live\""); + System.err.println(" suboption is specified, only count live objects"); ++ System.err.println(" parallel= parallel threads number for heap iteration:"); ++ System.err.println(" parallel=0 default behavior, use predefined number of threads"); ++ System.err.println(" parallel=1 disable parallel heap iteration"); ++ System.err.println(" parallel= use N threads for parallel heap iteration"); + System.err.println(" -clstats to print class loader statistics"); + System.err.println(" -finalizerinfo to print information on objects awaiting finalization"); + System.err.println(" -dump: to dump java heap in hprof binary format"); +diff --git a/jdk/test/sun/tools/common/ApplicationSetup.sh b/jdk/test/sun/tools/common/ApplicationSetup.sh +index 64da8b96..c0f6a636 100644 +--- a/jdk/test/sun/tools/common/ApplicationSetup.sh ++++ b/jdk/test/sun/tools/common/ApplicationSetup.sh +@@ -42,8 +42,15 @@ + startApplication() + { + appOutput="${TESTCLASSES}/Application.out" +- +- ${JAVA} -XX:+UsePerfData -classpath "${TESTCLASSPATH:-${TESTCLASSES}}" "$@" > "$appOutput" 2>&1 & ++ if [ $# -gt 2 ]; then ++ if [ $3 = "defineGC" ]; then ++ ${JAVA} -XX:+UsePerfData -XX:+$4 -classpath "${TESTCLASSPATH:-${TESTCLASSES}}" "$@" > "$appOutput" 2>&1 & ++ else ++ ${JAVA} -XX:+UsePerfData -classpath "${TESTCLASSPATH:-${TESTCLASSES}}" "$@" > "$appOutput" 2>&1 & ++ fi ++ else ++ ${JAVA} -XX:+UsePerfData -classpath "${TESTCLASSPATH:-${TESTCLASSES}}" "$@" > "$appOutput" 2>&1 & ++ fi + appJavaPid="$!" + appOtherPid= + appPidList="$appJavaPid" +@@ -120,7 +127,6 @@ startApplication() + echo "INFO: $1 output is in $appOutput" + } + +- + # Stops a simple application by invoking ShutdownSimpleApplication + # class with a specific port-file, usage: + # stopApplication port-file +diff --git a/jdk/test/sun/tools/jmap/ParallelInspection.sh b/jdk/test/sun/tools/jmap/ParallelInspection.sh +new file mode 100644 +index 00000000..69e51a76 +--- /dev/null ++++ b/jdk/test/sun/tools/jmap/ParallelInspection.sh +@@ -0,0 +1,79 @@ ++#!/bin/sh ++ ++# ++# Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. ++# ++ ++# @test ++# @summary Unit test for jmap parallel heap inspection feature ++# @library ../common ++# @build SimpleApplication ShutdownSimpleApplication ++# @run shell ParallelInspection.sh ++ ++. ${TESTSRC}/../common/CommonSetup.sh ++. ${TESTSRC}/../common/ApplicationSetup.sh ++# parallel num in G1GC ++# Start application and use PORTFILE for coordination ++PORTFILE="${TESTCLASSES}"/shutdown.port ++startApplication SimpleApplication "${PORTFILE}" defineGC UseG1GC ++ ++# all return statuses are checked in this test ++set +e ++ ++failed=0 ++ ++${JMAP} -J-XX:+UsePerfData -histo:parallel=0 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:parallel=1 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:parallel=2 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:live,parallel=0 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:live,parallel=1 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:live,parallel=2 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++set -e ++ ++stopApplication "${PORTFILE}" ++waitForApplication ++ ++# parallel num in ParallelGC ++# Start application and use PORTFILE for coordination ++PORTFILE="${TESTCLASSES}"/shutdown.port ++startApplication SimpleApplication "${PORTFILE}" defineGC UseParallelGC ++ ++# all return statuses are checked in this test ++set +e ++ ++failed=0 ++ ++${JMAP} -J-XX:+UsePerfData -histo:parallel=0 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:parallel=1 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:parallel=2 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:live,parallel=0 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:live,parallel=1 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++ ++${JMAP} -J-XX:+UsePerfData -histo:live,parallel=2 $appJavaPid ++if [ $? != 0 ]; then failed=1; fi ++set -e ++ ++stopApplication "${PORTFILE}" ++waitForApplication ++ ++exit $failed +-- +2.19.0 + diff --git a/8231841-debug.cpp-help-is-missing-an-AArch64-line-fo.patch b/8231841-debug.cpp-help-is-missing-an-AArch64-line-fo.patch new file mode 100755 index 0000000000000000000000000000000000000000..3d9294d464053067dd2230a01c18f9565a20e3b4 --- /dev/null +++ b/8231841-debug.cpp-help-is-missing-an-AArch64-line-fo.patch @@ -0,0 +1,29 @@ +From b271a27e0a3742705b1515976ad63ffa791a6a79 Mon Sep 17 00:00:00 2001 +Date: Fri, 18 Dec 2020 11:18:19 +0800 +Subject: 8231841: debug.cpp help() is missing an AArch64 line + for pns + +DTS/AR: AR.SR.IREQ02373832.002.001 +Summary: < hotspot> : debug.cpp help() is missing an AArch64 line for pns +LLT: NA +Patch Type: backport +Bug url: https://bugs.openjdk.java.net/browse/JDK-8231841 +--- + hotspot/src/share/vm/utilities/debug.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp +index 4f7cbddcd..7ba3a4c83 100644 +--- a/hotspot/src/share/vm/utilities/debug.cpp ++++ b/hotspot/src/share/vm/utilities/debug.cpp +@@ -687,6 +687,7 @@ void help() { + tty->print_cr(" pns(void* sp, void* fp, void* pc) - print native (i.e. mixed) stack trace. E.g."); + tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or"); + tty->print_cr(" pns($sp, $ebp, $pc) on Linux/x86 or"); ++ tty->print_cr(" pns($sp, $fp, $pc) on Linux/AArch64 or"); + tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or"); + tty->print_cr(" pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC"); + tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()"); +-- +2.19.0 + diff --git a/8240353.patch b/8240353.patch new file mode 100644 index 0000000000000000000000000000000000000000..ddc27ca933a543ba2f707400dfe256bc02341112 --- /dev/null +++ b/8240353.patch @@ -0,0 +1,49 @@ +diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +index e25061f7d..2df587d96 100644 +--- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp ++++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +@@ -1,6 +1,6 @@ + /* + * Copyright (c) 2013, Red Hat Inc. +- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. ++ * Copyright (c) 2000, 2020, Oracle and/or its affiliates. + * All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * +@@ -434,12 +434,9 @@ int LIR_Assembler::emit_unwind_handler() { + } + + if (compilation()->env()->dtrace_method_probes()) { +- __ call_Unimplemented(); +-#if 0 +- __ movptr(Address(rsp, 0), rax); +- __ mov_metadata(Address(rsp, sizeof(void*)), method()->constant_encoding()); +- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit))); +-#endif ++ __ mov(c_rarg0, rthread); ++ __ mov_metadata(c_rarg1, method()->constant_encoding()); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), c_rarg0, c_rarg1); + } + + if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { +diff --git a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp +index c1e48ac97..e774f2140 100644 +--- a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp ++++ b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp +@@ -1319,6 +1319,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { + } + break; + ++ case dtrace_object_alloc_id: ++ { // c_rarg0: object ++ StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments); ++ save_live_registers(sasm); ++ ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), c_rarg0); ++ ++ restore_live_registers(sasm); ++ } ++ break; + + default: + { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments); diff --git a/8254078-DataOutputStream-is-very-slow-post-disabling.patch b/8254078-DataOutputStream-is-very-slow-post-disabling.patch new file mode 100755 index 0000000000000000000000000000000000000000..8e7e356405d58ed8f55cfda90b3407346f96178e --- /dev/null +++ b/8254078-DataOutputStream-is-very-slow-post-disabling.patch @@ -0,0 +1,92 @@ +From 4deae815b41e9dd02eb49bae3148f774c346e8a5 Mon Sep 17 00:00:00 2001 +Date: Mon, 25 Jan 2021 15:48:35 +0800 +Subject: 8254078: DataOutputStream is very slow post-disabling + of Biased Locking + +DTS/AR: DTS202101180520BWP1D00 +Summary: : DataOutputStream is very slow post-disabling of Biased Locking +LLT: jtreg +Patch Type: backport +Bug url: https://bugs.openjdk.java.net/browse/JDK-8254078 +--- + .../classes/java/io/DataInputStream.java | 7 +++--- + .../classes/java/io/DataOutputStream.java | 24 ++++++++++++------- + 2 files changed, 20 insertions(+), 11 deletions(-) + +diff --git a/jdk/src/share/classes/java/io/DataInputStream.java b/jdk/src/share/classes/java/io/DataInputStream.java +index 7b24b74de..9516d0a7d 100644 +--- a/jdk/src/share/classes/java/io/DataInputStream.java ++++ b/jdk/src/share/classes/java/io/DataInputStream.java +@@ -31,9 +31,10 @@ package java.io; + * way. An application uses a data output stream to write data that + * can later be read by a data input stream. + *

+- * DataInputStream is not necessarily safe for multithreaded access. +- * Thread safety is optional and is the responsibility of users of +- * methods in this class. ++ * A DataInputStream is not safe for use by multiple concurrent ++ * threads. If a DataInputStream is to be used by more than one ++ * thread then access to the data input stream should be controlled ++ * by appropriate synchronization. + * + * @author Arthur van Hoff + * @see java.io.DataOutputStream +diff --git a/jdk/src/share/classes/java/io/DataOutputStream.java b/jdk/src/share/classes/java/io/DataOutputStream.java +index 99fafed84..7628fb916 100644 +--- a/jdk/src/share/classes/java/io/DataOutputStream.java ++++ b/jdk/src/share/classes/java/io/DataOutputStream.java +@@ -29,6 +29,11 @@ package java.io; + * A data output stream lets an application write primitive Java data + * types to an output stream in a portable way. An application can + * then use a data input stream to read the data back in. ++ *

++ * A DataOutputStream is not safe for use by multiple concurrent ++ * threads. If a DataOutputStream is to be used by more than one ++ * thread then access to the data output stream should be controlled ++ * by appropriate synchronization. + * + * @author unascribed + * @see java.io.DataInputStream +@@ -164,8 +169,9 @@ class DataOutputStream extends FilterOutputStream implements DataOutput { + * @see java.io.FilterOutputStream#out + */ + public final void writeShort(int v) throws IOException { +- out.write((v >>> 8) & 0xFF); +- out.write((v >>> 0) & 0xFF); ++ writeBuffer[0] = (byte)(v >>> 8); ++ writeBuffer[1] = (byte)(v >>> 0); ++ out.write(writeBuffer, 0, 2); + incCount(2); + } + +@@ -179,8 +185,9 @@ class DataOutputStream extends FilterOutputStream implements DataOutput { + * @see java.io.FilterOutputStream#out + */ + public final void writeChar(int v) throws IOException { +- out.write((v >>> 8) & 0xFF); +- out.write((v >>> 0) & 0xFF); ++ writeBuffer[0] = (byte)(v >>> 8); ++ writeBuffer[1] = (byte)(v >>> 0); ++ out.write(writeBuffer, 0, 2); + incCount(2); + } + +@@ -194,10 +201,11 @@ class DataOutputStream extends FilterOutputStream implements DataOutput { + * @see java.io.FilterOutputStream#out + */ + public final void writeInt(int v) throws IOException { +- out.write((v >>> 24) & 0xFF); +- out.write((v >>> 16) & 0xFF); +- out.write((v >>> 8) & 0xFF); +- out.write((v >>> 0) & 0xFF); ++ writeBuffer[0] = (byte)(v >>> 24); ++ writeBuffer[1] = (byte)(v >>> 16); ++ writeBuffer[2] = (byte)(v >>> 8); ++ writeBuffer[3] = (byte)(v >>> 0); ++ out.write(writeBuffer, 0, 4); + incCount(4); + } + +-- +2.19.0 + diff --git a/8259886-Improve-SSL-session-cache-performance-and-sc.patch b/8259886-Improve-SSL-session-cache-performance-and-sc.patch new file mode 100755 index 0000000000000000000000000000000000000000..73192e0b29cb3b0d6612e9db2e2be3b2f8d9cdd9 --- /dev/null +++ b/8259886-Improve-SSL-session-cache-performance-and-sc.patch @@ -0,0 +1,95 @@ +From c30e6789e2406ef5085978458c1342505f0eeb0b Mon Sep 17 00:00:00 2001 +Date: Thu, 11 Mar 2021 14:34:12 +0800 +Subject: 8259886: Improve SSL session cache performance and + scalability + +DTS/AR: DTS202103110E0APCP0H00 +Summary: : Improve SSL session cache performance and scalability +LLT: NA +Patch Type: backport +Bug url: https://bugs.openjdk.java.net/browse/JDK-8259886 +--- + .../classes/sun/security/util/Cache.java | 21 ++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/jdk/src/share/classes/sun/security/util/Cache.java b/jdk/src/share/classes/sun/security/util/Cache.java +index 7a2e6f394..1ba64a2c7 100644 +--- a/jdk/src/share/classes/sun/security/util/Cache.java ++++ b/jdk/src/share/classes/sun/security/util/Cache.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -252,6 +252,7 @@ class MemoryCache extends Cache { + private final Map> cacheMap; + private int maxSize; + private long lifetime; ++ private long nextExpirationTime = Long.MAX_VALUE; + + // ReferenceQueue is of type V instead of Cache + // to allow SoftCacheEntry to extend SoftReference +@@ -321,12 +322,18 @@ class MemoryCache extends Cache { + } + int cnt = 0; + long time = System.currentTimeMillis(); ++ if (nextExpirationTime > time) { ++ return; ++ } ++ nextExpirationTime = Long.MAX_VALUE; + for (Iterator> t = cacheMap.values().iterator(); + t.hasNext(); ) { + CacheEntry entry = t.next(); + if (entry.isValid(time) == false) { + t.remove(); + cnt++; ++ } else if (nextExpirationTime > entry.getExpirationTime()) { ++ nextExpirationTime = entry.getExpirationTime(); + } + } + if (DEBUG) { +@@ -360,6 +367,9 @@ class MemoryCache extends Cache { + emptyQueue(); + long expirationTime = (lifetime == 0) ? 0 : + System.currentTimeMillis() + lifetime; ++ if (expirationTime < nextExpirationTime) { ++ nextExpirationTime = expirationTime; ++ } + CacheEntry newEntry = newEntry(key, value, expirationTime, queue); + CacheEntry oldEntry = cacheMap.put(key, newEntry); + if (oldEntry != null) { +@@ -474,6 +484,7 @@ class MemoryCache extends Cache { + + V getValue(); + ++ long getExpirationTime(); + } + + private static class HardCacheEntry implements CacheEntry { +@@ -496,6 +507,10 @@ class MemoryCache extends Cache { + return value; + } + ++ public long getExpirationTime() { ++ return expirationTime; ++ } ++ + public boolean isValid(long currentTime) { + boolean valid = (currentTime <= expirationTime); + if (valid == false) { +@@ -533,6 +548,10 @@ class MemoryCache extends Cache { + return get(); + } + ++ public long getExpirationTime() { ++ return expirationTime; ++ } ++ + public boolean isValid(long currentTime) { + boolean valid = (currentTime <= expirationTime) && (get() != null); + if (valid == false) { +-- +2.19.0 + diff --git a/C1-typos-repair.patch b/C1-typos-repair.patch new file mode 100755 index 0000000000000000000000000000000000000000..9fde889c11983cf8a0e60d40e0cf7a5da3042e6d --- /dev/null +++ b/C1-typos-repair.patch @@ -0,0 +1,121 @@ +From 693b5eed765417ab055a19cbd5fd392cb052b06f Mon Sep 17 00:00:00 2001 +Date: Sat, 27 Feb 2021 17:06:24 +0800 +Subject: C1 typos repair + +DTS/AR: DTS202102240GWU4QP1O00 +Summary: : +LLT: NA +Patch Type: huawei +Bug url: NA +--- + .../src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp | 6 +++--- + .../src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp | 3 +-- + hotspot/src/share/vm/c1/c1_GraphBuilder.cpp | 7 +++---- + hotspot/src/share/vm/c1/c1_LIR.hpp | 12 ++++++------ + hotspot/src/share/vm/c1/c1_LIRGenerator.hpp | 1 - + 5 files changed, 13 insertions(+), 16 deletions(-) + +diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +index 2df587d96..60b67494c 100644 +--- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp ++++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +@@ -1004,7 +1004,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch + if (UseCompressedOops && !wide) { + __ ldrw(dest->as_register(), as_Address(from_addr)); + } else { +- __ ldr(dest->as_register(), as_Address(from_addr)); ++ __ ldr(dest->as_register(), as_Address(from_addr)); + } + break; + case T_METADATA: +@@ -1020,9 +1020,9 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch + // address that matches klass_offset_in_bytes() will be loaded + // as a word, not a long. + if (UseCompressedClassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) { +- __ ldrw(dest->as_register(), as_Address(from_addr)); ++ __ ldrw(dest->as_register(), as_Address(from_addr)); + } else { +- __ ldr(dest->as_register(), as_Address(from_addr)); ++ __ ldr(dest->as_register(), as_Address(from_addr)); + } + break; + case T_INT: +diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp +index cee0730d9..6d0b4acbd 100644 +--- a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp ++++ b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp +@@ -965,7 +965,6 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) { + assert(UseCRC32Intrinsics, "why are we here?"); + // Make all state_for calls early since they can emit code + LIR_Opr result = rlock_result(x); +- int flags = 0; + switch (x->id()) { + case vmIntrinsics::_updateCRC32: { + LIRItem crc(x->argument_at(0), this); +@@ -992,7 +991,7 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) { + int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0; + if(off.result()->is_constant()) { + index = LIR_OprFact::illegalOpr; +- offset += off.result()->as_jint(); ++ offset += off.result()->as_jint(); + } + LIR_Opr base_op = buf.result(); + +diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +index 174e59436..459315cb7 100644 +--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp ++++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +@@ -3243,10 +3243,9 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) + // Compiles where the root method is an intrinsic need a special + // compilation environment because the bytecodes for the method + // shouldn't be parsed during the compilation, only the special +- // Intrinsic node should be emitted. If this isn't done the the +- // code for the inlined version will be different than the root +- // compiled version which could lead to monotonicity problems on +- // intel. ++ // Intrinsic node should be emitted. If this isn't done the code ++ // for the inlined version will be different than the root compiled ++ // version which could lead to monotonicity problems on intel. + + // Set up a stream so that appending instructions works properly. + ciBytecodeStream s(scope->method()); +diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp +index 37232b9ba..cde709684 100644 +--- a/hotspot/src/share/vm/c1/c1_LIR.hpp ++++ b/hotspot/src/share/vm/c1/c1_LIR.hpp +@@ -200,14 +200,14 @@ class LIR_Const: public LIR_OprPtr { + class LIR_OprDesc: public CompilationResourceObj { + public: + // value structure: +- // data opr-type opr-kind +- // +--------------+-------+-------+ +- // [max...........|7 6 5 4|3 2 1 0] +- // ^ +- // is_pointer bit ++ // data opr-type opr-kind ++ // +-----------+----------+-------+ ++ // [max........|6 5 4 3|2 1 0] ++ // ^ ++ // is_pointer bit + // + // lowest bit cleared, means it is a structure pointer +- // we need 4 bits to represent types ++ // we need 4 bits to represent types + + private: + friend class LIR_OprFact; +diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +index 0ae48924a..24d072b36 100644 +--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp ++++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +@@ -611,7 +611,6 @@ class LIRItem: public CompilationResourceObj { + } else { + return _result; + } +- return _result; + } + + void set_result(LIR_Opr opr); +-- +2.19.0 + diff --git a/G1-memory-uncommit.patch b/G1-memory-uncommit.patch index fd8ccff06f682e70dcf0bc52ecbed67d1d6ce194..adaac309e2e11f25bc9fab9c53d253c83ada6067 100644 --- a/G1-memory-uncommit.patch +++ b/G1-memory-uncommit.patch @@ -2118,16 +2118,3 @@ index 00000000..7647daaa +{ + (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); +} -diff --git a/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c b/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c -index a2ddcb93..93af600d 100644 ---- a/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c -+++ b/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c -@@ -57,7 +57,7 @@ static struct perfbuf { - ticks *cpus; - } counters; - --#define DEC_64 "%lld" -+#define DEC_64 "%lud" - - static void next_line(FILE *f) { - while (fgetc(f) != '\n'); diff --git a/Test8167409.sh-fails-to-run-with-32bit-jdk-on-64bit-.patch b/Test8167409.sh-fails-to-run-with-32bit-jdk-on-64bit-.patch index 7e33188513e11afe17de4be3480acfceeb6021c9..b5fd0c47cc91cc18eed6b91311fe8d5801461124 100644 --- a/Test8167409.sh-fails-to-run-with-32bit-jdk-on-64bit-.patch +++ b/Test8167409.sh-fails-to-run-with-32bit-jdk-on-64bit-.patch @@ -5,7 +5,6 @@ Subject: Test8167409.sh fails to run with 32bit jdk on 64bit Summary: : Test8167409.sh fails to run with 32bit jdk on 64bit system LLT: jdk8u/hotspot/test/compiler/criticalnatives/argumentcorruption/Test8167409.sh -Bug url: https://gitlab.huawei.com/huaweijdk/jdk8u-dev/issues/2157 --- .../criticalnatives/argumentcorruption/Test8167409.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Use-Mutex-when-G1Uncommit.patch b/Use-Mutex-when-G1Uncommit.patch new file mode 100755 index 0000000000000000000000000000000000000000..ff9c1088793420ed9195571b7b6cf7f46257c554 --- /dev/null +++ b/Use-Mutex-when-G1Uncommit.patch @@ -0,0 +1,133 @@ +From 120ea606bc94b68e8a8d7d8c2cfc41bf472b5742 Mon Sep 17 00:00:00 2001 +Date: Mon, 8 Feb 2021 10:32:10 +0800 +Subject: Use Mutex when G1Uncommit + +DTS/AR: DTS2021021804F2O5P0H00 +Summary: : +LLT: jtreg +Patch Type: huawei +Bug url: https://dts-szv.clouddragon.huawei.com/DTSPortal/ticket/DTS2021021804F2O5P0H00 +--- + .../g1/g1PageBasedVirtualSpace.cpp | 8 +++---- + .../g1/g1RegionToSpaceMapper.cpp | 22 +++++++++++++------ + 2 files changed, 19 insertions(+), 11 deletions(-) + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp +index 1a22af82a..075217d60 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp +@@ -211,12 +211,12 @@ bool G1PageBasedVirtualSpace::commit(size_t start_page, size_t size_in_pages) { + // Check for dirty pages and update zero_filled if any found. + if (_dirty.get_next_one_offset(start_page, end_page) < end_page) { + zero_filled = false; +- _dirty.clear_range(start_page, end_page); ++ _dirty.par_clear_range(start_page, end_page, BitMap::unknown_range); + } + } else { + commit_internal(start_page, end_page); + } +- _committed.set_range(start_page, end_page); ++ _committed.par_set_range(start_page, end_page, BitMap::unknown_range); + + if (AlwaysPreTouch) { + pretouch_internal(start_page, end_page); +@@ -239,12 +239,12 @@ void G1PageBasedVirtualSpace::uncommit(size_t start_page, size_t size_in_pages) + if (_special) { + // Mark that memory is dirty. If committed again the memory might + // need to be cleared explicitly. +- _dirty.set_range(start_page, end_page); ++ _dirty.par_set_range(start_page, end_page, BitMap::unknown_range); + } else { + uncommit_internal(start_page, end_page); + } + +- _committed.clear_range(start_page, end_page); ++ _committed.par_clear_range(start_page, end_page, BitMap::unknown_range); + } + + bool G1PageBasedVirtualSpace::contains(const void* p) const { +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp +index 51b2bd8ad..f07c27107 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp +@@ -26,6 +26,8 @@ + #include "gc_implementation/g1/g1BiasedArray.hpp" + #include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" + #include "memory/allocation.inline.hpp" ++#include "runtime/mutex.hpp" ++#include "runtime/mutexLocker.hpp" + #include "runtime/virtualspace.hpp" + #include "services/memTracker.hpp" + #include "utilities/bitMap.inline.hpp" +@@ -68,13 +70,13 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper { + + virtual void commit_regions(uint start_idx, size_t num_regions) { + bool zero_filled = _storage.commit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region); +- _commit_map.set_range(start_idx, start_idx + num_regions); ++ _commit_map.par_set_range(start_idx, start_idx + num_regions, BitMap::unknown_range); + fire_on_commit(start_idx, num_regions, zero_filled); + } + + virtual void uncommit_regions(uint start_idx, size_t num_regions) { + _storage.uncommit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region); +- _commit_map.clear_range(start_idx, start_idx + num_regions); ++ _commit_map.par_clear_range(start_idx, start_idx + num_regions, BitMap::unknown_range); + } + }; + +@@ -89,7 +91,7 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { + }; + + size_t _regions_per_page; +- ++ Mutex _par_lock; + CommitRefcountArray _refcounts; + + uintptr_t region_idx_to_page_idx(uint region) const { +@@ -104,6 +106,7 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { + size_t commit_factor, + MemoryType type) : + G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, type), ++ _par_lock(Mutex::leaf, "G1RegionsSmallerThanCommitSizeMapper par lock"), + _regions_per_page((page_size * commit_factor) / alloc_granularity), _refcounts() { + + guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); +@@ -113,13 +116,15 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { + + virtual void commit_regions(uint start_idx, size_t num_regions) { + for (uint i = start_idx; i < start_idx + num_regions; i++) { ++ MutexLockerEx x(&_par_lock); + assert(!_commit_map.at(i), err_msg("Trying to commit storage at region %u that is already committed", i)); + size_t idx = region_idx_to_page_idx(i); +- uint new_refcount = Atomic::add(1, (volatile jint*)_refcounts.get_address_by_index(idx)); ++ uint old_refcount = _refcounts.get_by_index(idx); + bool zero_filled = false; +- if (new_refcount == 1) { ++ if (old_refcount == 0) { + zero_filled = _storage.commit(idx, 1); + } ++ _refcounts.set_by_index(idx, old_refcount + 1); + _commit_map.set_bit(i); + fire_on_commit(i, 1, zero_filled); + } +@@ -127,12 +132,15 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { + + virtual void uncommit_regions(uint start_idx, size_t num_regions) { + for (uint i = start_idx; i < start_idx + num_regions; i++) { ++ MutexLockerEx x(&_par_lock); + assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region %u that is not committed", i)); + size_t idx = region_idx_to_page_idx(i); +- uint new_refcount = Atomic::add(-1, (volatile jint*)_refcounts.get_address_by_index(idx)); +- if (new_refcount == 0) { ++ uint old_refcount = _refcounts.get_by_index(idx); ++ assert(old_refcount > 0, "must be"); ++ if (old_refcount == 1) { + _storage.uncommit(idx, 1); + } ++ _refcounts.set_by_index(idx, old_refcount - 1); + _commit_map.clear_bit(i); + } + } +-- +2.19.0 + diff --git a/Use-atomic-operation-when-G1Uncommit.patch b/Use-atomic-operation-when-G1Uncommit.patch new file mode 100755 index 0000000000000000000000000000000000000000..43beb5eb89873c3891e9a05c6ec2b0a69d6bd12f --- /dev/null +++ b/Use-atomic-operation-when-G1Uncommit.patch @@ -0,0 +1,110 @@ +From bdff9eab4eb0bc16ebdbe908cc6237e0a70d53e6 Mon Sep 17 00:00:00 2001 +Date: Sat, 26 Dec 2020 11:22:37 +0800 +Subject: Use atomic operation when G1Uncommit + +DTS/AR: DTS2021012207P2X7P0E00 +Summary: : +LLT: jtreg +Patch Type: huawei +Bug url: https://dts-szv.clouddragon.huawei.com/DTSPortal/ticket/DTS2021012207P2X7P0E00 +--- + .../vm/gc_implementation/g1/g1BiasedArray.hpp | 5 ++++ + .../g1/g1RegionToSpaceMapper.cpp | 11 ++++----- + .../vm/gc_implementation/g1/heapRegion.cpp | 24 +++++++++++++++++++ + 3 files changed, 33 insertions(+), 7 deletions(-) + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp +index 88a673574..e13c3fe8d 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp +@@ -109,6 +109,11 @@ public: + return this->base()[index]; + } + ++ T* get_address_by_index(idx_t index) const { ++ verify_index(index); ++ return this->base() + index; ++ } ++ + // Set the element of the given array at the given index to the + // given value. Assume the index is valid. This is a convenience + // method that does sanity checking on the index. +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp +index 0c26b783e..51b2bd8ad 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp +@@ -115,12 +115,11 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { + for (uint i = start_idx; i < start_idx + num_regions; i++) { + assert(!_commit_map.at(i), err_msg("Trying to commit storage at region %u that is already committed", i)); + size_t idx = region_idx_to_page_idx(i); +- uint old_refcount = _refcounts.get_by_index(idx); ++ uint new_refcount = Atomic::add(1, (volatile jint*)_refcounts.get_address_by_index(idx)); + bool zero_filled = false; +- if (old_refcount == 0) { ++ if (new_refcount == 1) { + zero_filled = _storage.commit(idx, 1); + } +- _refcounts.set_by_index(idx, old_refcount + 1); + _commit_map.set_bit(i); + fire_on_commit(i, 1, zero_filled); + } +@@ -130,12 +129,10 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { + for (uint i = start_idx; i < start_idx + num_regions; i++) { + assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region %u that is not committed", i)); + size_t idx = region_idx_to_page_idx(i); +- uint old_refcount = _refcounts.get_by_index(idx); +- assert(old_refcount > 0, "must be"); +- if (old_refcount == 1) { ++ uint new_refcount = Atomic::add(-1, (volatile jint*)_refcounts.get_address_by_index(idx)); ++ if (new_refcount == 0) { + _storage.uncommit(idx, 1); + } +- _refcounts.set_by_index(idx, old_refcount - 1); + _commit_map.clear_bit(i); + } + } +diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +index 32f8b1985..987d2c138 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +@@ -322,6 +322,29 @@ HeapRegion::HeapRegion(uint hrm_index, + } + + void HeapRegion::initialize(MemRegion mr, bool clear_space, bool mangle_space) { ++ _humongous_start_region = NULL; ++ _in_collection_set = false; ++ _next_in_special_set = NULL; ++ _orig_end = NULL; ++ _claimed = InitialClaimValue; ++ _evacuation_failed = false; ++ _prev_marked_bytes = 0; ++ _next_marked_bytes = 0; ++ _gc_efficiency = 0.0; ++ _next_young_region = NULL; ++ _next_dirty_cards_region = NULL; ++ _next = NULL; ++ _prev = NULL; ++#ifdef ASSERT ++ _containing_set = NULL; ++#endif // ASSERT ++ _in_uncommit_list = false; ++ _young_index_in_cset = -1; ++ _surv_rate_group = NULL; ++ _age_index = -1; ++ _recorded_rs_length = 0; ++ _predicted_elapsed_time_ms = 0; ++ _predicted_bytes_to_copy = 0; + assert(_rem_set->is_empty(), "Remembered set must be empty"); + + G1OffsetTableContigSpace::initialize(mr, clear_space, mangle_space); +@@ -1161,6 +1184,7 @@ G1OffsetTableContigSpace(G1BlockOffsetSharedArray* sharedOffsetArray, + + void G1OffsetTableContigSpace::initialize(MemRegion mr, bool clear_space, bool mangle_space) { + CompactibleSpace::initialize(mr, clear_space, mangle_space); ++ _gc_time_stamp = 0; + _top = bottom(); + _scan_top = bottom(); + set_saved_mark_word(NULL); +-- +2.19.0 + diff --git a/initialized-value-should-be-0-in-perfInit.patch b/initialized-value-should-be-0-in-perfInit.patch new file mode 100755 index 0000000000000000000000000000000000000000..c3044705cbda4d7ff96be88b66e7d6105334424b --- /dev/null +++ b/initialized-value-should-be-0-in-perfInit.patch @@ -0,0 +1,29 @@ +From 00c58142616a05509f005a676f786edaad88bfb4 Mon Sep 17 00:00:00 2001 +Date: Thu, 24 Dec 2020 16:12:02 +0800 +Subject: initialized value should be 0 in perfInit() + +DTS/AR: AR.SR.IREQ02517150.001.001 +Summary: : +LLT: +Patch Type: huawei +Bug url: +--- + hotspot/src/os/linux/vm/process_load.hpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hotspot/src/os/linux/vm/process_load.hpp b/hotspot/src/os/linux/vm/process_load.hpp +index 83800b199..896754d5e 100644 +--- a/hotspot/src/os/linux/vm/process_load.hpp ++++ b/hotspot/src/os/linux/vm/process_load.hpp +@@ -197,7 +197,7 @@ static int get_jvmticks(ticks *pticks) { + * This method must be called first, before any data can be gathererd. + */ + int perfInit() { +- static int initialized=1; ++ static int initialized = 0; + + if (!initialized) { + int i; +-- +2.19.0 + diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index 13867bd870ca3ea8b9e57f0d4df4c7759edde65f..33df699c1eed826be747d24b8334505ec2705c9f 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -587,6 +587,9 @@ exit 0 %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libnet.so %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libnio.so %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libnpt.so +%ifarch %{aarch64} +%{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libj2kae.so +%endif %ifarch %{sa_arches} %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libsaproc.so %endif @@ -628,6 +631,9 @@ exit 0 %{_jvmdir}/%{jredir -- %{?1}}/lib/ext/sunjce_provider.jar %{_jvmdir}/%{jredir -- %{?1}}/lib/ext/sunpkcs11.jar %{_jvmdir}/%{jredir -- %{?1}}/lib/ext/zipfs.jar +%ifarch %{aarch64} +%{_jvmdir}/%{jredir -- %{?1}}/lib/ext/kae_openssl.jar +%endif %ifarch %{jfr_arches} %{_jvmdir}/%{jredir -- %{?1}}/lib/jfr.jar %{_jvmdir}/%{jredir -- %{?1}}/lib/jfr/default.jfc @@ -915,7 +921,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 3 +Release: 8 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1070,6 +1076,19 @@ Patch146: 8168926.patch Patch147: 8215047.patch Patch148: 8237894.patch Patch149: Remove-the-parentheses-around-company-name.patch +Patch150: 8240353.patch +Patch151: kae-phase1.patch +Patch152: 8231841-debug.cpp-help-is-missing-an-AArch64-line-fo.patch +Patch153: initialized-value-should-be-0-in-perfInit.patch +Patch154: 8254078-DataOutputStream-is-very-slow-post-disabling.patch +Patch155: Use-atomic-operation-when-G1Uncommit.patch +Patch156: 8168996-backport-of-C2-crash-at-postaloc.cpp-140-ass.patch +Patch157: 8140597-Postpone-the-initial-mark-request-until-the-.patch +Patch158: Use-Mutex-when-G1Uncommit.patch +Patch159: C1-typos-repair.patch +Patch160: 8214418-half-closed-SSLEngine-status-may-cause-appli.patch +Patch161: 8259886-Improve-SSL-session-cache-performance-and-sc.patch +Patch162: 8214535-support-Jmap-parallel.patch ############################################# # @@ -1153,6 +1172,7 @@ BuildRequires: pkgconfig BuildRequires: xorg-x11-proto-devel BuildRequires: zip BuildRequires: unzip +BuildRequires: openssl-devel BuildRequires: java-1.8.0-openjdk-devel @@ -1493,6 +1513,19 @@ pushd %{top_level_dir_name} %patch147 -p1 %patch148 -p1 %patch149 -p1 +%patch150 -p1 +%patch151 -p1 +%patch152 -p1 +%patch153 -p1 +%patch154 -p1 +%patch155 -p1 +%patch156 -p1 +%patch157 -p1 +%patch158 -p1 +%patch159 -p1 +%patch160 -p1 +%patch161 -p1 +%patch162 -p1 popd @@ -2109,6 +2142,30 @@ require "copy_jdk_configs.lua" %endif %changelog +* Fri Mar 19 2021 kuenking111 - 1:1.8.0.282-b08.8 +- add 8214535-support-Jmap-parallel.patch + +* Fri Mar 19 2021 DataAndOperation - 1:1.8.0.282-b08.7 +- add 8231841-debug.cpp-help-is-missing-an-AArch64-line-fo.patch +- add initialized-value-should-be-0-in-perfInit.patch +- add 8254078-DataOutputStream-is-very-slow-post-disabling.patch +- add Use-atomic-operation-when-G1Uncommit.patch +- add 8168996-backport-of-C2-crash-at-postaloc.cpp-140-ass.patch +- add 8140597-Postpone-the-initial-mark-request-until-the-.patch +- add Use-Mutex-when-G1Uncommit.patch +- add C1-typos-repair.patch +- add 8214418-half-closed-SSLEngine-status-may-cause-appli.patch +- add 8259886-Improve-SSL-session-cache-performance-and-sc.patch + +* Wed Mar 17 2021 noah - 1:1.8.0.282-b08.6 +- add kae-phase1.patch + +* Fri Feb 5 2021 noah - 1:1.8.0.282-b08.5 +- delete some file header + +* Thu Feb 4 2021 jdkboy - 1:1.8.0.282-b08.4 +- add 8240353.patch + * Thu Feb 4 2021 jdkboy - 1:1.8.0.282-b08.3 - fix wrong patch G1-memory-uncommit.patch diff --git a/kae-phase1.patch b/kae-phase1.patch new file mode 100644 index 0000000000000000000000000000000000000000..bc0f6efd096cdc8f5f4009b46387d943d6c3e356 --- /dev/null +++ b/kae-phase1.patch @@ -0,0 +1,5496 @@ +From 4993e7a69c88f01dc8c858cfa429c3904a632462 Mon Sep 17 00:00:00 2001 +Date: Tue, 16 Mar 2021 06:03:50 +0000 +Subject: [PATCH 3/3] add kae feature + +--- + common/autoconf/generated-configure.sh | 28 + + common/autoconf/jdk-options.m4 | 14 + + common/autoconf/spec.gmk.in | 1 + + jdk/make/CompileJavaClasses.gmk | 28 +- + jdk/make/CreateJars.gmk | 1 + + jdk/make/CreateSecurityJars.gmk | 29 + + jdk/make/SignJars.gmk | 6 + + jdk/make/lib/SecurityLibraries.gmk | 25 + + jdk/make/mapfiles/libj2kae/mapfile-vers | 57 ++ + jdk/make/profile-includes.txt | 12 + + .../security/openssl/KAEAESCipher.java | 725 ++++++++++++++++ + .../openeuler/security/openssl/KAEDigest.java | 264 ++++++ + .../openeuler/security/openssl/KAEMac.java | 228 +++++ + .../security/openssl/KAEProvider.java | 180 ++++ + .../security/openssl/KAERSACipher.java | 796 ++++++++++++++++++ + .../openssl/KAERSAKeyPairGenerator.java | 164 ++++ + .../security/openssl/KAERSAPaddingType.java | 80 ++ + .../openeuler/security/openssl/KAEUtils.java | 196 +++++ + .../security/openssl/kae_cipher_aes.c | 255 ++++++ + .../security/openssl/kae_cipher_rsa.c | 463 ++++++++++ + .../openeuler/security/openssl/kae_digest.c | 227 +++++ + .../security/openssl/kae_exception.c | 116 +++ + .../security/openssl/kae_exception.h | 52 ++ + .../openssl/kae_keypairgenerator_rsa.c | 173 ++++ + .../org/openeuler/security/openssl/kae_log.h | 33 + + .../org/openeuler/security/openssl/kae_mac.c | 201 +++++ + .../openeuler/security/openssl/kae_provider.c | 47 ++ + .../org/openeuler/security/openssl/kae_util.c | 102 +++ + .../org/openeuler/security/openssl/kae_util.h | 39 + + jdk/test/java/net/URLPermission/policy.1 | 1 + + jdk/test/java/net/URLPermission/policy.2 | 1 + + jdk/test/java/net/URLPermission/policy.3 | 1 + + .../bench/security/openssl/AESBenchmark.java | 108 +++ + .../bench/security/openssl/BenchmarkBase.java | 100 +++ + .../security/openssl/DigestBenchmark.java | 69 ++ + .../bench/security/openssl/HMacBenchmark.java | 73 ++ + .../security/openssl/RSACipherBenchmark.java | 107 +++ + .../openssl/RSAKeyPairGeneratorBenchmark.java | 63 ++ + .../sun/security/krb5/auto/BasicProc.java | 4 +- + 39 files changed, 5066 insertions(+), 3 deletions(-) + create mode 100644 jdk/make/mapfiles/libj2kae/mapfile-vers + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEAESCipher.java + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEMac.java + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSACipher.java + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAPaddingType.java + create mode 100644 jdk/src/solaris/classes/org/openeuler/security/openssl/KAEUtils.java + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_aes.c + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.c + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.h + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_log.h + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_mac.c + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c + create mode 100644 jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h + create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java + create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java + create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java + create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java + create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java + create mode 100644 jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java + +diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh +index d754f1d6..ea43a7a0 100644 +--- a/common/autoconf/generated-configure.sh ++++ b/common/autoconf/generated-configure.sh +@@ -845,6 +845,7 @@ JDK_MINOR_VERSION + JDK_MAJOR_VERSION + USER_RELEASE_SUFFIX + ENABLE_JFR ++ENABLE_KAE + COMPRESS_JARS + UNLIMITED_CRYPTO + CACERTS_FILE +@@ -1060,6 +1061,7 @@ enable_hotspot_test_in_build + with_cacerts_file + enable_unlimited_crypto + enable_jfr ++enable_kae + with_milestone + with_update_version + with_user_release_suffix +@@ -1847,6 +1849,7 @@ Optional Features: + --enable-unlimited-crypto + Enable unlimited crypto policy [disabled] + --disable-jfr Disable Java Flight Recorder support [enabled] ++ --disable-kae Disable KAE support on aarch64 [enabled] + --disable-debug-symbols disable generation of debug symbols [enabled] + --disable-zip-debug-info + disable zipping of debug-info files [enabled] +@@ -19843,6 +19846,31 @@ fi + $as_echo "$ENABLE_JFR" >&6; } + + ++ ############################################################################### ++ # ++ # Enable or disable KAE ++ # ++ # Check whether --enable-kae was given. ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build KAE" >&5 ++$as_echo_n "checking whether to build KAE... " >&6; } ++if test "${enable_kae+set}" = set; then : ++ enableval=$enable_kae; enable_kae="${enableval}" ++else ++ #default enable on aarch64 ++ if test "x$OPENJDK_TARGET_CPU" = xaarch64; then ++ enable_kae="yes" ++ else ++ enable_kae="no" ++ fi ++fi ++ ++ if test "x$enable_kae" = "xyes"; then ++ ENABLE_KAE=true ++ elif test "x$enable_kae" = "xno"; then ++ ENABLE_KAE=false ++ fi ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_KAE" >&5 ++$as_echo "$ENABLE_KAE" >&6; } + + # Source the version numbers + . $AUTOCONF_DIR/version-numbers +diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 +index e4eb2352..23db9275 100644 +--- a/common/autoconf/jdk-options.m4 ++++ b/common/autoconf/jdk-options.m4 +@@ -461,6 +461,20 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], + fi + AC_MSG_RESULT([$ENABLE_JFR]) + AC_SUBST(ENABLE_JFR) ++ ++ ############################################################################### ++ # ++ # Enable or disable kae ++ # ++ AC_ARG_ENABLE(kae, [AS_HELP_STRING([--disable-kae], ++ [disable KAE @<:@disabled@:>@])],, ++ [enable_kae=no]) ++ if test "x$enable_kae" = "xyes"; then ++ ENABLE_KAE=true ++ else ++ ENABLE_KAE=false ++ fi ++ AC_SUBST(ENABLE_KAE) + ]) + + ############################################################################### +diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in +index 506cf617..4c3a9f61 100644 +--- a/common/autoconf/spec.gmk.in ++++ b/common/autoconf/spec.gmk.in +@@ -602,6 +602,7 @@ endif + + # Build setup + ENABLE_JFR=@ENABLE_JFR@ ++ENABLE_KAE=@ENABLE_KAE@ + ENABLE_INTREE_EC=@ENABLE_INTREE_EC@ + USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@ + USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@ +diff --git a/jdk/make/CompileJavaClasses.gmk b/jdk/make/CompileJavaClasses.gmk +index 3ec63e87..b0ae8e97 100644 +--- a/jdk/make/CompileJavaClasses.gmk ++++ b/jdk/make/CompileJavaClasses.gmk +@@ -284,6 +284,7 @@ endif + # The security classes should not end up in the classes directory as that will prevent them + # from working when running the exploded jdk image. Compile them separately to a different + # directory from where the jars can be created. ++ + SECURITY_PKGS := \ + com/oracle/security/ucrypto \ + com/sun/crypto/provider \ +@@ -294,6 +295,9 @@ SECURITY_PKGS := \ + sun/security/pkcs11 \ + # + ++# KAE classes ++KAE_PKG := org/openeuler/security/openssl ++ + AIX_SRC_DIRS := + ifeq ($(OPENJDK_TARGET_OS),aix) + AIX_SRC_DIRS += $(JDK_TOPDIR)/src/aix/classes +@@ -339,7 +343,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JDK,\ + $(JDK_OUTPUTDIR)/gensrc_no_srczip \ + $(CLOSED_SRC_DIRS),\ + INCLUDES:=$(JDK_USER_DEFINED_FILTER),\ +- EXCLUDES:=$(EXCLUDES) $(SECURITY_PKGS),\ ++ EXCLUDES:=$(EXCLUDES) $(SECURITY_PKGS) $(KAE_PKG),\ + EXCLUDE_FILES:=$(EXFILES),\ + BIN:=$(JDK_OUTPUTDIR)/classes,\ + COPY:=$(COPY_PATTERNS),\ +@@ -363,6 +367,26 @@ $(eval $(call SetupJavaCompilation,BUILD_SECURITY, \ + + $(BUILD_SECURITY): $(BUILD_JDK) + ++ ++########################################################################################## ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ $(eval $(call SetupJavaCompilation,BUILD_KAE, \ ++ SETUP := GENERATE_JDKBYTECODE, \ ++ SRC := $(JDK_TOPDIR)/src/share/classes \ ++ $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes \ ++ $(MACOSX_SRC_DIRS) \ ++ $(CLOSED_SRC_DIRS), \ ++ INCLUDES := $(KAE_PKG), \ ++ EXCLUDES := $(EXCLUDES), \ ++ EXCLUDE_FILES := $(EXFILES), \ ++ BIN := $(JDK_OUTPUTDIR)/classes_kae, \ ++ HEADERS := $(JDK_OUTPUTDIR)/gensrc_headers)) ++ ++ $(BUILD_KAE): $(BUILD_JDK) ++ endif ++endif ++ + ########################################################################################## + + $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin: +@@ -410,7 +434,7 @@ $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin: + + ########################################################################################## + +-all: $(BUILD_JDK) $(BUILD_SECURITY) $(COPY_EXTRA) \ ++all: $(BUILD_JDK) $(BUILD_SECURITY) $(BUILD_KAE) $(COPY_EXTRA) \ + $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin \ + $(BUILD_ACCESSBRIDGE_32) $(BUILD_ACCESSBRIDGE_64) \ + $(BUILD_ACCESSBRIDGE_LEGACY) +diff --git a/jdk/make/CreateJars.gmk b/jdk/make/CreateJars.gmk +index 559a62b6..cb3f26b3 100644 +--- a/jdk/make/CreateJars.gmk ++++ b/jdk/make/CreateJars.gmk +@@ -168,6 +168,7 @@ RT_JAR_EXCLUDES += \ + META-INF/services/com.sun.tools.attach.spi.AttachProvider \ + META-INF/services/com.sun.tools.xjc.Plugin \ + META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor \ ++ org/openeuler/security \ + org/relaxng/datatype \ + sun/awt/HKSCS.class \ + sun/awt/motif/X11GB2312.class \ +diff --git a/jdk/make/CreateSecurityJars.gmk b/jdk/make/CreateSecurityJars.gmk +index da9cc207..e991d994 100644 +--- a/jdk/make/CreateSecurityJars.gmk ++++ b/jdk/make/CreateSecurityJars.gmk +@@ -371,6 +371,35 @@ ifeq ($(OPENJDK_TARGET_OS), solaris) + + endif + endif ++########################################################################################## ++ ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ KAE_JAR_DST := $(JDK_OUTPUTDIR)/lib/ext/kae_openssl.jar ++ KAE_JAR_UNSIGNED := $(JDK_OUTPUTDIR)/jce/unsigned/kae_openssl.jar ++ ++ $(eval $(call SetupArchive,BUILD_OPENSSL_JAR, , \ ++ SRCS := $(JDK_OUTPUTDIR)/classes_kae, \ ++ SUFFIXES := .class, \ ++ INCLUDES := org/openeuler/security/openssl, \ ++ JAR := $(KAE_JAR_UNSIGNED), \ ++ MANIFEST := $(JCE_MANIFEST), \ ++ SKIP_METAINF := true)) ++ $(KAE_JAR_UNSIGNED): $(JCE_MANIFEST) ++ ifndef OPENJDK ++ KAE_JAR_SRC := $(JDK_TOPDIR)/make/closed/tools/crypto/openssl/kae_openssl.jar ++ $(KAE_JAR_DST): $(KAE_JAR_SRC) ++ @$(ECHO) $(LOG_INFO) Copying prebuilt $(@F) ++ $(install-file) ++ else ++ $(KAE_JAR_DST): $(KAE_JAR_UNSIGNED) ++ $(install-file) ++ endif ++ ++ TARGETS += $(KAE_JAR_UNSIGNED) $(KAE_JAR_DST) ++ ++ endif ++endif + + all: $(TARGETS) + +diff --git a/jdk/make/SignJars.gmk b/jdk/make/SignJars.gmk +index 21647889..babd8684 100644 +--- a/jdk/make/SignJars.gmk ++++ b/jdk/make/SignJars.gmk +@@ -99,6 +99,12 @@ JAR_LIST := \ + ucrypto.jar \ + # + ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ JAR_LIST += kae_openssl.jar ++ endif ++endif ++ + UNSIGNED_JARS := $(wildcard $(addprefix $(JDK_OUTPUTDIR)/jce/unsigned/, $(JAR_LIST))) + + ifeq ($(UNSIGNED_JARS), ) +diff --git a/jdk/make/lib/SecurityLibraries.gmk b/jdk/make/lib/SecurityLibraries.gmk +index a8eeceb3..62226836 100644 +--- a/jdk/make/lib/SecurityLibraries.gmk ++++ b/jdk/make/lib/SecurityLibraries.gmk +@@ -287,3 +287,28 @@ ifeq ($(OPENJDK_TARGET_OS), solaris) + + endif + endif ++########################################################################################## ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ $(eval $(call SetupNativeCompilation,BUILD_LIBJ2KAE, \ ++ LIBRARY := j2kae, \ ++ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ ++ SRC := $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/org/openeuler/security/openssl, \ ++ LANG := C, \ ++ OPTIMIZATION := LOW, \ ++ EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/os_cpu/linux_x86/vm/memcpy.cpp, \ ++ CFLAGS := $(CFLAGS_JDKLIB) \ ++ -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/org/openeuler/security/openssl, \ ++ MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libj2kae/mapfile-vers, \ ++ LDFLAGS := $(LDFLAGS_JDKLIB) \ ++ $(call SET_SHARED_LIBRARY_ORIGIN), \ ++ LDFLAGS_SUFFIX_linux := $(LIBDL) -lssl -lcrypto, \ ++ LDFLAGS_SUFFIX_posix := $(LIBDL), \ ++ LDFLAGS_SUFFIX_solaris := -lc, \ ++ VERSIONINFO_RESOURCE := $(JDK_TOPDIR)/src/windows/resource/version.rc, \ ++ OBJECT_DIR := $(JDK_OUTPUTDIR)/objs/libj2kae, \ ++ DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES))) ++ ++ BUILD_LIBRARIES += $(BUILD_LIBJ2KAE) ++ endif ++endif +diff --git a/jdk/make/mapfiles/libj2kae/mapfile-vers b/jdk/make/mapfiles/libj2kae/mapfile-vers +new file mode 100644 +index 00000000..6ed331b2 +--- /dev/null ++++ b/jdk/make/mapfiles/libj2kae/mapfile-vers +@@ -0,0 +1,57 @@ ++# ++# Copyright (c) 2020, Huawei Technologies Co., Ltd. All rights reserved. ++# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++# ++# This code is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License version 2 only, as ++# published by the Free Software Foundation. ++# ++# This code is distributed in the hope that it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++# version 2 for more details (a copy is included in the LICENSE file that ++# accompanied this code). ++# ++# You should have received a copy of the GNU General Public License version ++# 2 along with this work; if not, write to the Free Software Foundation, ++# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++# or visit www.oracle.com if you need additional information or have any ++# questions. ++# ++ ++# Define public interface. ++ ++SUNWprivate_1.1 { ++ global: ++ JNI_OnLoad; ++ Java_org_openeuler_security_openssl_KAEProvider_initOpenssl; ++ Java_org_openeuler_security_openssl_KAEDigest_nativeInit; ++ Java_org_openeuler_security_openssl_KAEDigest_nativeUpdate; ++ Java_org_openeuler_security_openssl_KAEDigest_nativeDigest; ++ Java_org_openeuler_security_openssl_KAEDigest_nativeClone; ++ Java_org_openeuler_security_openssl_KAEDigest_nativeFree; ++ Java_org_openeuler_security_openssl_KAEAESCipher_nativeInit; ++ Java_org_openeuler_security_openssl_KAEAESCipher_nativeUpdate; ++ Java_org_openeuler_security_openssl_KAEAESCipher_nativeFinal; ++ Java_org_openeuler_security_openssl_KAEAESCipher_nativeFree; ++ Java_org_openeuler_security_openssl_KAEMac_nativeInit; ++ Java_org_openeuler_security_openssl_KAEMac_nativeUpdate; ++ Java_org_openeuler_security_openssl_KAEMac_nativeFinal; ++ Java_org_openeuler_security_openssl_KAEMac_nativeFree; ++ Java_org_openeuler_security_openssl_KAERSAKeyPairGenerator_nativeGenerateKeyPair; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPrivateCrtKey; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPrivateKey; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPublicKey; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateEncrypt; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateDecrypt; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicEncrypt; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicDecrypt; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAEncryptOAEPPadding; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeRSADecryptOAEPPadding; ++ Java_org_openeuler_security_openssl_KAERSACipher_nativeFreeKey; ++ ++ local: ++ *; ++}; +diff --git a/jdk/make/profile-includes.txt b/jdk/make/profile-includes.txt +index 68bb27e5..013c426c 100644 +--- a/jdk/make/profile-includes.txt ++++ b/jdk/make/profile-includes.txt +@@ -195,6 +195,12 @@ PROFILE_1_JRE_LIB_FILES += \ + security/trusted.libraries \ + tzdb.dat + ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ PROFILE_1_JRE_LIB_FILES += ext/kae_openssl.jar ++ endif ++endif ++ + ifeq ($(OPENJDK_TARGET_OS), windows) + PROFILE_1_JRE_LIB_FILES += tzmappings + else +@@ -225,6 +231,12 @@ PROFILE_1_JRE_JAR_FILES := \ + security/policy/limited/local_policy.jar \ + security/policy/unlimited/local_policy.jar + ++ifeq ($(ENABLE_KAE), true) ++ ifeq ($(OPENJDK_TARGET_CPU_ARCH), aarch64) ++ PROFILE_1_JRE_JAR_FILES += ext/kae_openssl.jar ++ endif ++endif ++ + + PROFILE_2_JRE_BIN_FILES := \ + rmid$(EXE_SUFFIX) \ +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEAESCipher.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEAESCipher.java +new file mode 100644 +index 00000000..2dd5bf4a +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEAESCipher.java +@@ -0,0 +1,725 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.jca.JCAUtil; ++ ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.security.*; ++import java.security.spec.*; ++import java.util.Arrays; ++import java.util.Locale; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++import javax.crypto.*; ++import javax.crypto.spec.IvParameterSpec; ++import javax.crypto.spec.SecretKeySpec; ++ ++/* ++ * Cipher wrapper class utilizing openssl APIs. This class currently supports ++ * - AES/ECB/NOPADDING ++ * - AES/ECB/PKCS5PADDING ++ * - AES/CBC/NOPADDING ++ * - AES/CBC/PKCS5PADDING ++ * - AES/CTR/NOPADDING ++ */ ++abstract class KAEAESCipher extends CipherSpi { ++ ++ public static class Aes extends KAEAESCipher { ++ public Aes(Mode mode, Padding padding) { ++ super(mode, padding, -1); ++ } ++ ++ public static class Cbc extends Aes { ++ public Cbc(Padding padding) { ++ super(Mode.CBC, padding); ++ } ++ public static class NoPadding extends Cbc { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Cbc { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ public static class Ecb extends Aes { ++ public Ecb(Padding padding) { ++ super(Mode.ECB, padding); ++ } ++ public static class NoPadding extends Ecb { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Ecb { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ ++ public static class Ctr extends Aes { ++ public Ctr(Padding padding) { ++ super(Mode.CTR, padding); ++ } ++ public static class NoPadding extends Ctr { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ } ++ } ++ ++ public static class Aes_128 extends KAEAESCipher { ++ public Aes_128(Mode mode, Padding padding) { ++ super(mode, padding, 16); ++ } ++ public static class Cbc extends Aes_128 { ++ public Cbc(Padding padding) { ++ super(Mode.CBC, padding); ++ } ++ public static class NoPadding extends Cbc { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Cbc { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ public static class Ecb extends Aes_128 { ++ public Ecb(Padding padding) { ++ super(Mode.ECB, padding); ++ } ++ public static class NoPadding extends Ecb { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Ecb { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ ++ public static class Ctr extends Aes_128 { ++ public Ctr(Padding padding) { ++ super(Mode.CTR, padding); ++ } ++ public static class NoPadding extends Ctr { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ } ++ } ++ ++ public static class Aes_192 extends KAEAESCipher { ++ public Aes_192(Mode mode, Padding padding) { ++ super(mode, padding, 24); ++ } ++ public static class Cbc extends Aes_192 { ++ public Cbc(Padding padding) { ++ super(Mode.CBC, padding); ++ } ++ public static class NoPadding extends Cbc { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Cbc { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ public static class Ecb extends Aes_192 { ++ public Ecb(Padding padding) { ++ super(Mode.ECB, padding); ++ } ++ public static class NoPadding extends Ecb { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Ecb { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ ++ public static class Ctr extends Aes_192 { ++ public Ctr(Padding padding) { ++ super(Mode.CTR, padding); ++ } ++ public static class NoPadding extends Ctr { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ } ++ } ++ ++ public static class Aes_256 extends KAEAESCipher { ++ public Aes_256(Mode mode, Padding padding) { ++ super(mode, padding, 32); ++ } ++ public static class Cbc extends Aes_256 { ++ public Cbc(Padding padding) { ++ super(Mode.CBC, padding); ++ } ++ public static class NoPadding extends Cbc { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Cbc { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ public static class Ecb extends Aes_256 { ++ public Ecb(Padding padding) { ++ super(Mode.ECB, padding); ++ } ++ public static class NoPadding extends Ecb { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ public static class PKCS5Padding extends Ecb { ++ public PKCS5Padding() { ++ super(Padding.PKCS5PADDING); ++ } ++ } ++ } ++ ++ public static class Ctr extends Aes_256 { ++ public Ctr(Padding padding) { ++ super(Mode.CTR, padding); ++ } ++ public static class NoPadding extends Ctr { ++ public NoPadding() { ++ super(Padding.NOPADDING); ++ } ++ } ++ } ++ } ++ ++ enum Padding { ++ NOPADDING, ++ PKCS5PADDING ++ } ++ ++ enum Mode { ++ ECB, ++ CBC, ++ CTR, ++ } ++ ++ private final String keyAlgo = "AES"; ++ private final int blockSize = 16; ++ private Mode mode; ++ private Padding padding; ++ private int fixedKeySize; ++ ++ private CipherContextRef pCtx = null; ++ private byte[] keyValue; ++ protected byte[] iv; ++ private boolean initialized = false; ++ private boolean encrypt = false; ++ private int bytesBuffered = 0; ++ ++ private boolean calledUpdate; ++ private String cipherName; ++ ++ private static final PublicKey constructPublicKey(byte[] encodedKey, String encodedKeyAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException { ++ PublicKey key; ++ try { ++ KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm); ++ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); ++ key = keyFactory.generatePublic(keySpec); ++ } catch (NoSuchAlgorithmException e) { ++ throw new NoSuchAlgorithmException("No provider found for " + encodedKeyAlgorithm + " KeyFactory"); ++ } catch (InvalidKeySpecException e) { ++ throw new InvalidKeyException("Cannot construct public key", e); ++ } ++ return key; ++ } ++ ++ private static final PrivateKey constructPrivateKey(byte[] encodedKey, ++ String encodedKeyAlgorithm) throws InvalidKeyException, NoSuchAlgorithmException { ++ PrivateKey key = null; ++ try { ++ KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm); ++ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); ++ key = keyFactory.generatePrivate(keySpec); ++ } catch (NoSuchAlgorithmException e) { ++ throw new NoSuchAlgorithmException("No provider found for " + encodedKeyAlgorithm + " KeyFactory"); ++ } catch (InvalidKeySpecException e) { ++ throw new InvalidKeyException("Cannot construct private key", e); ++ } ++ return key; ++ } ++ ++ private static final SecretKey constructSecretKey(byte[] encodedKey, String encodedKeyAlgorithm) { ++ return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); ++ } ++ ++ static final Key constructKey(int keyType, byte[] encodedKey, ++ String encodedKeyAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException { ++ Key res = null; ++ switch (keyType) { ++ case Cipher.SECRET_KEY: ++ res = constructSecretKey(encodedKey, encodedKeyAlgorithm); ++ break; ++ case Cipher.PRIVATE_KEY: ++ res = constructPrivateKey(encodedKey, encodedKeyAlgorithm); ++ break; ++ case Cipher.PUBLIC_KEY: ++ res = constructPublicKey(encodedKey, encodedKeyAlgorithm); ++ break; ++ default: ++ throw new InvalidKeyException("Unknown keytype " + keyType); ++ } ++ return res; ++ } ++ ++ KAEAESCipher(Mode mode, Padding padding, int fixedKeySize) { ++ this.mode = mode; ++ this.padding = padding; ++ this.fixedKeySize = fixedKeySize; ++ } ++ ++ private static class CipherContextRef extends PhantomReference implements Comparable { ++ ++ private static ReferenceQueue refQueue = new ReferenceQueue<>(); ++ private static Set refList = new ConcurrentSkipListSet<>(); ++ private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); ++ ++ final long ctxAddress; ++ ++ private static void drainRefQueueBounded() { ++ while (true) { ++ CipherContextRef next = (CipherContextRef) refQueue.poll(); ++ if (next == null) { ++ break; ++ } ++ next.dispose(true); ++ } ++ } ++ ++ CipherContextRef(KAEAESCipher kaeCipher, long ctxAddress) { ++ super(kaeCipher, refQueue); ++ this.ctxAddress = ctxAddress; ++ if (!disableKaeDispose) { ++ refList.add(this); ++ drainRefQueueBounded(); ++ } ++ } ++ ++ @Override ++ public int compareTo(CipherContextRef o) { ++ if (this.ctxAddress == o.ctxAddress) { ++ return 0; ++ } else { ++ return (this.ctxAddress < o.ctxAddress) ? -1 : 1; ++ } ++ } ++ ++ void dispose(boolean needFree) { ++ if (!disableKaeDispose) { ++ refList.remove(this); ++ try { ++ if (needFree) { ++ nativeFree(ctxAddress); ++ } ++ } finally { ++ this.clear(); ++ } ++ } else { ++ nativeFree(ctxAddress); ++ } ++ } ++ } ++ ++ ++ @Override ++ protected void engineSetMode(String modeStr) throws NoSuchAlgorithmException { ++ if (modeStr == null) { ++ throw new NoSuchAlgorithmException("null mode"); ++ } ++ ++ if (modeStr.equalsIgnoreCase("ECB")) { ++ mode = Mode.ECB; ++ } else if (modeStr.equalsIgnoreCase("CBC")) { ++ mode = Mode.CBC; ++ } else if (modeStr.equalsIgnoreCase("CTR")) { ++ mode = Mode.CTR; ++ } else { ++ throw new NoSuchAlgorithmException("Unsupported mode " + mode); ++ } ++ ++ } ++ ++ @Override ++ protected void engineSetPadding(String paddingStr) throws NoSuchPaddingException { ++ if (paddingStr == null) { ++ throw new NoSuchPaddingException("null padding"); ++ } ++ ++ if (paddingStr.equalsIgnoreCase("NOPADDING")) { ++ this.padding = Padding.NOPADDING; ++ } else if(paddingStr.equalsIgnoreCase("PKCS5PADDING")) { ++ if (mode == Mode.CTR) { ++ throw new NoSuchPaddingException("PKCS#5 padding not supported with CTR mode"); ++ } ++ this.padding = Padding.PKCS5PADDING; ++ } else { ++ throw new NoSuchPaddingException("Unsupported padding "+padding); ++ } ++ } ++ ++ ++ @Override ++ protected int engineGetBlockSize() { ++ return blockSize; ++ } ++ ++ @Override ++ protected int engineGetOutputSize(int inputLen) { ++ return getOutputSizeByOperation(inputLen, true); ++ } ++ ++ @Override ++ protected byte[] engineGetIV() { ++ return iv == null ? null : iv.clone(); ++ } ++ ++ @Override ++ protected AlgorithmParameters engineGetParameters() { ++ if (iv == null) { ++ return null; ++ } ++ IvParameterSpec ivSpec = new IvParameterSpec(iv.clone()); ++ try { ++ AlgorithmParameters params = AlgorithmParameters.getInstance(keyAlgo); ++ params.init(ivSpec); ++ return params; ++ } catch (GeneralSecurityException e) { ++ throw new RuntimeException("Could not encode parameters", e); ++ } ++ } ++ ++ @Override ++ protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { ++ try { ++ engineInit(opmode, key, (AlgorithmParameterSpec) null, random); ++ } catch (InvalidAlgorithmParameterException e) { ++ throw new InvalidKeyException("init() failed", e); ++ } ++ } ++ ++ @Override ++ protected void engineInit(int opmode, Key key, AlgorithmParameters params, ++ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { ++ AlgorithmParameterSpec ivSpec = null; ++ if (params != null) { ++ try { ++ ivSpec = params.getParameterSpec(IvParameterSpec.class); ++ } catch (InvalidParameterSpecException e) { ++ throw new InvalidAlgorithmParameterException("Could not decode IV", e); ++ } ++ } ++ engineInit(opmode, key, ivSpec, random); ++ } ++ ++ @Override ++ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, ++ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { ++ checkKey(key); ++ boolean doEncrypt = (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE); ++ ++ byte[] ivBytes = null; ++ ++ if (params != null) { ++ if (!(params instanceof IvParameterSpec)) { ++ throw new InvalidKeyException("IvParameterSpec required. Received: " + params.getClass().getName()); ++ } else { ++ ivBytes = ((IvParameterSpec) params).getIV(); ++ if (ivBytes.length != blockSize) { ++ throw new InvalidAlgorithmParameterException("Wrong IV length: must be " + blockSize + ++ " bytes long. Received length:" + ivBytes.length); ++ } ++ } ++ } ++ if (mode == Mode.ECB) { ++ if (params != null) { ++ throw new InvalidAlgorithmParameterException("No Parameters for ECB mode"); ++ } ++ } else if (ivBytes == null) { ++ if (doEncrypt) { ++ ivBytes = new byte[blockSize]; ++ if (random == null) { ++ random = JCAUtil.getSecureRandom(); ++ } ++ random.nextBytes(ivBytes); ++ } else { ++ throw new InvalidAlgorithmParameterException("Parameters required for decryption"); ++ } ++ } ++ implInit(doEncrypt, key.getEncoded(), ivBytes); ++ } ++ ++ private void implInit(boolean encrypt, byte[] keyVal, byte[] ivVal) { ++ ++ reset(true); ++ this.encrypt = encrypt; ++ this.keyValue = keyVal; ++ this.iv = ivVal; ++ this.cipherName = "aes-" + (keyVal.length * 8) + "-" + mode.toString().toLowerCase(Locale.US); ++ ++ // OpenSSL only supports PKCS5 Padding ++ long pCtxVal; ++ try { ++ pCtxVal = nativeInit(cipherName, encrypt, keyValue, iv, padding == Padding.PKCS5PADDING); ++ } catch (RuntimeException e) { ++ throw new ProviderException("Invoke nativeInit failed for " + cipherName, e); ++ } ++ ++ initialized = (pCtxVal != 0L); ++ if (initialized) { ++ pCtx = new CipherContextRef(this, pCtxVal); ++ } else { ++ throw new NullPointerException("pCtxVal == 0"); ++ } ++ calledUpdate = false; ++ } ++ ++ final int checkKey(Key key) throws InvalidKeyException { ++ if (key == null || key.getEncoded() == null) { ++ throw new InvalidKeyException("Key cannot be null"); ++ } else { ++ if (!keyAlgo.equalsIgnoreCase(key.getAlgorithm())) { ++ throw new InvalidKeyException("Key algorithm must be " + keyAlgo); ++ } ++ int keyLen = key.getEncoded().length; ++ if (fixedKeySize == -1) { ++ if (keyLen != 16 && keyLen != 24 & keyLen != 32) { ++ throw new InvalidKeyException("Key size is not valid. Got key length of: " + keyLen); ++ } ++ } else { ++ if (keyLen != fixedKeySize) { ++ throw new InvalidKeyException("Only " + fixedKeySize + "-byte keys are accepted. Got: " + keyLen); ++ } ++ } ++ return keyLen; ++ } ++ } ++ ++ @Override ++ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { ++ byte[] out = new byte[getOutputSizeByOperation(inputLen, false)]; ++ int n = implUpdate(input, inputOffset, inputLen, out, 0); ++ if (n == 0) { ++ return new byte[0]; ++ } else if (out.length != n) { ++ out = Arrays.copyOf(out, n); ++ } ++ return out; ++ } ++ ++ @Override ++ protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, ++ int outputOffset) throws ShortBufferException { ++ int min = getOutputSizeByOperation(inputLen, false); ++ if (output.length - outputOffset < min) { ++ throw new ShortBufferException("min" + min + "-byte buffer needed"); ++ } ++ return implUpdate(input, inputOffset, inputLen, output, outputOffset); ++ } ++ ++ private int implUpdate(byte[] in, int inOfs, int inLen, byte[] output, int outOfs) { ++ ensureInitialized(); ++ if (inLen <= 0) { ++ return 0; ++ } ++ int k; ++ try { ++ k = nativeUpdate(pCtx.ctxAddress, in, inOfs, inLen, output, outOfs); ++ } catch (ArrayIndexOutOfBoundsException e) { ++ reset(true); ++ throw new ProviderException("Invoke nativeUpdate failed for " + cipherName, e); ++ } ++ bytesBuffered += (inLen - k); ++ ++ calledUpdate = true; ++ return k; ++ } ++ ++ protected int getOutputSizeByOperation(int inLen, boolean isDoFinal) { ++ if (inLen <= 0) { ++ inLen = 0; ++ } ++ if (!isDoFinal && inLen == 0) { ++ return 0; ++ } ++ if (padding == Padding.NOPADDING) { ++ return inLen + bytesBuffered; ++ } else { ++ int len = inLen + bytesBuffered; ++ ++ /* ++ * The amount of data written may be anything from zero bytes to (inl + cipher_block_size - 1) for encrypt. ++ * Refer to {@link https://www.openssl.org/docs/man1.1.0/man3/EVP_CipherUpdate.html} for details. ++ */ ++ len += (len % blockSize != 0 || encrypt) ? blockSize : 0; ++ return len - (len % blockSize); ++ } ++ } ++ ++ @Override ++ protected byte[] engineDoFinal(byte[] input, int inputOffset, ++ int inputLen) throws IllegalBlockSizeException, BadPaddingException { ++ byte[] out = new byte[getOutputSizeByOperation(inputLen, true)]; ++ try { ++ int outLen = engineDoFinal(input, inputOffset, inputLen, out, 0); ++ if (out.length != outLen) { ++ out = Arrays.copyOf(out, outLen); ++ } ++ return out; ++ } catch (ShortBufferException e) { ++ throw new ProviderException(e); ++ } ++ } ++ ++ @Override ++ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, ++ int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { ++ int outLen = 0; ++ int min = getOutputSizeByOperation(inputLen, true); ++ if (output.length - outputOffset < min) { ++ throw new ShortBufferException("min" + min + "-byte buffer needed"); ++ } ++ if (inputLen > 0) { ++ outLen = implUpdate(input, inputOffset, inputLen, output, outputOffset); ++ outputOffset += outLen; ++ } ++ outLen += implDoFinal(output, outputOffset); ++ return outLen; ++ } ++ ++ @Override ++ protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { ++ byte[] res = null; ++ try { ++ byte[] encodedKey = key.getEncoded(); ++ if (encodedKey == null || encodedKey.length == 0) { ++ throw new InvalidKeyException("Cannot get an encoding of the key to be wrapped"); ++ } ++ res = engineDoFinal(encodedKey, 0, encodedKey.length); ++ } catch (BadPaddingException e) { ++ // Should never happen ++ } ++ return res; ++ } ++ ++ @Override ++ protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, ++ int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { ++ byte[] encodedKey; ++ try { ++ encodedKey = engineDoFinal(wrappedKey, 0, wrappedKey.length); ++ } catch (IllegalBlockSizeException | BadPaddingException e) { ++ throw (InvalidKeyException) (new InvalidKeyException()).initCause(e); ++ } ++ return constructKey(wrappedKeyType, encodedKey, wrappedKeyAlgorithm); ++ } ++ ++ private int implDoFinal(byte[] out, int outOfs) { ++ ++ if (!encrypt && !calledUpdate) { ++ return 0; ++ } ++ ensureInitialized(); ++ ++ int outLen; ++ try { ++ outLen = nativeFinal(pCtx.ctxAddress, out, outOfs); ++ } catch (ArrayIndexOutOfBoundsException | BadPaddingException e) { ++ throw new ProviderException("Invoke nativeFinal failed for " + cipherName, e); ++ } finally { ++ reset(true); ++ } ++ ++ return outLen; ++ } ++ ++ protected void reset(boolean doCancel) { ++ initialized = false; ++ bytesBuffered = 0; ++ calledUpdate = false; ++ if (pCtx != null) { ++ pCtx.dispose(doCancel); ++ pCtx = null; ++ } ++ } ++ ++ protected native static long nativeInit(String cipherType, boolean encrypt, byte[] key, byte[] iv, boolean padding) throws RuntimeException; ++ ++ protected native static int nativeUpdate(long pContext, byte[] in, int inOfs, int inLen, byte[] out, ++ int outOfs) throws ArrayIndexOutOfBoundsException; ++ ++ protected native static int nativeFinal(long pContext, byte[] out, ++ int outOfs) throws ArrayIndexOutOfBoundsException, BadPaddingException; ++ ++ protected native static void nativeFree(long pContext); ++ ++ protected void ensureInitialized() { ++ if (!initialized) { ++ reset(true); ++ long pCtxVal = nativeInit(cipherName, encrypt, keyValue, iv, padding == Padding.PKCS5PADDING); ++ initialized = (pCtxVal != 0L); ++ if (initialized) { ++ pCtx = new CipherContextRef(this, pCtxVal); ++ } else { ++ throw new RuntimeException("Cannot initialize Cipher"); ++ } ++ } ++ } ++} ++ +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java +new file mode 100644 +index 00000000..bb5c8681 +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEDigest.java +@@ -0,0 +1,264 @@ ++/* ++ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.security.DigestException; ++import java.security.MessageDigestSpi; ++import java.security.ProviderException; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++/** ++ * KAE Digest ++ */ ++abstract class KAEDigest extends MessageDigestSpi implements Cloneable { ++ ++ public static final class MD5 extends KAEDigest { ++ private static final long initContext = nativeInit("md5"); ++ ++ public MD5() { ++ super("md5", 16, initContext); ++ } ++ } ++ ++ public static final class SM3 extends KAEDigest { ++ private static final long initContext = nativeInit("sm3"); ++ ++ public SM3() { ++ super("sm3", 32, initContext); ++ } ++ } ++ ++ public static final class SHA256 extends KAEDigest { ++ private static final long initContext = nativeInit("sha256"); ++ ++ public SHA256() { ++ super("sha256", 32, initContext); ++ } ++ } ++ ++ public static final class SHA384 extends KAEDigest { ++ private static final long initContext = nativeInit("sha384"); ++ ++ public SHA384() { ++ super("sha384", 48, initContext); ++ } ++ } ++ ++ private final int digestLength; ++ ++ private final String algorithm; ++ private final long initContext; ++ ++ // field for ensuring native memory is freed ++ private DigestContextRef contextRef = null; ++ ++ KAEDigest(String algorithm, int digestLength, long initContext) { ++ this.algorithm = algorithm; ++ this.digestLength = digestLength; ++ this.initContext = initContext; ++ } ++ ++ private static class DigestContextRef extends PhantomReference ++ implements Comparable { ++ ++ private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static Set referenceList = new ConcurrentSkipListSet<>(); ++ private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); ++ ++ private final long ctxAddress; ++ ++ DigestContextRef(KAEDigest kaeDigest, long ctxAddress) { ++ super(kaeDigest, referenceQueue); ++ this.ctxAddress = ctxAddress; ++ if (!disableKaeDispose) { ++ referenceList.add(this); ++ drainRefQueueBounded(); ++ } ++ } ++ ++ @Override ++ public int compareTo(DigestContextRef other) { ++ if (this.ctxAddress == other.ctxAddress) { ++ return 0; ++ } else { ++ return (this.ctxAddress < other.ctxAddress) ? -1 : 1; ++ } ++ } ++ ++ private static void drainRefQueueBounded() { ++ while (true) { ++ DigestContextRef next = (DigestContextRef) referenceQueue.poll(); ++ if (next == null) { ++ break; ++ } ++ next.dispose(); ++ } ++ } ++ ++ void dispose() { ++ if (!disableKaeDispose) { ++ referenceList.remove(this); ++ try { ++ nativeFree(ctxAddress); ++ } finally { ++ this.clear(); ++ } ++ } else { ++ nativeFree(ctxAddress); ++ } ++ } ++ } ++ ++ // single byte update. See JCA doc. ++ @Override ++ protected synchronized void engineUpdate(byte input) { ++ byte[] oneByte = new byte[]{input}; ++ engineUpdate(oneByte, 0, 1); ++ } ++ ++ ++ // array update. See JCA doc. ++ @Override ++ protected synchronized void engineUpdate(byte[] input, int offset, int len) { ++ if (len == 0 || input == null) { ++ return; ++ } ++ if ((offset < 0) || (len < 0) || (offset > input.length - len)) { ++ throw new ArrayIndexOutOfBoundsException(); ++ } ++ if (contextRef == null) { ++ contextRef = createDigestContext(this); ++ } ++ ++ try { ++ nativeUpdate(contextRef.ctxAddress, input, offset, len); ++ } catch (Exception e) { ++ engineReset(); ++ throw new ProviderException("nativeUpdate failed for " + algorithm, e); ++ } ++ } ++ ++ ++ // return the digest. See JCA doc. ++ @Override ++ protected synchronized byte[] engineDigest() { ++ final byte[] output = new byte[digestLength]; ++ try { ++ engineDigest(output, 0, digestLength); ++ } catch (Exception e) { ++ throw new ProviderException("Internal error", e); ++ } ++ return output; ++ } ++ ++ // return the digest in the specified array. See JCA doc. ++ @Override ++ protected int engineDigest(byte[] output, int offset, int len) throws DigestException { ++ if (output == null) { ++ return 0; ++ } ++ if (len < digestLength) { ++ throw new DigestException("Length must be at least " ++ + digestLength + " for " + algorithm + " digests"); ++ } ++ if ((offset < 0) || (len < 0) || (offset > output.length - len)) { ++ throw new DigestException("Buffer too short to store digest"); ++ } ++ if (contextRef == null) { ++ contextRef = createDigestContext(this); ++ } ++ try { ++ nativeDigest(contextRef.ctxAddress, output, offset, digestLength); ++ } catch (Exception e) { ++ throw new ProviderException("Invoke nativeDigest failed for " + algorithm, e); ++ } finally { ++ engineReset(); ++ } ++ return digestLength; ++ } ++ ++ // reset this object. See JCA doc. ++ @Override ++ protected synchronized void engineReset() { ++ if (contextRef != null) { ++ contextRef.dispose(); ++ contextRef = null; ++ } ++ } ++ ++ // return digest length. See JCA doc. ++ @Override ++ protected int engineGetDigestLength() { ++ return digestLength; ++ } ++ ++ @Override ++ public synchronized Object clone() throws CloneNotSupportedException { ++ KAEDigest kaeDigest = (KAEDigest) super.clone(); ++ if (kaeDigest.contextRef != null && kaeDigest.contextRef.ctxAddress != 0) { ++ long addr; ++ try { ++ addr = nativeClone(kaeDigest.contextRef.ctxAddress); ++ } catch (Exception e) { ++ throw new ProviderException("Invoke nativeClone failed for " + algorithm, e); ++ } ++ kaeDigest.contextRef = new DigestContextRef(kaeDigest, addr); ++ } ++ return kaeDigest; ++ } ++ ++ private DigestContextRef createDigestContext(KAEDigest kaeDigest) { ++ long addr; ++ try { ++ addr = nativeClone(initContext); ++ } catch (Exception e) { ++ throw new ProviderException("Invoke nativeInit failed for " + algorithm, e); ++ } ++ if (addr == 0) { ++ throw new RuntimeException("Cannot initialize EVP_MD_CTX for " + algorithm); ++ } ++ return new DigestContextRef(kaeDigest, addr); ++ } ++ ++ // return pointer to the context ++ protected native static long nativeInit(String algorithmName); ++ ++ // update the input byte ++ protected native static void nativeUpdate(long ctxAddress, byte[] input, int offset, int inLen); ++ ++ // digest and store the digest message to output ++ protected native static int nativeDigest(long ctxAddress, byte[] output, int offset, int len); ++ ++ // digest clone ++ protected static native long nativeClone(long ctxAddress); ++ ++ // free the specified context ++ protected native static void nativeFree(long ctxAddress); ++} +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEMac.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEMac.java +new file mode 100644 +index 00000000..54c5cbdf +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEMac.java +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.MacSpi; ++import javax.crypto.SecretKey; ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.nio.ByteBuffer; ++import java.security.*; ++import java.security.spec.AlgorithmParameterSpec; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++public abstract class KAEMac extends MacSpi implements Cloneable { ++ ++ private final String algorithm; ++ ++ /** ++ * The secret key used in this keyed MAC. ++ */ ++ private byte[] keyBytes; ++ ++ /** ++ * Holds the output size of the message digest. ++ */ ++ private final int digestSize; ++ ++ /** ++ * Holds a dummy buffer for writing single bytes to the digest. ++ */ ++ private final byte[] singleByte = new byte[1]; ++ ++ private HmacContextRef contextRef = null; ++ ++ private KAEMac(String algo, int size) { ++ this.algorithm = algo; ++ this.digestSize = size; ++ } ++ ++ private static class HmacContextRef extends PhantomReference ++ implements Comparable { ++ ++ private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static Set referenceList = new ConcurrentSkipListSet<>(); ++ private static boolean disableKaeDispose = Boolean.getBoolean("kae.disableKaeDispose"); ++ ++ private final long address; ++ ++ HmacContextRef(KAEMac kaeMac, long address) { ++ super(kaeMac, referenceQueue); ++ this.address = address; ++ if (!disableKaeDispose) { ++ referenceList.add(this); ++ drainRefQueueBounded(); ++ } ++ } ++ ++ @Override ++ public int compareTo(HmacContextRef other) { ++ if (this.address == other.address) { ++ return 0; ++ } else { ++ return (this.address < other.address) ? -1 : 1; ++ } ++ } ++ ++ private static void drainRefQueueBounded() { ++ while (true) { ++ HmacContextRef next = (HmacContextRef) referenceQueue.poll(); ++ if (next == null) break; ++ next.dispose(true); ++ } ++ } ++ ++ void dispose(boolean needFree) { ++ if (!disableKaeDispose) { ++ referenceList.remove(this); ++ try { ++ if (needFree) { ++ nativeFree(address); ++ } ++ } finally { ++ this.clear(); ++ } ++ } else { ++ nativeFree(address); ++ } ++ } ++ } ++ ++ private void checkAndInitHmacContext () { ++ try { ++ if (contextRef == null) { ++ long ctxAddr = nativeInit(keyBytes, keyBytes.length, algorithm); ++ contextRef = new HmacContextRef(this, ctxAddr); ++ } ++ } ++ catch (Exception e) { ++ throw new ProviderException(e.getMessage()) ; ++ } ++ } ++ ++ @Override ++ protected int engineGetMacLength() { ++ return digestSize; ++ } ++ ++ @Override ++ protected void engineInit(Key key, AlgorithmParameterSpec params) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ if (!(key instanceof SecretKey)) { ++ throw new InvalidKeyException("key must be a SecretKey"); ++ } ++ if (params != null) { ++ throw new InvalidAlgorithmParameterException("unknown parameter type"); ++ } ++ keyBytes = key.getEncoded(); ++ if (keyBytes == null) { ++ throw new InvalidKeyException("key cannot be encoded"); ++ } ++ } ++ ++ @Override ++ protected void engineUpdate(byte input) { ++ singleByte[0] = input; ++ engineUpdate(singleByte, 0, 1); ++ } ++ ++ @Override ++ protected void engineUpdate(byte[] input, int offset, int len) { ++ checkAndInitHmacContext(); ++ try { ++ nativeUpdate(contextRef.address, input, offset, len); ++ } ++ catch (Exception e) { ++ engineReset(); ++ throw new ProviderException(e.getMessage()); ++ } ++ } ++ ++ ++ @Override ++ protected byte[] engineDoFinal() { ++ final byte[] output = new byte[digestSize]; ++ checkAndInitHmacContext(); ++ final byte[] res; ++ try { ++ int bytesWritten = nativeFinal(contextRef.address, output, 0, digestSize); ++ res = new byte[bytesWritten]; ++ System.arraycopy(output, 0, res, 0, bytesWritten); ++ } ++ catch (Exception e) { ++ engineReset(); ++ throw new ProviderException(e.getMessage()); ++ } ++ return res; ++ } ++ ++ @Override ++ protected void engineReset() { ++ if (contextRef != null) { ++ contextRef.dispose(true); ++ contextRef = null; ++ } ++ } ++ ++ public static final class HmacMD5 extends KAEMac { ++ public HmacMD5() { ++ super("MD5", 16); ++ } ++ } ++ public static final class HmacSHA1 extends KAEMac { ++ public HmacSHA1() { ++ super("SHA1", 20); ++ } ++ } ++ public static final class HmacSHA224 extends KAEMac { ++ public HmacSHA224() throws NoSuchAlgorithmException { ++ super("SHA224", 28); ++ } ++ } ++ public static final class HmacSHA256 extends KAEMac { ++ public HmacSHA256() throws NoSuchAlgorithmException { ++ super("SHA256", 32); ++ } ++ } ++ public static final class HmacSHA384 extends KAEMac { ++ public HmacSHA384() throws NoSuchAlgorithmException { ++ super("SHA384", 48); ++ } ++ } ++ public static final class HmacSHA512 extends KAEMac { ++ public HmacSHA512() throws NoSuchAlgorithmException { ++ super("SHA512", 64); ++ } ++ } ++ ++ protected static native long nativeInit(byte[] key, int len, String algo); ++ ++ protected static native void nativeUpdate(long ctxAddr, byte[] input, int inOffset, int inLen); ++ ++ protected static native int nativeFinal(long ctxAddr, byte[] output, int outOffset, int inLen); ++ ++ protected static native void nativeFree(long ctxAddr); ++} +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java +new file mode 100644 +index 00000000..fb84b768 +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEProvider.java +@@ -0,0 +1,180 @@ ++/* ++ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.io.BufferedWriter; ++import java.io.File; ++import java.io.IOException; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.Paths; ++import java.nio.file.StandardOpenOption; ++import java.util.Date; ++import java.security.Provider; ++ ++/** ++ * KAE Provider ++ */ ++public class KAEProvider extends Provider { ++ private static Throwable excp; ++ private static boolean needLog = true; ++ ++ static { ++ Throwable status = null; ++ try { ++ System.loadLibrary("j2kae"); ++ initOpenssl(); ++ } catch (UnsatisfiedLinkError t) { ++ status = t; ++ } catch (RuntimeException e) { ++ status = e; ++ } ++ excp = status; ++ } ++ ++ private void logStart(Throwable excp) { ++ File file = new File(System.getProperty("user.dir"), "kae.log"); ++ Path fpath = file.toPath(); ++ if (!Files.exists(fpath)) { ++ try { ++ file.createNewFile(); ++ } catch (IOException e) { ++ e.printStackTrace(); ++ } ++ } ++ ++ try (BufferedWriter writer = Files.newBufferedWriter(fpath, StandardOpenOption.APPEND)) { ++ if (excp != null) { ++ writer.write(excp.getMessage()); ++ } else { ++ writer.write("KAE Engine was found"); ++ } ++ writer.write(" " + new Date()); ++ writer.newLine(); ++ } catch (IOException e) { ++ e.initCause(excp).printStackTrace(); ++ } ++ KAEProvider.excp = null; // Exception already logged, clean it. ++ } ++ ++ private void putCipherAES() { ++ final String blockModes = "ECB|CBC|CTR"; ++ final String blockPads = "NOPADDING|PKCS5PADDING"; ++ ++ put("Cipher.AES SupportedModes", blockModes); ++ put("Cipher.AES SupportedPaddings", blockPads); ++ put("Cipher.AES", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ecb$PKCS5Padding"); ++ ++ put("Cipher.AES/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Cbc$PKCS5Padding"); ++ put("Cipher.AES/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.AES/CBC/PKCS7Padding", "AES/CBC/PKCS5Padding"); ++ put("Cipher.AES/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ecb$NoPadding"); ++ put("Cipher.AES/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.AES/ECB/PKCS7Padding", "AES/ECB/PKCS5Padding"); ++ put("Cipher.AES/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes$Ctr$NoPadding"); ++ ++ put("Cipher.AES_128/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Cbc$PKCS5Padding"); ++ put("Cipher.AES_128/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.AES_128/CBC/PKCS7Padding", "AES_128/CBC/PKCS5Padding"); ++ put("Cipher.AES_128/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Ecb$NoPadding"); ++ put("Cipher.AES_128/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.AES_128/ECB/PKCS7Padding", "AES_128/ECB/PKCS5Padding"); ++ put("Cipher.AES_128/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_128$Ctr$NoPadding"); ++ ++ put("Cipher.AES_192/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Cbc$PKCS5Padding"); ++ put("Cipher.AES_192/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.AES_192/CBC/PKCS7Padding", "AES_192/CBC/PKCS5Padding"); ++ put("Cipher.AES_192/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Ecb$NoPadding"); ++ put("Cipher.AES_192/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.AES_192/ECB/PKCS7Padding", "AES_192/ECB/PKCS5Padding"); ++ put("Cipher.AES_192/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_192$Ctr$NoPadding"); ++ ++ put("Cipher.AES_256/CBC/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Cbc$PKCS5Padding"); ++ put("Cipher.AES_256/CBC/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Cbc$NoPadding"); ++ put("Alg.Alias.Cipher.AES_256/CBC/PKCS7Padding", "AES_256/CBC/PKCS5Padding"); ++ put("Cipher.AES_256/ECB/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Ecb$NoPadding"); ++ put("Cipher.AES_256/ECB/PKCS5Padding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Ecb$PKCS5Padding"); ++ put("Alg.Alias.Cipher.AES_256/ECB/PKCS7Padding", "AES_256/ECB/PKCS5Padding"); ++ put("Cipher.AES_256/CTR/NoPadding", "org.openeuler.security.openssl.KAEAESCipher$Aes_256$Ctr$NoPadding"); ++ } ++ ++ private void putMessageDigest() { ++ put("MessageDigest.MD5", "org.openeuler.security.openssl.KAEDigest$MD5"); ++ put("MessageDigest.SHA-256", "org.openeuler.security.openssl.KAEDigest$SHA256"); ++ put("MessageDigest.SHA-384", "org.openeuler.security.openssl.KAEDigest$SHA384"); ++ } ++ ++ private void putCipherRSA() { ++ // rsa ++ put("KeyPairGenerator.RSA", "org.openeuler.security.openssl.KAERSAKeyPairGenerator$Legacy"); ++ put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA"); ++ put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA"); ++ ++ put("KeyPairGenerator.RSASSA-PSS", "org.openeuler.security.openssl.KAERSAKeyPairGenerator$PSS"); ++ put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1.10", "RSASSA-PSS"); ++ ++ put("Cipher.RSA", "org.openeuler.security.openssl.KAERSACipher"); ++ put("Cipher.RSA SupportedModes", "ECB"); ++ put("Cipher.RSA SupportedPaddings", ++ "NOPADDING|PKCS1PADDING|OAEPPADDING" ++ + "|OAEPWITHMD5ANDMGF1PADDING" ++ + "|OAEPWITHSHA1ANDMGF1PADDING" ++ + "|OAEPWITHSHA-1ANDMGF1PADDING" ++ + "|OAEPWITHSHA-224ANDMGF1PADDING" ++ + "|OAEPWITHSHA-256ANDMGF1PADDING" ++ + "|OAEPWITHSHA-384ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512/224ANDMGF1PADDING" ++ + "|OAEPWITHSHA-512/256ANDMGF1PADDING"); ++ put("Cipher.RSA SupportedKeyClasses", ++ "java.security.interfaces.RSAPublicKey" + ++ "|java.security.interfaces.RSAPrivateKey"); ++ } ++ ++ private void putMAC() { ++ put("MAC.HmacMD5", "org.openeuler.security.openssl.KAEMac$HmacMD5"); ++ put("MAC.HmacSHA1", "org.openeuler.security.openssl.KAEMac$HmacSHA1"); ++ put("MAC.HmacSHA224", "org.openeuler.security.openssl.KAEMac$HmacSHA224"); ++ put("MAC.HmacSHA256", "org.openeuler.security.openssl.KAEMac$HmacSHA256"); ++ put("MAC.HmacSHA384", "org.openeuler.security.openssl.KAEMac$HmacSHA384"); ++ put("MAC.HmacSHA512", "org.openeuler.security.openssl.KAEMac$HmacSHA512"); ++ } ++ ++ public KAEProvider() { ++ super("KAEProvider", 1.8d, "KAE provider"); ++ if (needLog) { ++ logStart(excp); ++ needLog = false; // Log only once ++ } ++ putMessageDigest(); ++ putCipherAES(); ++ putMAC(); ++ putCipherRSA(); ++ } ++ ++ // init openssl ++ static native void initOpenssl() throws RuntimeException; ++} +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSACipher.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSACipher.java +new file mode 100644 +index 00000000..a7bc172a +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSACipher.java +@@ -0,0 +1,796 @@ ++/* ++ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; ++import sun.security.jca.Providers; ++import sun.security.rsa.RSACore; ++import sun.security.rsa.RSAKeyFactory; ++import sun.security.rsa.RSAPadding; ++import sun.security.util.KeyUtil; ++ ++import javax.crypto.*; ++import javax.crypto.spec.OAEPParameterSpec; ++import javax.crypto.spec.PSource; ++import java.lang.ref.PhantomReference; ++import java.lang.ref.ReferenceQueue; ++import java.security.*; ++import java.security.interfaces.RSAKey; ++import java.security.interfaces.RSAPrivateCrtKey; ++import java.security.interfaces.RSAPrivateKey; ++import java.security.interfaces.RSAPublicKey; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.InvalidParameterSpecException; ++import java.security.spec.MGF1ParameterSpec; ++import java.util.Arrays; ++import java.util.Locale; ++import java.util.Set; ++import java.util.concurrent.ConcurrentSkipListSet; ++ ++ ++/** ++ * RSA cipher implementation. Supports RSA en/decryption and signing/verifying ++ * using both PKCS#1 v1.5 and OAEP (v2.2) paddings and without padding (raw RSA). ++ * Note that raw RSA is supported mostly for completeness and should only be ++ * used in rare cases. ++ *

++ * Objects should be instantiated by calling Cipher.getInstance() using the ++ * following algorithm names: ++ * . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 v1.5 padding. ++ * . "RSA/ECB/OAEPwithandMGF1Padding" (or "RSA/ECB/OAEPPadding") for ++ * PKCS#1 v2.2 padding. ++ * . "RSA/ECB/NoPadding" for rsa RSA. ++ *

++ * We only do one RSA operation per doFinal() call. If the application passes ++ * more data via calls to update() or doFinal(), we throw an ++ * IllegalBlockSizeException when doFinal() is called (see JCE API spec). ++ * Bulk encryption using RSA does not make sense and is not standardized. ++ *

++ * Note: RSA keys should be at least 512 bits long ++ */ ++public final class KAERSACipher extends CipherSpi { ++ // constant for an empty byte array ++ private final static byte[] B0 = new byte[0]; ++ ++ // mode constant for public key encryption ++ private final static int MODE_ENCRYPT = 1; ++ ++ // mode constant for private key decryption ++ private final static int MODE_DECRYPT = 2; ++ ++ // mode constant for private key encryption (signing) ++ private final static int MODE_SIGN = 3; ++ ++ // mode constant for public key decryption (verifying) ++ private final static int MODE_VERIFY = 4; ++ ++ // current mode, one of MODE_* above. Set when init() is called ++ private int mode; ++ ++ // active padding type, one of PAD_* above. Set by setPadding() ++ private KAERSAPaddingType paddingType; ++ ++ // padding object ++ private RSAPadding padding; ++ ++ // cipher parameter for OAEP padding and TLS RSA premaster secret ++ private AlgorithmParameterSpec spec = null; ++ ++ // buffer for the data ++ private byte[] buffer; ++ // offset into the buffer (number of bytes buffered) ++ private int bufOfs; ++ ++ // size of the output ++ private int outputSize; ++ ++ // hash algorithm for OAEP ++ private String oaepHashAlgorithm = "SHA-1"; ++ ++ // the source of randomness ++ private SecureRandom random; ++ ++ private RSAKey rsaKey; ++ ++ // rsa key holder ++ private KAERSAKeyHolder rsaKeyHolder; ++ ++ ++ public KAERSACipher() { ++ paddingType = KAERSAPaddingType.PKCS1Padding; ++ } ++ ++ // modes do not make sense for RSA, but allow ECB ++ // see JCE spec ++ @Override ++ protected void engineSetMode(String mode) throws NoSuchAlgorithmException { ++ if (!mode.equalsIgnoreCase("ECB")) { ++ throw new NoSuchAlgorithmException("Unsupported mode " + mode); ++ } ++ } ++ ++ // set the padding type ++ // see JCE spec ++ @Override ++ protected void engineSetPadding(String paddingName) ++ throws NoSuchPaddingException { ++ if (KAERSAPaddingType.NoPadding.getName().equalsIgnoreCase(paddingName)) { ++ paddingType = KAERSAPaddingType.NoPadding; ++ } else if (KAERSAPaddingType.PKCS1Padding.getName().equalsIgnoreCase(paddingName)) { ++ paddingType = KAERSAPaddingType.PKCS1Padding; ++ } else { ++ String lowerPadding = paddingName.toLowerCase(Locale.ENGLISH); ++ if ("oaeppadding".equals(lowerPadding)) { ++ paddingType = KAERSAPaddingType.OAEP; ++ } else if (lowerPadding.startsWith("oaepwith") && ++ lowerPadding.endsWith("andmgf1padding")) { ++ paddingType = KAERSAPaddingType.OAEP; ++ // "oaepwith" length is 8 ++ // "andmgf1padding" length is 14 ++ oaepHashAlgorithm = ++ paddingName.substring(8, paddingName.length() - 14); ++ // check if MessageDigest appears to be available ++ // avoid getInstance() call here ++ if (Providers.getProviderList().getService ++ ("MessageDigest", oaepHashAlgorithm) == null) { ++ throw new NoSuchPaddingException ++ ("MessageDigest not available for " + paddingName); ++ } ++ } else { ++ throw new NoSuchPaddingException ++ ("Padding " + paddingName + " not supported"); ++ } ++ } ++ } ++ ++ // return 0 as block size, we are not a block cipher ++ // see JCE spec ++ @Override ++ protected int engineGetBlockSize() { ++ return 0; ++ } ++ ++ // return the output size ++ // see JCE spec ++ @Override ++ protected int engineGetOutputSize(int inputLen) { ++ return outputSize; ++ } ++ ++ // no iv, return null ++ // see JCE spec ++ @Override ++ protected byte[] engineGetIV() { ++ return null; ++ } ++ ++ // see JCE spec ++ @Override ++ protected AlgorithmParameters engineGetParameters() { ++ if (spec != null && spec instanceof OAEPParameterSpec) { ++ try { ++ AlgorithmParameters params = ++ AlgorithmParameters.getInstance("OAEP"); ++ params.init(spec); ++ return params; ++ } catch (NoSuchAlgorithmException nsae) { ++ // should never happen ++ throw new RuntimeException("Cannot find OAEP " + ++ " AlgorithmParameters implementation in SunJCE provider"); ++ } catch (InvalidParameterSpecException ipse) { ++ // should never happen ++ throw new RuntimeException("OAEPParameterSpec not supported"); ++ } ++ } else { ++ return null; ++ } ++ } ++ ++ // see JCE spec ++ @Override ++ protected void engineInit(int opmode, Key key, SecureRandom random) ++ throws InvalidKeyException { ++ try { ++ init(opmode, key, random, null); ++ } catch (InvalidAlgorithmParameterException iape) { ++ // never thrown when null parameters are used; ++ // but re-throw it just in case ++ throw new InvalidKeyException("Wrong parameters", iape); ++ } ++ } ++ ++ // see JCE spec ++ @Override ++ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ init(opmode, key, random, params); ++ } ++ ++ // see JCE spec ++ @Override ++ protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ if (params == null) { ++ init(opmode, key, random, null); ++ } else { ++ try { ++ OAEPParameterSpec oaepParameterSpec = ++ params.getParameterSpec(OAEPParameterSpec.class); ++ init(opmode, key, random, oaepParameterSpec); ++ } catch (InvalidParameterSpecException ipse) { ++ InvalidAlgorithmParameterException iape = ++ new InvalidAlgorithmParameterException("Wrong parameter"); ++ iape.initCause(ipse); ++ throw iape; ++ } ++ } ++ } ++ ++ // check TlsRsaPremasterSecretParameterSpec ++ private void checkTlsRsaPremasterSecretParameterSpec(AlgorithmParameterSpec params) ++ throws InvalidAlgorithmParameterException { ++ if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { ++ throw new InvalidAlgorithmParameterException( ++ "Parameters not supported"); ++ } ++ } ++ ++ // check OAEPParameterSpec ++ private void checkOAEPParameterSpec(AlgorithmParameterSpec params) ++ throws InvalidAlgorithmParameterException { ++ if (!(params instanceof OAEPParameterSpec)) { ++ throw new InvalidAlgorithmParameterException ++ ("Wrong Parameters for OAEP Padding"); ++ } ++ ++ // check MGF algorithm ++ OAEPParameterSpec oaepParameterSpec = (OAEPParameterSpec) params; ++ String mgfName = oaepParameterSpec.getMGFAlgorithm(); ++ if (!mgfName.equalsIgnoreCase("MGF1")) { ++ throw new InvalidAlgorithmParameterException ++ ("Unsupported MGF algo: " + mgfName); ++ } ++ ++ // check PSource algorithm ++ PSource pSource = oaepParameterSpec.getPSource(); ++ String pSourceAlgorithm = pSource.getAlgorithm(); ++ if (!pSourceAlgorithm.equalsIgnoreCase("PSpecified")) { ++ throw new InvalidAlgorithmParameterException ++ ("Unsupported pSource algo: " + pSourceAlgorithm); ++ } ++ } ++ ++ // compute OAEP data buffer length ++ private int getOAEPBufferLen(int outputSize, OAEPParameterSpec oaepParameterSpec, boolean encrypt) ++ throws InvalidKeyException { ++ if (!encrypt) { ++ return outputSize; ++ } ++ String mdName = oaepParameterSpec.getDigestAlgorithm(); ++ String mgfMdName = ((MGF1ParameterSpec) oaepParameterSpec.getMGFParameters()) ++ .getDigestAlgorithm(); ++ int digestLen = KAEUtils.getDigestLength(mdName); ++ int bufferLen = outputSize - 2 - 2 * digestLen; ++ if (bufferLen < 0) { ++ throw new InvalidKeyException ++ ("Key is too short for encryption using OAEPPadding" + ++ " with " + mdName + " and MGF1" + mgfMdName); ++ } ++ return bufferLen; ++ } ++ ++ // non-CRT private key, use the jdk soft calculation. ++ private boolean useJdkSoftCalculation() { ++ return (rsaKey instanceof RSAPrivateKey) && !(rsaKey instanceof RSAPrivateCrtKey); ++ } ++ ++ // get the rsa padding ++ private RSAPadding getRSAPadding(KAERSAPaddingType paddingType, int paddedSize, ++ SecureRandom random, AlgorithmParameterSpec spec) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ RSAPadding rsaPadding; ++ if (KAERSAPaddingType.NoPadding.equals(paddingType)) { ++ rsaPadding = RSAPadding.getInstance(RSAPadding.PAD_NONE, paddedSize, random); ++ } else if (KAERSAPaddingType.PKCS1Padding.equals(paddingType)) { ++ int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 ++ : RSAPadding.PAD_BLOCKTYPE_1; ++ rsaPadding = RSAPadding.getInstance(blockType, paddedSize, random); ++ } else { ++ rsaPadding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, paddedSize, ++ random, (OAEPParameterSpec) spec); ++ } ++ return rsaPadding; ++ } ++ ++ private boolean isEncrypt(int opmode) throws InvalidKeyException { ++ boolean encrypt; ++ switch (opmode) { ++ case Cipher.ENCRYPT_MODE: ++ case Cipher.WRAP_MODE: ++ encrypt = true; ++ break; ++ case Cipher.DECRYPT_MODE: ++ case Cipher.UNWRAP_MODE: ++ encrypt = false; ++ break; ++ default: ++ throw new InvalidKeyException("Unknown mode: " + opmode); ++ } ++ return encrypt; ++ } ++ ++ // initialize this cipher ++ private void init(int opmode, Key key, SecureRandom random, AlgorithmParameterSpec params) ++ throws InvalidKeyException, InvalidAlgorithmParameterException { ++ // check the key, and convert to RSAKey ++ rsaKey = RSAKeyFactory.toRSAKey(key); ++ ++ // init mode ++ boolean encrypt = isEncrypt(opmode); ++ if (key instanceof RSAPublicKey) { ++ mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY; ++ } else { ++ mode = encrypt ? MODE_SIGN : MODE_DECRYPT; ++ } ++ ++ int bufferLen = RSACore.getByteLength(rsaKey.getModulus()); ++ outputSize = bufferLen; ++ bufOfs = 0; ++ if (KAERSAPaddingType.PKCS1Padding.equals(paddingType)) { ++ if (params != null) { ++ checkTlsRsaPremasterSecretParameterSpec(params); ++ spec = params; ++ this.random = random; // for TLS RSA premaster secret ++ } ++ if (encrypt) { ++ bufferLen -= 11; ++ } ++ } else if (KAERSAPaddingType.OAEP.equals(paddingType)) { ++ if ((mode == MODE_SIGN) || (mode == MODE_VERIFY)) { ++ throw new InvalidKeyException ++ ("OAEP cannot be used to sign or verify signatures"); ++ } ++ if (params != null) { ++ checkOAEPParameterSpec(params); ++ spec = params; ++ } else { ++ spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1", ++ MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); ++ } ++ bufferLen = getOAEPBufferLen(bufferLen, (OAEPParameterSpec) spec, encrypt); ++ } ++ buffer = new byte[bufferLen]; ++ ++ if (useJdkSoftCalculation()) { ++ this.padding = getRSAPadding(paddingType, outputSize, random, spec); ++ } ++ } ++ ++ // internal update method ++ private void update(byte[] in, int inOfs, int inLen) { ++ if ((inLen == 0) || (in == null)) { ++ return; ++ } ++ if (inLen > (buffer.length - bufOfs)) { ++ bufOfs = buffer.length + 1; ++ return; ++ } ++ System.arraycopy(in, inOfs, buffer, bufOfs, inLen); ++ bufOfs += inLen; ++ } ++ ++ // encrypt or decrypt for NoPadding or PKCS1Padding ++ private int doCryptNotOAEPPadding(long keyAddress, byte[] input, byte[] output) throws BadPaddingException { ++ int resultSize; ++ switch (mode) { ++ case MODE_SIGN: ++ resultSize = nativeRSAPrivateEncrypt(keyAddress, input.length, input, output, paddingType.getId()); ++ break; ++ case MODE_VERIFY: ++ resultSize = nativeRSAPublicDecrypt(keyAddress, input.length, input, output, paddingType.getId()); ++ break; ++ case MODE_ENCRYPT: ++ resultSize = nativeRSAPublicEncrypt(keyAddress, input.length, input, output, paddingType.getId()); ++ break; ++ case MODE_DECRYPT: ++ resultSize = nativeRSAPrivateDecrypt(keyAddress, input.length, input, output, paddingType.getId()); ++ break; ++ default: ++ throw new AssertionError("Internal error"); ++ } ++ return resultSize; ++ } ++ ++ ++ // encrypt or decrypt for OAEPPadding ++ private int doCryptOAEPPadding(long keyAddress, byte[] input, byte[] output, OAEPParameterSpec oaepParameterSpec) ++ throws BadPaddingException { ++ // oaep digest algorithm ++ String oaepMdAlgorithm = KAEUtils.getKAEDigestName(oaepParameterSpec.getDigestAlgorithm()); ++ // mgf1 digest algorithm ++ MGF1ParameterSpec mgf1ParameterSpec = (MGF1ParameterSpec) oaepParameterSpec.getMGFParameters(); ++ String mgf1MdAlgorithm = KAEUtils.getKAEDigestName(mgf1ParameterSpec.getDigestAlgorithm()); ++ // label ++ PSource pSource = oaepParameterSpec.getPSource(); ++ byte[] label = ((PSource.PSpecified) pSource).getValue(); ++ int resultSize; ++ switch (mode) { ++ case MODE_ENCRYPT: ++ resultSize = nativeRSAEncryptOAEPPadding(keyAddress, input.length, input, output, paddingType.getId(), ++ oaepMdAlgorithm, mgf1MdAlgorithm, label); ++ break; ++ case MODE_DECRYPT: ++ resultSize = nativeRSADecryptOAEPPadding(keyAddress, input.length, input, output, paddingType.getId(), ++ oaepMdAlgorithm, mgf1MdAlgorithm, label); ++ break; ++ default: ++ throw new AssertionError("Internal error"); ++ } ++ return resultSize; ++ } ++ ++ // get input bytes ++ private byte[] getInputBytes(byte[] buffer, int bufOfs, KAERSAPaddingType paddingType) { ++ if (bufOfs == buffer.length) { ++ return buffer; ++ } ++ ++ // if padding type is NoPadding , data should move to end ++ final byte[] input; ++ if (KAERSAPaddingType.NoPadding.equals(paddingType)) { ++ input = new byte[buffer.length]; ++ System.arraycopy(buffer, 0, input, buffer.length - bufOfs, bufOfs); ++ } else { ++ input = Arrays.copyOf(buffer, bufOfs); ++ } ++ return input; ++ } ++ ++ // internal doFinal() method. Here we perform the actual RSA operation ++ private byte[] doFinal() throws BadPaddingException, IllegalBlockSizeException { ++ if (bufOfs > buffer.length) { ++ throw new IllegalBlockSizeException("Data must not be longer " ++ + "than " + buffer.length + " bytes"); ++ } ++ ++ if (useJdkSoftCalculation()) { ++ return doFinalForJdkSoftCalculation(padding); ++ } ++ ++ // get input bytes ++ final byte[] input = getInputBytes(buffer, bufOfs, paddingType); ++ ++ try { ++ rsaKeyHolder = new KAERSAKeyHolder(this, rsaKey); ++ } catch (InvalidKeyException e) { ++ throw new RuntimeException(e.getMessage()); ++ } ++ ++ long keyAddress = rsaKeyHolder.keyAddress; ++ byte[] output = new byte[outputSize]; ++ int cipherTextLength; ++ try { ++ if (KAERSAPaddingType.OAEP.equals(paddingType)) { ++ // do crypt for OAEPPadding ++ cipherTextLength = doCryptOAEPPadding(keyAddress, input, output, (OAEPParameterSpec) spec); ++ } else { ++ // do crypt for NoPadding or PKCS1Padding ++ cipherTextLength = doCryptNotOAEPPadding(keyAddress, input, output); ++ } ++ ++ // If mode is signing or verifying , and the length of the ciphertext is less than output length, ++ // just keep output length ciphertext. ++ if ((mode == MODE_VERIFY || mode == MODE_DECRYPT) && cipherTextLength != output.length) { ++ output = Arrays.copyOf(output, cipherTextLength); ++ } ++ } finally { ++ bufOfs = 0; ++ resetKeyHolder(); ++ } ++ return output; ++ } ++ ++ private byte[] doFinalForJdkSoftCalculation(RSAPadding padding) throws BadPaddingException { ++ try { ++ byte[] data; ++ switch (mode) { ++ case MODE_SIGN: ++ data = padding.pad(buffer, 0, bufOfs); ++ return RSACore.rsa(data, (RSAPrivateKey) rsaKey, true); ++ case MODE_DECRYPT: ++ byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); ++ data = RSACore.rsa(decryptBuffer, (RSAPrivateKey) rsaKey, false); ++ return padding.unpad(data); ++ default: ++ throw new AssertionError("Internal error"); ++ } ++ } finally { ++ bufOfs = 0; ++ } ++ } ++ ++ // see JCE spec ++ @Override ++ protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { ++ update(in, inOfs, inLen); ++ return B0; ++ } ++ ++ // see JCE spec ++ @Override ++ protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, ++ int outOfs) { ++ update(in, inOfs, inLen); ++ return 0; ++ } ++ ++ // see JCE spec ++ @Override ++ protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) ++ throws BadPaddingException, IllegalBlockSizeException { ++ update(in, inOfs, inLen); ++ return doFinal(); ++ } ++ ++ // see JCE spec ++ @Override ++ protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) ++ throws ShortBufferException, BadPaddingException, IllegalBlockSizeException { ++ if (outputSize > out.length - outOfs) { ++ throw new ShortBufferException ++ ("Need " + outputSize + " bytes for output"); ++ } ++ update(in, inOfs, inLen); ++ byte[] result = doFinal(); ++ int length = result.length; ++ System.arraycopy(result, 0, out, outOfs, length); ++ return length; ++ } ++ ++ // see JCE spec ++ @Override ++ protected byte[] engineWrap(Key key) throws InvalidKeyException, ++ IllegalBlockSizeException { ++ byte[] encoded = key.getEncoded(); ++ if ((encoded == null) || (encoded.length == 0)) { ++ throw new InvalidKeyException("Could not obtain encoded key"); ++ } ++ if (encoded.length > buffer.length) { ++ throw new InvalidKeyException("Key is too long for wrapping"); ++ } ++ update(encoded, 0, encoded.length); ++ try { ++ return doFinal(); ++ } catch (BadPaddingException e) { ++ // should not occur ++ throw new InvalidKeyException("Wrapping failed", e); ++ } ++ } ++ ++ // see JCE spec ++ @Override ++ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, int type) ++ throws InvalidKeyException, NoSuchAlgorithmException { ++ if (wrappedKey.length > buffer.length) { ++ throw new InvalidKeyException("Key is too long for unwrapping"); ++ } ++ ++ boolean isTlsRsaPremasterSecret = "TlsRsaPremasterSecret".equals(algorithm); ++ Exception failover = null; ++ byte[] encoded = null; ++ ++ update(wrappedKey, 0, wrappedKey.length); ++ try { ++ encoded = doFinal(); ++ } catch (BadPaddingException e) { ++ if (isTlsRsaPremasterSecret) { ++ failover = e; ++ } else { ++ throw new InvalidKeyException("Unwrapping failed", e); ++ } ++ } catch (IllegalBlockSizeException e) { ++ // should not occur, handled with length check above ++ throw new InvalidKeyException("Unwrapping failed", e); ++ } ++ ++ if (isTlsRsaPremasterSecret) { ++ if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { ++ throw new IllegalStateException( ++ "No TlsRsaPremasterSecretParameterSpec specified"); ++ } ++ ++ // polish the TLS premaster secret ++ encoded = KeyUtil.checkTlsPreMasterSecretKey( ++ ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), ++ ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), ++ random, encoded, (failover != null)); ++ } ++ return KAEUtils.ConstructKeys.constructKey(encoded, algorithm, type); ++ } ++ ++ // see JCE spec ++ @Override ++ protected int engineGetKeySize(Key key) throws InvalidKeyException { ++ RSAKey newRSAKey = RSAKeyFactory.toRSAKey(key); ++ return newRSAKey.getModulus().bitLength(); ++ } ++ ++ // reset the key holder ++ private void resetKeyHolder() { ++ if (rsaKeyHolder != null) { ++ rsaKeyHolder.dispose(true); ++ rsaKeyHolder = null; ++ } ++ } ++ ++ // create KAE rsa key ++ protected static native long nativeCreateRSAPrivateCrtKey(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q, ++ byte[] dmp1, byte[] dmq1, byte[] iqmp); ++ ++ // create KAE rsa public key ++ protected static native long nativeCreateRSAPublicKey(byte[] n, byte[] e); ++ ++ // encrypt by private key for padding type (NOPADDING|PKCS1PADDING) ++ protected static native int nativeRSAPrivateEncrypt(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType) throws BadPaddingException; ++ ++ // decrypt by private key for padding type (NOPADDING|PKCS1PADDING) ++ protected static native int nativeRSAPrivateDecrypt(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType) throws BadPaddingException; ++ ++ // encrypt by public key for padding type (NOPADDING|PKCS1PADDING) ++ protected static native int nativeRSAPublicEncrypt(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType) throws BadPaddingException; ++ ++ // decrypt by public key for padding type (NOPADDING|PKCS1PADDING) ++ protected static native int nativeRSAPublicDecrypt(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType) throws BadPaddingException; ++ ++ // encrypt by public for padding type (OAEPPADDING) ++ protected static native int nativeRSAEncryptOAEPPadding(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType, String oaepMdAlgo, String mgf1MdAlgo, ++ byte[] label) throws BadPaddingException; ++ ++ // decrypt by public for padding type (OAEPPADDING) ++ protected static native int nativeRSADecryptOAEPPadding(long keyAddress, int inLen, byte[] in, byte[] out, ++ int paddingType, String oaepMdAlgo, String mgf1MdAlgo, ++ byte[] label) throws BadPaddingException; ++ ++ // free the key ++ protected static native void nativeFreeKey(long keyAddress); ++ ++ /** ++ * The rsa openssl key holder , use PhantomReference in case of native memory leaks ++ */ ++ private static class KAERSAKeyHolder extends PhantomReference ++ implements Comparable { ++ private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); ++ private static Set referenceList = new ConcurrentSkipListSet<>(); ++ private final long keyAddress; ++ ++ KAERSAKeyHolder(KAERSACipher rsaCipher, RSAKey rsaKey) throws InvalidKeyException { ++ super(rsaCipher, referenceQueue); ++ this.keyAddress = getKeyAddress(rsaKey); ++ referenceList.add(this); ++ drainRefQueueBounded(); ++ } ++ ++ private static void drainRefQueueBounded() { ++ while (true) { ++ KAERSAKeyHolder next = (KAERSAKeyHolder) referenceQueue.poll(); ++ if (next == null) { ++ break; ++ } ++ next.dispose(true); ++ } ++ } ++ ++ void dispose(boolean needFree) { ++ referenceList.remove(this); ++ try { ++ if (needFree) { ++ nativeFreeKey(keyAddress); ++ } ++ } finally { ++ this.clear(); ++ } ++ } ++ ++ @Override ++ public int compareTo(KAERSAKeyHolder other) { ++ if (this.keyAddress == other.keyAddress) { ++ return 0; ++ } else { ++ return (this.keyAddress < other.keyAddress) ? -1 : 1; ++ } ++ } ++ ++ private long getKeyAddress(RSAKey rsaKey) throws InvalidKeyException { ++ long address; ++ if (rsaKey instanceof RSAPrivateCrtKey) { // RSAPrivateCrtKeyImpl ++ address = getKeyAddress((RSAPrivateCrtKey) rsaKey); ++ } else if (rsaKey instanceof RSAPublicKey) { // RSAPublicKeyImpl ++ address = getKeyAddress((RSAPublicKey) rsaKey); ++ } else { ++ throw new InvalidKeyException("Invalid RSAKey implement " + rsaKey.getClass()); ++ } ++ return address; ++ } ++ ++ private long getKeyAddress(RSAPrivateCrtKey key) throws InvalidKeyException { ++ checkKey(key); ++ long address; ++ try { ++ address = nativeCreateRSAPrivateCrtKey( ++ key.getModulus().toByteArray(), ++ key.getPublicExponent().toByteArray(), ++ key.getPrivateExponent().toByteArray(), ++ key.getPrimeP().toByteArray(), ++ key.getPrimeQ().toByteArray(), ++ key.getPrimeExponentP().toByteArray(), ++ key.getPrimeExponentQ().toByteArray(), ++ key.getCrtCoefficient().toByteArray()); ++ return address; ++ } catch (Exception e) { ++ throw new InvalidKeyException(e); ++ } ++ } ++ ++ private long getKeyAddress(RSAPublicKey key) throws InvalidKeyException { ++ checkKey(key); ++ long address; ++ try { ++ address = nativeCreateRSAPublicKey( ++ key.getModulus().toByteArray(), ++ key.getPublicExponent().toByteArray() ++ ); ++ return address; ++ } catch (Exception e) { ++ throw new InvalidKeyException(e); ++ } ++ } ++ ++ private void checkKey(RSAPrivateCrtKey key) throws InvalidKeyException { ++ if (key.getModulus() == null ++ || key.getPublicExponent() == null ++ || key.getPrivateExponent() == null ++ || key.getPrimeP() == null ++ || key.getPrimeQ() == null ++ || key.getPrimeExponentP() == null ++ || key.getPrimeExponentQ() == null ++ || key.getCrtCoefficient() == null) { ++ throw new InvalidKeyException("Invalid RSA private key"); ++ } ++ } ++ ++ private void checkKey(RSAPublicKey key) throws InvalidKeyException { ++ if (key.getModulus() == null || key.getPublicExponent() == null) { ++ throw new InvalidKeyException("Invalid RSA public key"); ++ } ++ } ++ } ++} +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java +new file mode 100644 +index 00000000..51d7a95e +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAKeyPairGenerator.java +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import sun.security.rsa.*; ++import sun.security.rsa.RSAUtil.KeyType; ++import sun.security.util.SecurityProviderConstants; ++ ++import java.math.BigInteger; ++import java.security.*; ++import java.security.spec.AlgorithmParameterSpec; ++import java.security.spec.RSAKeyGenParameterSpec; ++ ++public abstract class KAERSAKeyPairGenerator extends KeyPairGeneratorSpi { ++ // public exponent to use ++ private BigInteger publicExponent; ++ ++ // size of the key to generate, >= KAERSAKeyFactory.MIN_MODLEN ++ private int keySize; ++ ++ private final KeyType type; ++ ++ private AlgorithmParameterSpec keyParams; ++ ++ ++ KAERSAKeyPairGenerator(KeyType keyType, int keySize) { ++ this.type = keyType; ++ initialize(keySize, null); ++ } ++ ++ // initialize the generator. See JCA doc ++ @Override ++ public void initialize(int keySize, SecureRandom random) { ++ try { ++ initialize(new RSAKeyGenParameterSpec(keySize, ++ RSAKeyGenParameterSpec.F4), null); ++ } catch (InvalidAlgorithmParameterException iape) { ++ throw new InvalidParameterException(iape.getMessage()); ++ } ++ } ++ ++ // second initialize method. See JCA doc ++ @Override ++ public void initialize(AlgorithmParameterSpec params, SecureRandom random) ++ throws InvalidAlgorithmParameterException { ++ if (!(params instanceof RSAKeyGenParameterSpec)) { ++ throw new InvalidAlgorithmParameterException ++ ("Params must be instance of RSAKeyGenParameterSpec"); ++ } ++ ++ RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) params; ++ int tmpKeySize = rsaSpec.getKeysize(); ++ BigInteger tmpPublicExponent = rsaSpec.getPublicExponent(); ++ keyParams = rsaSpec.getKeyParams(); ++ ++ if (tmpPublicExponent == null) { ++ tmpPublicExponent = RSAKeyGenParameterSpec.F4; ++ } else { ++ if (tmpPublicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) { ++ throw new InvalidAlgorithmParameterException ++ ("Public exponent must be 3 or larger"); ++ } ++ if (tmpPublicExponent.bitLength() > tmpKeySize) { ++ throw new InvalidAlgorithmParameterException ++ ("Public exponent must be smaller than key size"); ++ } ++ } ++ ++ // do not allow unreasonably large key sizes, probably user error ++ try { ++ RSAKeyFactory.checkKeyLengths(tmpKeySize, tmpPublicExponent, ++ 512, 64 * 1024); ++ } catch (InvalidKeyException e) { ++ throw new InvalidAlgorithmParameterException( ++ "Invalid key sizes", e); ++ } ++ ++ this.keySize = tmpKeySize; ++ this.publicExponent = tmpPublicExponent; ++ } ++ ++ // generate the keypair. See JCA doc ++ @Override ++ public KeyPair generateKeyPair() { ++ // get the KAE RSA key Parameters ++ byte[][] params = nativeGenerateKeyPair(keySize, publicExponent.toByteArray()); ++ ++ try { ++ // check KAE RSA key Parameters ++ checkKAERSAParams(params); ++ ++ BigInteger n = new BigInteger(params[0]); ++ BigInteger e = new BigInteger(params[1]); ++ BigInteger d = new BigInteger(params[2]); ++ BigInteger p = new BigInteger(params[3]); ++ BigInteger q = new BigInteger(params[4]); ++ BigInteger pe = new BigInteger(params[5]); ++ BigInteger qe = new BigInteger(params[6]); ++ BigInteger coeff = new BigInteger(params[7]); ++ ++ // public key ++ PublicKey publicKey = RSAPublicKeyImpl.newKey(type, keyParams, n, e); ++ ++ // private key ++ PrivateKey privateKey = RSAPrivateCrtKeyImpl.newKey(type, keyParams, n, e, d, p, q, pe, qe, coeff); ++ ++ return new KeyPair(publicKey, privateKey); ++ } catch (InvalidKeyException ex) { ++ throw new RuntimeException(ex); ++ } ++ } ++ ++ // check KAE RSA key Parameters ++ private void checkKAERSAParams(byte[][] params) throws InvalidKeyException { ++ if (params == null || params.length < 8) { ++ throw new InvalidKeyException("Invalid KAE RSA key Parameter"); ++ } ++ ++ for (int i = 0; i < params.length; i++) { ++ if (params[i] == null) { ++ throw new InvalidKeyException("Invalid KAE RSA key Parameter , params[" + i + "] = null"); ++ } ++ } ++ } ++ ++ public static final class Legacy extends KAERSAKeyPairGenerator { ++ public Legacy() { ++ super(KeyType.RSA, SecurityProviderConstants.DEF_RSA_KEY_SIZE); ++ } ++ } ++ ++ public static final class PSS extends KAERSAKeyPairGenerator { ++ public PSS() { ++ super(KeyType.PSS, SecurityProviderConstants.DEF_RSASSA_PSS_KEY_SIZE); ++ } ++ } ++ ++ // generate key pair ++ static native byte[][] nativeGenerateKeyPair(int keySize, byte[] publicExponent) throws RuntimeException; ++} +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAPaddingType.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAPaddingType.java +new file mode 100644 +index 00000000..04036b8d +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAERSAPaddingType.java +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import java.util.Arrays; ++import java.util.Collections; ++import java.util.HashSet; ++import java.util.Set; ++ ++enum KAERSAPaddingType { ++ // raw RSA ++ PKCS1Padding(1, "PKCS1Padding"), ++ ++ // PKCS#1 v1.5 RSA ++ NoPadding(3, "NoPadding"), ++ ++ // PKCS#2 v2.2 OAEP with MGF1 ++ OAEP(4, "OAEP", new HashSet<>( ++ Arrays.asList( ++ "OAEPPADDING", ++ "OAEPWITHMD5ANDMGF1PADDING", ++ "OAEPWITHSHA1ANDMGF1PADDING", ++ "OAEPWITHMD5ANDMGF1PADDING", ++ "OAEPWITHSHA1ANDMGF1PADDING", ++ "OAEPWITHSHA-1ANDMGF1PADDING", ++ "OAEPWITHSHA-224ANDMGF1PADDING", ++ "OAEPWITHSHA-256ANDMGF1PADDING", ++ "OAEPWITHSHA-384ANDMGF1PADDING", ++ "OAEPWITHSHA-512ANDMGF1PADDING", ++ "OAEPWITHSHA-512/224ANDMGF1PADDING", ++ "OAEPWITHSHA-512/256ANDMGF1PADDING")) ++ ); ++ ++ private final int id; ++ private final String name; ++ private final Set supportPaddings; ++ ++ public int getId() { ++ return id; ++ } ++ ++ public String getName() { ++ return name; ++ } ++ ++ KAERSAPaddingType(int id, String name) { ++ this(id, name, Collections.singleton(name)); ++ } ++ ++ KAERSAPaddingType(int id, String name, Set supportPaddings) { ++ this.id = id; ++ this.name = name; ++ this.supportPaddings = supportPaddings; ++ } ++ ++ public Set getSupportPaddings() { ++ return supportPaddings; ++ } ++} +diff --git a/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEUtils.java b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEUtils.java +new file mode 100644 +index 00000000..f563fd07 +--- /dev/null ++++ b/jdk/src/solaris/classes/org/openeuler/security/openssl/KAEUtils.java +@@ -0,0 +1,196 @@ ++/* ++ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.security.openssl; ++ ++import javax.crypto.Cipher; ++import javax.crypto.SecretKey; ++import javax.crypto.spec.SecretKeySpec; ++import java.security.*; ++import java.security.spec.InvalidKeySpecException; ++import java.security.spec.PKCS8EncodedKeySpec; ++import java.security.spec.X509EncodedKeySpec; ++import java.util.*; ++ ++class KAEUtils { ++ enum MessageDigestType { ++ MD2("MD2", "md2", 16), ++ MD5("MD5", "md5", 16), ++ SHA1("SHA-1", "sha1", 20, ++ new HashSet<>(Arrays.asList("SHA1", "1.3.14.3.2.26", "OID.1.3.14.3.2.26"))), ++ SHA224("SHA-224", "sha224", 28, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.4", "OID.2.16.840.1.101.3.4.2.4"))), ++ SHA256("SHA-256", "sha256", 32, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.1", "OID.2.16.840.1.101.3.4.2.1"))), ++ SHA384("SHA-384", "sha384", 48, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.2", "OID.2.16.840.1.101.3.4.2.2"))), ++ SHA512("SHA-512", "sha512", 64, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.3", "OID.2.16.840.1.101.3.4.2.3"))), ++ SHA512_224("SHA-512/224", "sha512-224", 28, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.5", "OID.2.16.840.1.101.3.4.2.5"))), ++ SHA_512_256("SHA-512/256", "sha512-256", 32, ++ new HashSet<>(Arrays.asList("2.16.840.1.101.3.4.2.6", "OID.2.16.840.1.101.3.4.2.6"))); ++ ++ final String digestName; ++ final String kaeDigestName; ++ final int digestLen; ++ final Set aliasNames; ++ ++ public String getDigestName() { ++ return digestName; ++ } ++ ++ public String getKaeDigestName() { ++ return kaeDigestName; ++ } ++ ++ public int getDigestLen() { ++ return digestLen; ++ } ++ ++ public Set getAliasNames() { ++ return aliasNames; ++ } ++ ++ MessageDigestType(String digestName, String kaeDigestName, int digestLen, Set aliasNames) { ++ this.digestName = digestName; ++ this.kaeDigestName = kaeDigestName; ++ this.digestLen = digestLen; ++ this.aliasNames = aliasNames; ++ } ++ ++ MessageDigestType(String digestName, String kaeDigestName, int digestLen) { ++ this(digestName, kaeDigestName, digestLen, Collections.emptySet()); ++ } ++ } ++ ++ /** ++ * kae digest algorithm info map ++ */ ++ private static final Map DIGEST_ALGORITHM_NAME_MAP = new HashMap<>(); ++ private static final Map DIGEST_ALGORITHM_LENGTH_MAP = new HashMap<>(); ++ ++ static { ++ initDigest(); ++ } ++ ++ private static void initDigest() { ++ MessageDigestType[] messageDigestTypes = MessageDigestType.values(); ++ for (MessageDigestType messageDigestType : messageDigestTypes) { ++ DIGEST_ALGORITHM_NAME_MAP.put(messageDigestType.getDigestName(), messageDigestType.getKaeDigestName()); ++ DIGEST_ALGORITHM_LENGTH_MAP.put(messageDigestType.getDigestName(), messageDigestType.getDigestLen()); ++ for (String aliasName : messageDigestType.getAliasNames()) { ++ DIGEST_ALGORITHM_NAME_MAP.put(aliasName, messageDigestType.getKaeDigestName()); ++ DIGEST_ALGORITHM_LENGTH_MAP.put(aliasName, messageDigestType.getDigestLen()); ++ } ++ } ++ } ++ ++ // get the kae digest algorithm name ++ static String getKAEDigestName(String digestName) { ++ return DIGEST_ALGORITHM_NAME_MAP.get(digestName); ++ } ++ ++ static int getDigestLength(String digestName) { ++ return DIGEST_ALGORITHM_LENGTH_MAP.get(digestName); ++ } ++ ++ static class ConstructKeys { ++ /** ++ * Construct a public key from its encoding. ++ * ++ * @param encodedKey the encoding of a public key. ++ * @param encodedKeyAlgorithm the algorithm the encodedKey is for. ++ * @return a public key constructed from the encodedKey. ++ */ ++ private static PublicKey constructPublicKey(byte[] encodedKey, ++ String encodedKeyAlgorithm) ++ throws InvalidKeyException, NoSuchAlgorithmException { ++ try { ++ KeyFactory keyFactory = ++ KeyFactory.getInstance(encodedKeyAlgorithm); ++ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); ++ return keyFactory.generatePublic(keySpec); ++ } catch (NoSuchAlgorithmException nsae) { ++ throw new NoSuchAlgorithmException("No installed providers " + ++ "can create keys for the " + ++ encodedKeyAlgorithm + ++ "algorithm", nsae); ++ } catch (InvalidKeySpecException ike) { ++ throw new InvalidKeyException("Cannot construct public key", ike); ++ } ++ } ++ ++ /** ++ * Construct a private key from its encoding. ++ * ++ * @param encodedKey the encoding of a private key. ++ * @param encodedKeyAlgorithm the algorithm the wrapped key is for. ++ * @return a private key constructed from the encodedKey. ++ */ ++ private static PrivateKey constructPrivateKey(byte[] encodedKey, ++ String encodedKeyAlgorithm) throws InvalidKeyException, ++ NoSuchAlgorithmException { ++ try { ++ KeyFactory keyFactory = ++ KeyFactory.getInstance(encodedKeyAlgorithm); ++ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); ++ return keyFactory.generatePrivate(keySpec); ++ } catch (NoSuchAlgorithmException nsae) { ++ throw new NoSuchAlgorithmException("No installed providers " + ++ "can create keys for the " + ++ encodedKeyAlgorithm + ++ "algorithm", nsae); ++ } catch (InvalidKeySpecException ike) { ++ throw new InvalidKeyException("Cannot construct private key", ike); ++ } ++ } ++ ++ /** ++ * Construct a secret key from its encoding. ++ * ++ * @param encodedKey the encoding of a secret key. ++ * @param encodedKeyAlgorithm the algorithm the secret key is for. ++ * @return a secret key constructed from the encodedKey. ++ */ ++ private static SecretKey constructSecretKey(byte[] encodedKey, ++ String encodedKeyAlgorithm) { ++ return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); ++ } ++ ++ static Key constructKey(byte[] encoding, String keyAlgorithm, ++ int keyType) throws InvalidKeyException, NoSuchAlgorithmException { ++ switch (keyType) { ++ case Cipher.SECRET_KEY: ++ return constructSecretKey(encoding, keyAlgorithm); ++ case Cipher.PRIVATE_KEY: ++ return constructPrivateKey(encoding, keyAlgorithm); ++ case Cipher.PUBLIC_KEY: ++ return constructPublicKey(encoding, keyAlgorithm); ++ default: ++ throw new InvalidKeyException("Unknown keytype " + keyType); ++ } ++ } ++ } ++} +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_aes.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_aes.c +new file mode 100644 +index 00000000..8a9526a2 +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_aes.c +@@ -0,0 +1,255 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#include ++#include "kae_log.h" ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAEAESCipher.h" ++ ++static const EVP_CIPHER* EVPGetCipherByName(JNIEnv* env, const char* algo) ++{ ++ static const EVP_CIPHER* aes128Ecb = NULL; ++ static const EVP_CIPHER* aes128Cbc = NULL; ++ static const EVP_CIPHER* aes128Ctr = NULL; ++ static const EVP_CIPHER* aes192Ecb = NULL; ++ static const EVP_CIPHER* aes192Cbc = NULL; ++ static const EVP_CIPHER* aes192Ctr = NULL; ++ static const EVP_CIPHER* aes256Ecb = NULL; ++ static const EVP_CIPHER* aes256Cbc = NULL; ++ static const EVP_CIPHER* aes256Ctr = NULL; ++ ++ if (strcasecmp(algo, "aes-128-ecb") == 0) { ++ return aes128Ecb == NULL ? aes128Ecb = EVP_get_cipherbyname(algo) : aes128Ecb; ++ } else if (strcasecmp(algo, "aes-128-cbc") == 0) { ++ return aes128Cbc == NULL ? aes128Cbc = EVP_get_cipherbyname(algo) : aes128Cbc; ++ } else if (strcasecmp(algo, "aes-128-ctr") == 0) { ++ return aes128Ctr == NULL ? aes128Ctr = EVP_get_cipherbyname(algo) : aes128Ctr; ++ } else if (strcasecmp(algo, "aes-192-ecb") == 0) { ++ return aes192Ecb == NULL ? aes192Ecb = EVP_get_cipherbyname(algo) : aes192Ecb; ++ } else if (strcasecmp(algo, "aes-192-cbc") == 0) { ++ return aes192Cbc == NULL ? aes192Cbc = EVP_get_cipherbyname(algo) : aes192Cbc; ++ } else if (strcasecmp(algo, "aes-192-ctr") == 0) { ++ return aes192Ctr == NULL ? aes192Ctr = EVP_get_cipherbyname(algo) : aes192Ctr; ++ } else if (strcasecmp(algo, "aes-256-ecb") == 0) { ++ return aes256Ecb == NULL ? aes256Ecb = EVP_get_cipherbyname(algo) : aes256Ecb; ++ } else if (strcasecmp(algo, "aes-256-cbc") == 0) { ++ return aes256Cbc == NULL ? aes256Cbc = EVP_get_cipherbyname(algo) : aes256Cbc; ++ } else if (strcasecmp(algo, "aes-256-ctr") == 0) { ++ return aes256Ctr == NULL ? aes256Ctr = EVP_get_cipherbyname(algo) : aes256Ctr; ++ } else { ++ KAE_ThrowRuntimeException(env, "EVPGetCipherByName error"); ++ return 0; ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEAESCipher ++ * Method: nativeInit ++ * Signature: (Ljava/lang/String;Z[B[B)J ++ */ ++JNIEXPORT jlong JNICALL ++Java_org_openeuler_security_openssl_KAEAESCipher_nativeInit(JNIEnv* env, jclass cls, ++ jstring cipherType, jboolean encrypt, jbyteArray key, jbyteArray iv, jboolean padding) ++{ ++ EVP_CIPHER_CTX* ctx = NULL; ++ jbyte* keyBytes = NULL; ++ jbyte* ivBytes = NULL; ++ const EVP_CIPHER* cipher = NULL; ++ ++ const char* algo = (*env)->GetStringUTFChars(env, cipherType, 0); ++ cipher = EVPGetCipherByName(env, algo); ++ (*env)->ReleaseStringUTFChars(env, cipherType, algo); ++ if (cipher == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_CIPHER fail"); ++ goto err; ++ } ++ ++ ctx = EVP_CIPHER_CTX_new(); ++ if (ctx == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_CIPHER_CTX fail"); ++ goto err; ++ } ++ ++ if (iv != NULL) { ++ ivBytes = (*env)->GetByteArrayElements(env, iv, NULL); ++ } ++ const unsigned char* i = (const unsigned char*) ivBytes; ++ ++ if (key != NULL) { ++ keyBytes = (*env)->GetByteArrayElements(env, key, NULL); ++ } ++ const unsigned char* k = (const unsigned char*) keyBytes; ++ ++ if (!EVP_CipherInit_ex(ctx, cipher, NULL, k, i, encrypt ? 1 : 0)) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherInit_ex failed", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ KAE_TRACE("KAEAESCipher_nativeInit EVP_CipherInit_ex(ctx = %p, cipher = %p, key = %p, iv = %p, encrypt = %d) " ++ "success", ctx, cipher, key, iv, encrypt ? 1 : 0); ++ ++ EVP_CIPHER_CTX_set_padding(ctx, padding ? 1 : 0); ++ ++ if (iv != NULL) { ++ (*env)->ReleaseByteArrayElements(env, iv, ivBytes, 0); ++ } ++ (*env)->ReleaseByteArrayElements(env, key, keyBytes, 0); ++ return (jlong) ctx; ++err: ++ if (ctx != NULL) { ++ EVP_CIPHER_CTX_free(ctx); ++ } ++ if (ivBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, iv, ivBytes, 0); ++ } ++ if (keyBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, key, keyBytes, 0); ++ } ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEAESCipher ++ * Method: nativeUpdate ++ * Signature: (JZ[BII[BI)I ++ */ ++JNIEXPORT jint JNICALL ++Java_org_openeuler_security_openssl_KAEAESCipher_nativeUpdate(JNIEnv* env, jclass cls, ++ jlong ctxAddress, jbyteArray inArr, jint inOfs, jint inLen, jbyteArray outArr, jint outOfs) ++{ ++ jbyte* in = NULL; ++ unsigned char* out = NULL; ++ ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*) ctxAddress; ++ if (ctx == NULL) { ++ goto err; ++ } ++ ++ if (inArr == NULL || outArr == NULL) { ++ goto err; ++ } ++ int inputLen = (*env)->GetArrayLength(env, inArr); ++ if ((inOfs < 0) || (inOfs > inputLen) || (inLen < 0) || (inLen > inputLen - inOfs)) { ++ KAE_ThrowArrayIndexOutOfBoundsException(env, "inArr"); ++ goto err; ++ } ++ in = malloc(sizeof(jbyte) * inputLen); ++ if (in == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto err; ++ } ++ (*env)->GetByteArrayRegion(env, inArr, 0, inputLen, in); ++ ++ int outputLen = (*env)->GetArrayLength(env, outArr); ++ if ((outOfs < 0) || (outOfs > outputLen) || (inLen < 0) || (inLen > outputLen - outOfs)) { ++ KAE_ThrowArrayIndexOutOfBoundsException(env, "outArr"); ++ goto err; ++ } ++ out = malloc(outputLen - outOfs); ++ if (out == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto err; ++ } ++ ++ unsigned int bytesWritten = 0; ++ if (EVP_CipherUpdate(ctx, out, &bytesWritten, in + inOfs, inLen) == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherUpdate failed", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ KAE_TRACE("KAEAESCipher_nativeUpdate EVP_CipherUpdate success, bytesWritten = %d", bytesWritten); ++ (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*) out); ++ ++ free(in); ++ free(out); ++ return bytesWritten; ++err: ++ if (in != NULL) { ++ free(in); ++ } ++ if (out != NULL) { ++ free(out); ++ } ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEAESCipher ++ * Method: nativeFinal ++ * Signature: (JZ[BI)I ++ */ ++JNIEXPORT jint JNICALL ++Java_org_openeuler_security_openssl_KAEAESCipher_nativeFinal(JNIEnv* env, jclass cls, ++ jlong ctxAddress, jbyteArray outArr, jint outOfs) ++{ ++ unsigned char* out; ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*) ctxAddress; ++ KAE_TRACE("KAEAESCipher_nativeFinal(ctxAddress = %p, outArr = %p, outOfs = %d)", ++ ctx, outArr, outOfs); ++ if (ctx == NULL) { ++ goto err; ++ } ++ if (outArr == NULL) { ++ goto err; ++ } ++ int outputLen = (*env)->GetArrayLength(env, outArr); ++ out = malloc(outputLen - outOfs); ++ if (out == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ goto err; ++ } ++ unsigned int bytesWritten = 0; ++ int result_code = EVP_CipherFinal_ex(ctx, out, &bytesWritten); ++ if (result_code == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_CipherFinal_ex failed", KAE_ThrowBadPaddingException); ++ goto err; ++ } ++ KAE_TRACE("KAEAESCipher_nativeFinal EVP_CipherFinal_ex success, bytesWritten = %d", bytesWritten); ++ (*env)->SetByteArrayRegion(env, outArr, outOfs, bytesWritten, (jbyte*) out); ++ free(out); ++ KAE_TRACE("KAEAESCipher_nativeFinal: finished"); ++ return bytesWritten; ++ ++err: ++ if (out != NULL) { ++ free(out); ++ } ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEAESCipher ++ * Method: nativeFree ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL ++Java_org_openeuler_security_openssl_KAEAESCipher_nativeFree(JNIEnv* env, jclass cls, jlong ctxAddress) ++{ ++ EVP_CIPHER_CTX* ctx = (EVP_CIPHER_CTX*) ctxAddress; ++ KAE_TRACE("KAEAESCipher_nativeFree(ctx = %p)", ctx); ++ if (ctx != NULL) { ++ EVP_CIPHER_CTX_free(ctx); ++ } ++ ++ KAE_TRACE("KAEAESCipher_nativeFree: finished"); ++} +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c +new file mode 100644 +index 00000000..ed645698 +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_cipher_rsa.c +@@ -0,0 +1,463 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAERSACipher.h" ++ ++#define SUCCESS 1 ++#define FAILED -1 ++ ++typedef int RSACryptOperation(int, const unsigned char*, unsigned char*, RSA*, int); ++ ++typedef int EvpPkeyCryptOperation(EVP_PKEY_CTX*, unsigned char*, size_t*, const unsigned char*, size_t); ++ ++typedef int EvpPkeyCryptInitOperation(EVP_PKEY_CTX*); ++ ++/* ++ * RSA encrypt or decrypt for NoPadding or PKCS1Padding , follow the steps below ++ * ++ */ ++static int RSACryptNotOAEPPadding(JNIEnv* env, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, ++ jint paddingType, RSACryptOperation rsaCryptOperation, char* cryptName) { ++ jbyte* inBytes = NULL; ++ jbyte* outBytes = NULL; ++ int resultSize = 0; ++ ++ // get RSA ++ EVP_PKEY* pkey = (EVP_PKEY*)keyAddress; ++ ++ // rsa = pkey->rsa ++ RSA* rsa = EVP_PKEY_get1_RSA(pkey); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_get1_RSA", KAE_ThrowRuntimeException); ++ return 0; ++ } ++ ++ // do encrypt or decrypt ++ inBytes = (*env)->GetByteArrayElements(env, in, NULL); ++ if (inBytes == NULL) { ++ KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ outBytes = (*env)->GetByteArrayElements(env, out, NULL); ++ if (outBytes == NULL) { ++ KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ resultSize = rsaCryptOperation(inLen, (unsigned char*)inBytes, (unsigned char*)outBytes, rsa, paddingType); ++ if (resultSize <= 0) { ++ KAE_ThrowFromOpenssl(env, cryptName, KAE_ThrowBadPaddingException); ++ goto cleanup; ++ } ++ jsize outLen = (*env)->GetArrayLength(env, out); ++ (*env)->SetByteArrayRegion(env, out, 0, outLen, outBytes); ++ ++cleanup: ++ if (outBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, out, outBytes, 0); ++ } ++ if (inBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, in, inBytes, 0); ++ } ++ return resultSize; ++} ++ ++/* ++ * set rsa padding ++ */ ++static int SetRSAPadding(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, int paddingType) { ++ if (EVP_PKEY_CTX_set_rsa_padding(pkeyCtx, paddingType) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_padding", KAE_ThrowInvalidAlgorithmParameterException); ++ return FAILED; ++ } ++ return SUCCESS; ++} ++ ++/* ++ * set rsa mgf1 md ++ */ ++static int SetRSAMgf1Md(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, const char* mgf1MdAlgoUTF) { ++ EVP_MD* mgf1MD = (EVP_MD*)EVP_get_digestbyname(mgf1MdAlgoUTF); ++ if (mgf1MD == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_get_digestbyname", KAE_ThrowInvalidAlgorithmParameterException); ++ return FAILED; ++ } ++ if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkeyCtx, mgf1MD) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_mgf1_md", KAE_ThrowInvalidAlgorithmParameterException); ++ return FAILED; ++ } ++ return SUCCESS; ++} ++ ++/* ++ * set rsa oaep md ++ */ ++static int SetRSAOaepMd(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, const char* oaepMdAlgoUTF) { ++ EVP_MD* oaepMD = (EVP_MD*)EVP_get_digestbyname(oaepMdAlgoUTF); ++ if (oaepMD == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_get_digestbyname", KAE_ThrowInvalidAlgorithmParameterException); ++ return FAILED; ++ } ++ if (EVP_PKEY_CTX_set_rsa_oaep_md(pkeyCtx, oaepMD) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set_rsa_oaep_md", KAE_ThrowInvalidAlgorithmParameterException); ++ return FAILED; ++ } ++ return SUCCESS; ++} ++ ++/* ++ * set rsa oaep label ++ */ ++static int SetRSAOaepLabel(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, jbyte* labelBytes, jsize labelSize) { ++ if (EVP_PKEY_CTX_set0_rsa_oaep_label(pkeyCtx, labelBytes, labelSize) <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_CTX_set0_rsa_oaep_label", KAE_ThrowInvalidAlgorithmParameterException); ++ return FAILED; ++ } ++ return SUCCESS; ++} ++ ++/* ++ * release rsa oaep temp resource ++ */ ++static void ReleaseRSACryptOAEPResource(JNIEnv* env, EVP_PKEY_CTX* pkeyCtx, ++ jstring mgf1MdAlgo, const char* mgf1MdAlgoUTF, jstring oaepMdAlgo, const char* oaepMdAlgoUTF, ++ jbyteArray in, jbyte* inBytes, jbyteArray out, jbyte* outBytes) { ++ if (mgf1MdAlgoUTF != NULL) { ++ (*env)->ReleaseStringUTFChars(env, mgf1MdAlgo, mgf1MdAlgoUTF); ++ } ++ if (oaepMdAlgoUTF != NULL) { ++ (*env)->ReleaseStringUTFChars(env, oaepMdAlgo, oaepMdAlgoUTF); ++ } ++ if (outBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, out, outBytes, 0); ++ } ++ if (inBytes != NULL) { ++ (*env)->ReleaseByteArrayElements(env, in, inBytes, 0); ++ } ++ EVP_PKEY_CTX_free(pkeyCtx); ++} ++ ++static int RSACryptOAEPPadding(JNIEnv* env, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, ++ jint paddingType, jstring oaepMdAlgo, jstring mgf1MdAlgo, jbyteArray label, ++ EvpPkeyCryptInitOperation cryptInitOperation, char* cryptInitName, ++ EvpPkeyCryptOperation cryptOperation, char* cryptName) { ++ EVP_PKEY_CTX* pkeyCtx = NULL; ++ const char* mgf1MdAlgoUTF = NULL; ++ const char* oaepMdAlgoUTF = NULL; ++ jbyte* labelBytes = NULL; ++ jbyte* outBytes = NULL; ++ jbyte* inBytes = NULL; ++ // outLen type should be size_t ++ // EVP_PKEY_encrypt takes the outLen address as a parameter, and the parameter type is size_t* ++ // You can refer to the issue #2774 to see more content ++ size_t outLen = 0; ++ ++ EVP_PKEY* pkey = (EVP_PKEY*) keyAddress; ++ ++ // new ctx ++ // rsa encrypt/decrypt init ++ if ((pkeyCtx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL || cryptInitOperation(pkeyCtx) <= 0) { ++ KAE_ThrowFromOpenssl(env, pkeyCtx == NULL ? "EVP_PKEY_CTX_new" : cryptInitName, KAE_ThrowInvalidKeyException); ++ goto cleanup; ++ } ++ ++ if ((mgf1MdAlgoUTF = (*env)->GetStringUTFChars(env, mgf1MdAlgo, 0)) == NULL || ++ (oaepMdAlgoUTF = (*env)->GetStringUTFChars(env, oaepMdAlgo, 0)) == NULL) { ++ KAE_ThrowOOMException(env, "GetStringUTFChars failed"); ++ goto cleanup; ++ } ++ ++ /* ++ * set padding type ++ * set rsa mgf1 md ++ * set rsa oaep md ++ */ ++ if(SetRSAPadding(env, pkeyCtx, paddingType) == FAILED || ++ SetRSAMgf1Md(env, pkeyCtx, mgf1MdAlgoUTF) == FAILED || ++ SetRSAOaepMd(env, pkeyCtx, oaepMdAlgoUTF) == FAILED) { ++ goto cleanup; ++ } ++ ++ // set rsa oaep label ++ jsize labelSize = (*env)->GetArrayLength(env, label); ++ if (labelSize > 0) { ++ // EVP_PKEY_CTX_free will free the labelBytes, so we can not free labelBytes when cleanup. ++ // Only SetRSAOaepLabel failed , free labelBytes. ++ if ((labelBytes = malloc(labelSize)) == NULL) { ++ KAE_ThrowNullPointerException(env, "malloc failed"); ++ goto cleanup; ++ } ++ (*env)->GetByteArrayRegion(env, label, 0, labelSize, labelBytes); ++ if(SetRSAOaepLabel(env, pkeyCtx, labelBytes, labelSize) == FAILED) { ++ free(labelBytes); ++ goto cleanup; ++ } ++ } ++ ++ // do encrypt/decrypt ++ outLen = (size_t)(*env)->GetArrayLength(env, out); ++ if ((outBytes = (*env)->GetByteArrayElements(env, out, NULL)) == NULL || ++ (inBytes = (*env)->GetByteArrayElements(env, in, NULL)) == NULL) { ++ KAE_ThrowNullPointerException(env, "GetByteArrayElements failed"); ++ goto cleanup; ++ } ++ if (cryptOperation(pkeyCtx, (unsigned char*)outBytes, &outLen, (unsigned char*)inBytes, inLen) <= 0) { ++ KAE_ThrowFromOpenssl(env, cryptName, KAE_ThrowBadPaddingException); ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, out, 0, outLen, outBytes); ++ ++cleanup: ++ ReleaseRSACryptOAEPResource(env, pkeyCtx, mgf1MdAlgo, mgf1MdAlgoUTF, oaepMdAlgo, oaepMdAlgoUTF, ++ in, inBytes, out, outBytes); ++ return outLen; ++} ++ ++/* ++ * Release rsa param n,e,d,p,q,dmp1,dmq1,iqmp ++ */ ++void ReleaseRSAParams(BIGNUM* bnN, BIGNUM* bnE, BIGNUM* bnD, BIGNUM* bnP, BIGNUM* bnQ, ++ BIGNUM* bnDMP1, BIGNUM* bnDMQ1, BIGNUM* bnIQMP) { ++ KAE_ReleaseBigNumFromByteArray(bnN); ++ KAE_ReleaseBigNumFromByteArray(bnE); ++ KAE_ReleaseBigNumFromByteArray(bnD); ++ KAE_ReleaseBigNumFromByteArray(bnP); ++ KAE_ReleaseBigNumFromByteArray(bnQ); ++ KAE_ReleaseBigNumFromByteArray(bnDMP1); ++ KAE_ReleaseBigNumFromByteArray(bnDMQ1); ++ KAE_ReleaseBigNumFromByteArray(bnIQMP); ++} ++ ++/* ++ * Create rsa private crt key ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeCreateRSAPrivateCrtKey ++ * Signature: ([B[B[B[B[B[B[B[B)J ++ */ ++JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPrivateCrtKey(JNIEnv* env, ++ jclass cls, jbyteArray n, jbyteArray e, jbyteArray d, jbyteArray p, jbyteArray q, ++ jbyteArray dmp1, jbyteArray dmq1, jbyteArray iqmp) { ++ BIGNUM* bnN = NULL; ++ BIGNUM* bnE = NULL; ++ BIGNUM* bnD = NULL; ++ BIGNUM* bnP = NULL; ++ BIGNUM* bnQ = NULL; ++ BIGNUM* bnDMP1 = NULL; ++ BIGNUM* bnDMQ1 = NULL; ++ BIGNUM* bnIQMP = NULL; ++ RSA* rsa = NULL; ++ EVP_PKEY* pkey = NULL; ++ ++ // convert to big num ++ if ((bnN = KAE_GetBigNumFromByteArray(env, n)) == NULL || ++ (bnE = KAE_GetBigNumFromByteArray(env, e)) == NULL || ++ (bnD = KAE_GetBigNumFromByteArray(env, d)) == NULL || ++ (bnP = KAE_GetBigNumFromByteArray(env, p)) == NULL || ++ (bnQ = KAE_GetBigNumFromByteArray(env, q)) == NULL || ++ (bnDMP1 = KAE_GetBigNumFromByteArray(env, dmp1)) == NULL || ++ (bnDMQ1 = KAE_GetBigNumFromByteArray(env, dmq1)) == NULL || ++ (bnIQMP = KAE_GetBigNumFromByteArray(env, iqmp)) == NULL) { ++ goto err; ++ } ++ ++ // new pkey ++ pkey = EVP_PKEY_new(); ++ if (pkey == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ ++ // new rsa ++ rsa = RSA_new(); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "RSA_new", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ ++ // set rsa private crt key params n,e,d,p,q,dmp1,dmp1,iqmp ++ if (RSA_set0_key(rsa, bnN, bnE, bnD) <= 0 || ++ RSA_set0_factors(rsa, bnP, bnQ) <= 0 || ++ RSA_set0_crt_params(rsa, bnDMP1, bnDMQ1, bnIQMP) <= 0) { ++ KAE_ThrowFromOpenssl(env, "RSA set param", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ ++ // assign rsa to pkey ++ int result = EVP_PKEY_assign_RSA(pkey, rsa); ++ if (result <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_assign_RSA", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ return (jlong)pkey; ++err: ++ ReleaseRSAParams(bnN, bnE, bnD, bnP, bnQ, bnDMP1, bnDMQ1, bnIQMP); ++ RSA_free(rsa); ++ EVP_PKEY_free(pkey); ++ return 0; ++} ++ ++/* ++ * Create rsa public key ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeCreateRSAPublicKey ++ * Signature: ([B[B)J ++ */ ++JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeCreateRSAPublicKey( ++ JNIEnv* env, jclass cls, jbyteArray n, jbyteArray e) { ++ BIGNUM* bnN = NULL; ++ BIGNUM* bnE = NULL; ++ RSA* rsa = NULL; ++ EVP_PKEY* pkey = NULL; ++ ++ // get public key param n ++ bnN = KAE_GetBigNumFromByteArray(env, n); ++ if (bnN == NULL) { ++ goto err; ++ } ++ ++ // get public key param e ++ bnE = KAE_GetBigNumFromByteArray(env, e); ++ if (bnE == NULL) { ++ goto err; ++ } ++ ++ // new RSA ++ rsa = RSA_new(); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "RSA_new", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ ++ // new EVP_PKEY ++ pkey = EVP_PKEY_new(); ++ if (pkey == NULL) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_new", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ ++ // set rsa public key params n and e ++ if(RSA_set0_key(rsa, bnN, bnE, NULL) <= 0) { ++ KAE_ThrowFromOpenssl(env, "RSA_set0_key", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ ++ // assign rsa to pkey ++ int result = EVP_PKEY_assign_RSA(pkey, rsa); ++ if (result <= 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_PKEY_assign_RSA", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ return (jlong)pkey; ++err: ++ KAE_ReleaseBigNumFromByteArray(bnN); ++ KAE_ReleaseBigNumFromByteArray(bnE); ++ RSA_free(rsa); ++ EVP_PKEY_free(pkey); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAPrivateEncrypt ++ * Signature: (JI[B[BI)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateEncrypt(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { ++ return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_private_encrypt, ++ "RSA_private_encrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAPrivateDecrypt ++ * Signature: (JI[B[BI)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPrivateDecrypt(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { ++ return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_private_decrypt, ++ "RSA_private_decrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAPublicEncrypt ++ * Signature: (JI[B[BI)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicEncrypt(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { ++ return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_public_encrypt, ++ "RSA_public_encrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAPublicDecrypt ++ * Signature: (JI[B[BI)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAPublicDecrypt(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType) { ++ return RSACryptNotOAEPPadding(env, keyAddress, inLen, in, out, paddingType, RSA_public_decrypt, ++ "RSA_public_decrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSAEncryptOAEPPading ++ * Signature: (JI[B[BI[B[B[B)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSAEncryptOAEPPadding(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, ++ jint paddingType,jstring oaepMdAlgo, jstring mgf1MdAlgo, jbyteArray label) { ++ return RSACryptOAEPPadding(env, keyAddress, inLen, in, out, paddingType, oaepMdAlgo, mgf1MdAlgo, label, ++ EVP_PKEY_encrypt_init, "EVP_PKEY_encrypt_init", ++ EVP_PKEY_encrypt, "EVP_PKEY_encrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeRSADecryptOAEPPadding ++ * Signature: (JI[B[BILjava/lang/String;Ljava/lang/String;[B)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeRSADecryptOAEPPadding(JNIEnv* env, ++ jclass cls, jlong keyAddress, jint inLen, jbyteArray in, jbyteArray out, jint paddingType, ++ jstring oaepMdAlgo, jstring mgf1MdAlgo, jbyteArray label) { ++ return RSACryptOAEPPadding(env, keyAddress, inLen, in, out, paddingType, oaepMdAlgo, mgf1MdAlgo, label, ++ EVP_PKEY_decrypt_init, "EVP_PKEY_decrypt_init", ++ EVP_PKEY_decrypt, "EVP_PKEY_decrypt"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSACipher ++ * Method: nativeFreeKey ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAERSACipher_nativeFreeKey(JNIEnv* env, ++ jclass cls, jlong keyAddress) { ++ EVP_PKEY* pkey = (EVP_PKEY*) keyAddress; ++ if (pkey != NULL) { ++ EVP_PKEY_free(pkey); ++ } ++} +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c +new file mode 100644 +index 00000000..6ae14969 +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_digest.c +@@ -0,0 +1,227 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#include "kae_log.h" ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAEDigest.h" ++ ++#define DIGEST_STACK_SIZE 1024 ++#define DIGEST_CHUNK_SIZE 64*1024 ++#define DIGEST_LENGTH_THRESHOLD 48 ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDigest ++ * Method: nativeInit ++ * Signature: (Ljava/lang/String;)J ++ */ ++JNIEXPORT jlong JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeInit(JNIEnv *env, jclass cls, jstring algorithmName) ++{ ++ EVP_MD_CTX* ctx = NULL; ++ ++ if (algorithmName == NULL) { ++ KAE_ThrowNullPointerException(env, "algorithm is null"); ++ return 0; ++ } ++ ++ // EVP_get_digestbyname ++ const char* algo_utf = (*env)->GetStringUTFChars(env, algorithmName, 0); ++ EVP_MD* md = (EVP_MD*) EVP_get_digestbyname(algo_utf); ++ (*env)->ReleaseStringUTFChars(env, algorithmName, algo_utf); ++ if (md == NULL) { ++ KAE_TRACE("%s not supported", algo_utf); ++ return 0; ++ } ++ KAE_TRACE("KAEDigest_nativeInit: create md => %p", md); ++ ++ ctx = EVP_MD_CTX_create(); ++ if (ctx == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_MD_CTX fail"); ++ return 0; ++ } ++ KAE_TRACE("KAEDigest_nativeInit: create ctx => %p", ctx); ++ ++ // EVP_DigestInit_ex ++ int result_code = EVP_DigestInit_ex(ctx, md, NULL); ++ if (result_code == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_DigestInit_ex failed", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ KAE_TRACE("KAEDigest_nativeInit EVP_DigestInit_ex(ctx = %p, md = %p) success", ctx, md); ++ ++ KAE_TRACE("KAEDigest_nativeInit: finished"); ++ return (jlong) ctx; ++ ++err: ++ EVP_MD_CTX_destroy(ctx); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDigest ++ * Method: nativeUpdate ++ * Signature: (Ljava/lang/String;J[BII)I ++ */ ++JNIEXPORT void JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeUpdate(JNIEnv *env, jclass cls, jlong ctxAddress, ++ jbyteArray input, jint offset, jint inLen) ++{ ++ EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; ++ KAE_TRACE("KAEDigest_nativeUpdate(ctx = %p, input = %p, offset = %d, inLen = %d", ctx, input, offset, inLen); ++ if (ctx == NULL) { ++ return; ++ } ++ ++ jint in_offset = offset; ++ jint in_size = inLen; ++ int result_code = 0; ++ if (in_size <= DIGEST_STACK_SIZE) { // allocation on the stack ++ jbyte buffer[DIGEST_STACK_SIZE]; ++ (*env)->GetByteArrayRegion(env, input, offset, inLen, buffer); ++ result_code = EVP_DigestUpdate(ctx, buffer, inLen); ++ } else { // data chunk ++ jint remaining = in_size; ++ jint buf_size = (remaining >= DIGEST_CHUNK_SIZE) ? DIGEST_CHUNK_SIZE : remaining; ++ jbyte* buffer = malloc(buf_size); ++ if (buffer == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ return; ++ } ++ while (remaining > 0) { ++ jint chunk_size = (remaining >= buf_size) ? buf_size : remaining; ++ (*env)->GetByteArrayRegion(env, input, in_offset, chunk_size, buffer); ++ result_code = EVP_DigestUpdate(ctx, buffer, chunk_size); ++ if (!result_code) { ++ break; ++ } ++ in_offset += chunk_size; ++ remaining -= chunk_size; ++ } ++ free(buffer); ++ } ++ if (!result_code) { ++ KAE_ThrowFromOpenssl(env, "EVP_DigestUpdate failed", KAE_ThrowRuntimeException); ++ return; ++ } ++ KAE_TRACE("KAEDigest_nativeUpdate EVP_DigestUpdate success"); ++ KAE_TRACE("KAEDigest_nativeUpdate: finished"); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDigest ++ * Method: nativeDigest ++ * Signature: (Ljava/lang/String;J[BII)I ++ */ ++JNIEXPORT jint JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeDigest(JNIEnv *env, jclass cls, ++ jlong ctxAddress, jbyteArray output, jint offset, jint len) ++{ ++ EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; ++ KAE_TRACE("KAEDigest_nativeDigest(ctx = %p, output = %p, offset = %d, len = %d", ctx, output, offset, len); ++ unsigned char* md = NULL; ++ unsigned int bytesWritten = 0; ++ ++ if (ctx == NULL) { ++ return 0; ++ } ++ ++ if (len <= 0 || len > DIGEST_LENGTH_THRESHOLD) { ++ KAE_ThrowRuntimeException(env, "len out of length"); ++ return 0; ++ } ++ md = malloc(len); ++ if (md == NULL) { ++ KAE_ThrowOOMException(env, "malloc error"); ++ return 0; ++ } ++ ++ // EVP_DigestFinal_ex ++ int result_code = EVP_DigestFinal_ex(ctx, md, &bytesWritten); ++ if (result_code == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_DigestFinal_ex failed", KAE_ThrowRuntimeException); ++ goto cleanup; ++ } ++ KAE_TRACE("KAEDigest_nativeFinal EVP_DigestFinal_ex success, bytesWritten = %d", bytesWritten); ++ ++ (*env)->SetByteArrayRegion(env, output, offset, bytesWritten, (jbyte*) md); ++ ++ KAE_TRACE("KAEDigest_nativeFinal: finished"); ++ ++cleanup: ++ free(md); ++ return bytesWritten; ++} ++ ++/* ++* Class: org_openeuler_security_openssl_KAEDigest ++* Method: nativeClone ++* Signature: (J)J ++*/ ++JNIEXPORT jlong JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeClone(JNIEnv *env, jclass cls, jlong ctxAddress) ++{ ++ EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; ++ KAE_TRACE("KAEDigest_nativeClone: ctx = %p", ctx); ++ if (ctx == NULL) { ++ return 0; ++ } ++ ++ EVP_MD_CTX* ctxCopy = EVP_MD_CTX_create(); ++ if (ctxCopy == NULL) { ++ KAE_ThrowOOMException(env, "create EVP_MD_CTX fail"); ++ return 0; ++ } ++ KAE_TRACE("KAEDigest_nativeClone: create ctxCopy => %p", ctxCopy); ++ ++ int result_code = EVP_MD_CTX_copy_ex(ctxCopy, ctx); ++ if (result_code == 0) { ++ KAE_ThrowFromOpenssl(env, "EVP_MD_CTX_copy_ex failed", KAE_ThrowRuntimeException); ++ goto err; ++ } ++ KAE_TRACE("KAEDigest_nativeClone EVP_MD_CTX_copy_ex(ctxCopy = %p, ctx = %p) success", ctxCopy, ctx); ++ KAE_TRACE("KAEDigest_nativeClone: finished"); ++ return (jlong) ctxCopy; ++ ++err: ++ EVP_MD_CTX_destroy(ctxCopy); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEDigest ++ * Method: nativeFree ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL ++Java_org_openeuler_security_openssl_KAEDigest_nativeFree(JNIEnv *env, jclass cls, jlong ctxAddress) ++{ ++ EVP_MD_CTX* ctx = (EVP_MD_CTX*) ctxAddress; ++ KAE_TRACE("KAEDigest_nativeFree(ctx = %p)", ctx); ++ if (ctx != NULL) { ++ EVP_MD_CTX_destroy(ctx); ++ } ++ ++ KAE_TRACE("KAEDigest_nativeFree: finished"); ++} +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.c +new file mode 100644 +index 00000000..b1a29334 +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.c +@@ -0,0 +1,116 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#include "kae_util.h" ++#include "kae_log.h" ++#include "kae_exception.h" ++ ++void KAE_ThrowByName(JNIEnv* env, const char* name, const char* msg) { ++ jclass cls = (*env)->FindClass(env, name); ++ if (cls != 0) { ++ (*env)->ThrowNew(env, cls, msg); ++ (*env)->DeleteLocalRef(env, cls); ++ } ++} ++ ++void KAE_ThrowOOMException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/OutOfMemoryError", msg); ++} ++ ++void KAE_ThrowNullPointerException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/NullPointerException", msg); ++} ++ ++void KAE_ThrowArrayIndexOutOfBoundsException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/ArrayIndexOutOfBoundsException", msg); ++} ++ ++void KAE_ThrowEvpException(JNIEnv* env, int reason, const char* msg, void (* defaultException)(JNIEnv*, const char*)) { ++ switch (reason) { ++ case EVP_R_UNSUPPORTED_ALGORITHM: ++ KAE_ThrowByName(env, "java/security/NoSuchAlgorithmException", msg); ++ break; ++ case EVP_R_MISSING_PARAMETERS: ++ KAE_ThrowByName(env, "java/security/InvalidKeyException", msg); ++ break; ++ case EVP_R_BAD_DECRYPT: ++ KAE_ThrowByName(env, "javax/crypto/BadPaddingException", msg); ++ break; ++ default: ++ defaultException(env, msg); ++ break; ++ } ++} ++ ++void KAE_ThrowRuntimeException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/lang/RuntimeException", msg); ++} ++ ++void KAE_ThrowBadPaddingException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "javax/crypto/BadPaddingException", msg); ++} ++ ++void KAE_ThrowInvalidKeyException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/security/InvalidKeyException", msg); ++} ++ ++void KAE_ThrowInvalidAlgorithmParameterException(JNIEnv* env, const char* msg) { ++ KAE_ThrowByName(env, "java/security/InvalidAlgorithmParameterException", msg); ++} ++ ++void KAE_ThrowFromOpenssl(JNIEnv* env, const char* msg, void (* defaultException)(JNIEnv*, const char*)) { ++ const char* file = NULL; ++ const char* data = NULL; ++ int line = 0; ++ int flags = 0; ++ unsigned long err; ++ static const int ESTRING_SIZE = 256; ++ ++ err = ERR_get_error_line_data(&file, &line, &data, &flags); ++ if (err == 0) { ++ KAE_ThrowRuntimeException(env, "Unknown OpenSSL error"); ++ return; ++ } ++ ++ if (!(*env)->ExceptionCheck(env)) { ++ char estring[ESTRING_SIZE]; ++ ERR_error_string_n(err, estring, ESTRING_SIZE); ++ int lib = ERR_GET_LIB(err); ++ int reason = ERR_GET_REASON(err); ++ KAE_TRACE("OpenSSL error in %s: err=%lx, lib=%x, reason=%x, file=%s, line=%d, estring=%s, data=%s", msg, err, ++ lib, reason, file, line, estring, (flags & ERR_TXT_STRING) ? data : "(no data)"); ++ ++ switch (lib) { ++ case ERR_LIB_EVP: ++ KAE_ThrowEvpException(env, reason, estring, defaultException); ++ break; ++ default: ++ defaultException(env, estring); ++ break; ++ } ++ } ++ ++ ERR_clear_error(); ++} +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.h b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.h +new file mode 100644 +index 00000000..f528ad4a +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_exception.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#ifndef KAE_EXCEPTION_H ++#define KAE_EXCEPTION_H ++ ++#include ++ ++/* Throw a Java exception by name */ ++void KAE_ThrowByName(JNIEnv* env, const char* name, const char* msg); ++ ++void KAE_ThrowOOMException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowNullPointerException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowArrayIndexOutOfBoundsException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowFromOpenssl(JNIEnv* env, const char* msg, void (* defaultException)(JNIEnv*, const char*)); ++ ++void KAE_ThrowEvpException(JNIEnv* env, int reason, const char* msg, void (* defaultException)(JNIEnv*, const char*)); ++ ++void KAE_ThrowRuntimeException(JNIEnv* env, const char* msg); ++ ++void KAE_ThrowBadPaddingException(JNIEnv* env, const char* msg); ++ ++/* Throw InvalidKeyException */ ++void KAE_ThrowInvalidKeyException(JNIEnv* env, const char* msg); ++ ++/* Throw AlgorithmParameterException */ ++void KAE_ThrowInvalidAlgorithmParameterException(JNIEnv* env, const char* msg); ++ ++#endif +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c +new file mode 100644 +index 00000000..01848c0e +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_keypairgenerator_rsa.c +@@ -0,0 +1,173 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAERSAKeyPairGenerator.h" ++#define KAE_RSA_PARAM_SIZE 8 ++#define SUCCESS 1 ++#define FAILED -1 ++ ++ ++// rsa param index ++typedef enum RSAParamIndex { ++ rsa_n = 0, ++ rsa_e = 1, ++ rsa_d = 2, ++ rsa_p = 3, ++ rsa_q = 4, ++ rsa_dmp1 = 5, ++ rsa_dmq1 = 6, ++ rsa_iqmp = 7 ++} RSAParamIndex; ++ ++// rsa param name array ++static const char* RSAParamNames[] = {"n", "e", "d", "p", "q", "dmp1", "dmq1", "iqmp"}; ++ ++// rsa get rsa param function list ++static const BIGNUM* (* GetRSAParamFunctionList[])(const RSA*) = { ++ RSA_get0_n, ++ RSA_get0_e, ++ RSA_get0_d, ++ RSA_get0_p, ++ RSA_get0_q, ++ RSA_get0_dmp1, ++ RSA_get0_dmq1, ++ RSA_get0_iqmp ++}; ++ ++/* ++ * New RSA and generate rsa key, follow the steps below ++ * step 1.New RSA ++ * step 2.Convert publicExponent to BIGNUM ++ * step 3.Generate rsa key, and all key information is stored in RSA ++ */ ++static RSA* NewRSA(JNIEnv* env, jint keySize, jbyteArray publicExponent) { ++ // RSA_new ++ RSA* rsa = RSA_new(); ++ if (rsa == NULL) { ++ KAE_ThrowFromOpenssl(env, "RSA_new", KAE_ThrowRuntimeException); ++ return NULL; ++ } ++ ++ // convert publicExponent to BIGNUM ++ BIGNUM* exponent = KAE_GetBigNumFromByteArray(env, publicExponent); ++ if (exponent == NULL) { ++ return NULL; ++ } ++ ++ // generate rsa key ++ int result_code = RSA_generate_key_ex(rsa, keySize, exponent, NULL); ++ KAE_ReleaseBigNumFromByteArray(exponent); ++ if (result_code <= 0) { ++ RSA_free(rsa); ++ KAE_ThrowFromOpenssl(env, "RSA_generate_key_ex", KAE_ThrowRuntimeException); ++ return NULL; ++ } ++ return rsa; ++} ++ ++/* ++ * release RSA ++ */ ++static void ReleaseRSA(RSA* rsa) { ++ if (rsa != NULL) { ++ RSA_free(rsa); ++ } ++} ++ ++/* ++ * Set rsa key param, follow the steps below ++ * step 1. Get rsa param name ++ * step 2. Get rsa param value ++ * step 3. Convert paramValue (BIGNUM) to jbyteArray ++ * step 4. Set the rsa param to the param array ++ */ ++static int SetRSAKeyParam(JNIEnv* env, RSA* rsa, jobjectArray params, RSAParamIndex rsaParamIndex) { ++ // get rsa param name ++ const char* rsaParamName = RSAParamNames[rsaParamIndex]; ++ ++ // get rsa param value ++ const BIGNUM* rsaParamValue = GetRSAParamFunctionList[rsaParamIndex](rsa); ++ if (rsaParamValue == NULL) { ++ return FAILED; ++ } ++ ++ // Convert paramValue to jbyteArray ++ jbyteArray param = KAE_GetByteArrayFromBigNum(env, rsaParamValue, rsaParamName); ++ if (param == NULL) { ++ return FAILED; ++ } ++ ++ // Set the rsa param to the param array ++ (*env)->SetObjectArrayElement(env, params, rsaParamIndex, param); ++ return SUCCESS; ++} ++ ++/* ++ * New rsa key params, follow the steps below ++ * step 1. New rsa key param array ++ * step 2. Set rsa key param ++ */ ++static jobjectArray NewRSAKeyParams(JNIEnv* env, RSA* rsa) { ++ // new param array ++ jclass byteArrayClass = (*env)->FindClass(env, "[B"); ++ jobjectArray params = (*env)->NewObjectArray(env, KAE_RSA_PARAM_SIZE, byteArrayClass, NULL); ++ if (params == NULL) { ++ KAE_ThrowOOMException(env, "failed to allocate array"); ++ return NULL; ++ } ++ ++ // set rsa key param ++ for (RSAParamIndex paramIndex = rsa_n; paramIndex <= rsa_iqmp; paramIndex++) { ++ if (SetRSAKeyParam(env, rsa, params, paramIndex) == FAILED) { ++ return NULL; ++ } ++ } ++ return params; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAERSAKeyPairGenerator ++ * Method: nativeGenerateKeyPair ++ * Signature: (I[B)[[B ++ */ ++JNIEXPORT jobjectArray JNICALL Java_org_openeuler_security_openssl_KAERSAKeyPairGenerator_nativeGenerateKeyPair ++ (JNIEnv* env, jclass cls, jint keySize, jbyteArray publicExponent) { ++ if (publicExponent == NULL) { ++ return NULL; ++ } ++ ++ // new RSA ++ RSA* rsa = NewRSA(env, keySize, publicExponent); ++ if (rsa == NULL) { ++ return NULL; ++ } ++ ++ // new RSA Key Parameters ++ jobjectArray rsaParm = NewRSAKeyParams(env, rsa); ++ ++ // release rsa ++ ReleaseRSA(rsa); ++ return rsaParm; ++} +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_log.h b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_log.h +new file mode 100644 +index 00000000..d8d9c7b3 +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_log.h +@@ -0,0 +1,33 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#ifndef KAE_LOG_H ++#define KAE_LOG_H ++ ++#ifdef KAE_DEBUG ++#define KAE_TRACE(...) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); } ++#else ++#define KAE_TRACE(...) ++#endif ++ ++#endif +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_mac.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_mac.c +new file mode 100644 +index 00000000..2df2a9cb +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_mac.c +@@ -0,0 +1,201 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#include "kae_exception.h" ++#include "kae_log.h" ++ ++static const EVP_MD* EVPGetDigestByName(JNIEnv* env, const char* algo) ++{ ++ static const EVP_MD* md5 = NULL; ++ static const EVP_MD* sha1 = NULL; ++ static const EVP_MD* sha224 = NULL; ++ static const EVP_MD* sha256 = NULL; ++ static const EVP_MD* sha384 = NULL; ++ static const EVP_MD* sha512 = NULL; ++ ++ if (strcasecmp(algo, "md5") == 0) { ++ return md5 == NULL ? md5 = EVP_get_digestbyname(algo) : md5; ++ } else if (strcasecmp(algo, "sha1") == 0) { ++ return sha1 == NULL ? sha1 = EVP_get_digestbyname(algo) : sha1; ++ } else if (strcasecmp(algo, "sha224") == 0) { ++ return sha224 == NULL ? sha224 = EVP_get_digestbyname(algo) : sha224; ++ } else if (strcasecmp(algo, "sha256") == 0) { ++ return sha256 == NULL ? sha256 = EVP_get_digestbyname(algo) : sha256; ++ } else if (strcasecmp(algo, "sha384") == 0) { ++ return sha384 == NULL ? sha384 = EVP_get_digestbyname(algo) : sha384; ++ } else if (strcasecmp(algo, "sha512") == 0) { ++ return sha512 == NULL ? sha512 = EVP_get_digestbyname(algo) : sha512; ++ } else { ++ KAE_ThrowRuntimeException(env, "EVPGetDigestByName error"); ++ return 0; ++ } ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEMac ++ * Method: nativeInit ++ * Signature: ([BILjava/lang/String;)J ++ */ ++JNIEXPORT jlong JNICALL Java_org_openeuler_security_openssl_KAEMac_nativeInit ++ (JNIEnv* env, jclass cls, jbyteArray key, jint key_len, jstring algoStr) { ++ if (key == NULL || algoStr == NULL) { ++ KAE_ThrowNullPointerException(env, "param key or algoStr is null"); ++ return 0; ++ } ++ if (key_len <= 0) { ++ KAE_ThrowArrayIndexOutOfBoundsException(env, "key"); ++ return 0; ++ } ++ HMAC_CTX* ctx = NULL; ++ jbyte* key_buffer = NULL; ++ const EVP_MD* md = NULL; ++ ++ const char* algo = (*env)->GetStringUTFChars(env, algoStr, 0); ++ md = EVPGetDigestByName(env, algo); ++ (*env)->ReleaseStringUTFChars(env, algoStr, algo); ++ if (md == NULL) { ++ KAE_ThrowRuntimeException(env, "algorithm unsupport"); ++ return 0; ++ } ++ ++ // get secret-key ++ key_buffer = malloc(key_len); ++ if (key_buffer == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ return 0; ++ } ++ (*env)->GetByteArrayRegion(env, key, 0, key_len, key_buffer); ++ ++ // create a hmac context ++ ctx = HMAC_CTX_new(); ++ if (ctx == NULL) { ++ KAE_ThrowRuntimeException(env, "Hmac_CTX_new invoked failed"); ++ goto err; ++ } ++ ++ // init hmac context with sc_key and evp_md ++ int result_code = HMAC_Init_ex(ctx, key_buffer, key_len, md, NULL); ++ if (result_code == 0) { ++ KAE_ThrowRuntimeException(env, "Hmac_Init_ex invoked failed"); ++ goto err; ++ } ++ free(key_buffer); ++ return (jlong) ctx; ++ ++err: ++ free(key_buffer); ++ HMAC_CTX_free(ctx); ++ return 0; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEMac ++ * Method: nativeUpdate ++ * Signature: (J[BII)V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEMac_nativeUpdate ++ (JNIEnv* env, jclass cls, jlong hmac_ctx, jbyteArray input, jint in_offset, jint in_len) { ++ KAE_TRACE("KAEMac_nativeUpdate(ctx = %p, input = %p, offset = %d, inLen = %d", hmac_ctx, input, in_offset, in_len); ++ HMAC_CTX* ctx = (HMAC_CTX*) hmac_ctx; ++ if (ctx == NULL || input == NULL) { ++ KAE_ThrowNullPointerException(env, "param ctx or input is null"); ++ return; ++ } ++ int input_size = (*env)->GetArrayLength(env, input); ++ if ((in_offset < 0) || (in_len < 0) || (in_offset > input_size - in_len)) { ++ KAE_ThrowArrayIndexOutOfBoundsException(env, "input"); ++ return; ++ } ++ // do nothing while in_len is 0 ++ if (in_len == 0) { ++ return; ++ } ++ ++ jbyte* buffer = malloc(in_len); ++ if (buffer == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ return; ++ } ++ (*env)->GetByteArrayRegion(env, input, in_offset, in_len, buffer); ++ if (!HMAC_Update(ctx, (unsigned char*) buffer, in_len)) { ++ KAE_ThrowRuntimeException(env, "Hmac_Update invoked failed"); ++ } ++ free(buffer); ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEMac ++ * Method: nativeFinal ++ * Signature: (J[BII)I ++ */ ++JNIEXPORT jint JNICALL Java_org_openeuler_security_openssl_KAEMac_nativeFinal ++ (JNIEnv* env, jclass cls, jlong hmac_ctx, jbyteArray output, jint out_offset, jint in_len) { ++ HMAC_CTX* ctx = (HMAC_CTX*) hmac_ctx; ++ if (ctx == NULL || output == NULL) { ++ KAE_ThrowNullPointerException(env, "param ctx or input is null"); ++ return 0; ++ } ++ int output_size = (*env)->GetArrayLength(env, output); ++ if ((out_offset < 0) || (in_len < 0) || (out_offset > output_size - in_len)) { ++ KAE_ThrowArrayIndexOutOfBoundsException(env, "output"); ++ return 0; ++ } ++ ++ jbyte* temp_result = NULL; ++ ++ temp_result = malloc(in_len); ++ if (temp_result == NULL) { ++ KAE_ThrowOOMException(env, "malloc failed"); ++ return 0; ++ } ++ // do final ++ unsigned int bytesWritten = 0; ++ int result_code = HMAC_Final(ctx, (unsigned char*) temp_result, &bytesWritten); ++ if (result_code == 0) { ++ KAE_ThrowRuntimeException(env, "Hmac_Final invoked failed"); ++ goto cleanup; ++ } ++ ++ // write back to output_array ++ (*env)->SetByteArrayRegion(env, output, out_offset, bytesWritten, (jbyte*) temp_result); ++ KAE_TRACE("KAEMac_nativeFinal success, output_offset = %d, bytesWritten = %d", out_offset, bytesWritten); ++ ++cleanup: ++ free(temp_result); ++ return bytesWritten; ++} ++ ++/* ++ * Class: org_openeuler_security_openssl_KAEMac ++ * Method: nativeFree ++ * Signature: (J)V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEMac_nativeFree ++ (JNIEnv* env, jclass cls, jlong hmac_ctx) { ++ HMAC_CTX* ctx = (HMAC_CTX*) hmac_ctx; ++ if (ctx != NULL) { ++ HMAC_CTX_free(ctx); ++ } ++} +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c +new file mode 100644 +index 00000000..cfd2480e +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_provider.c +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include ++#include ++#include "kae_exception.h" ++#include "org_openeuler_security_openssl_KAEProvider.h" ++/* ++ * Class: org_openeuler_security_openssl_WdProvider ++ * Method: initOpenssl ++ * Signature: ()V ++ */ ++JNIEXPORT void JNICALL Java_org_openeuler_security_openssl_KAEProvider_initOpenssl ++ (JNIEnv *env, jclass cls) { ++ SSL_load_error_strings(); ++ ERR_load_BIO_strings(); ++ OpenSSL_add_all_algorithms(); ++ ++ // determine whether KAE is loaded successfully ++ ENGINE *e = ENGINE_by_id("kae"); ++ if (e == NULL) { ++ KAE_ThrowRuntimeException(env, "kae engine not found"); ++ return; ++ } ++ ENGINE_free(e); ++} +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c +new file mode 100644 +index 00000000..4e4c31ec +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.c +@@ -0,0 +1,102 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#include ++#include "kae_util.h" ++#include "kae_exception.h" ++ ++ ++BIGNUM* KAE_GetBigNumFromByteArray(JNIEnv* env, jbyteArray byteArray) { ++ if (byteArray == NULL) { ++ KAE_ThrowNullPointerException(env, "KAE_GetBigNumFromByteArray byteArray is null"); ++ return NULL; ++ } ++ ++ jsize len = (*env)->GetArrayLength(env, byteArray); ++ if (len == 0) { ++ KAE_ThrowRuntimeException(env, "KAE_GetBigNumFromByteArray byteArray is empty"); ++ return NULL; ++ } ++ ++ BIGNUM* bn = BN_new(); ++ if (bn == NULL) { ++ KAE_ThrowFromOpenssl(env, "BN_new", KAE_ThrowRuntimeException); ++ return NULL; ++ } ++ ++ jbyte* bytes = (*env)->GetByteArrayElements(env, byteArray, NULL); ++ if (bytes == NULL) { ++ KAE_ThrowNullPointerException(env,"GetByteArrayElements failed"); ++ goto error; ++ } ++ BIGNUM* result = BN_bin2bn((const unsigned char*) bytes, len, bn); ++ (*env)->ReleaseByteArrayElements(env, byteArray, bytes, 0); ++ if (result == NULL) { ++ KAE_ThrowFromOpenssl(env, "BN_bin2bn", KAE_ThrowRuntimeException); ++ goto error; ++ } ++ return bn; ++ ++error: ++ BN_free(bn); ++ return NULL; ++} ++ ++void KAE_ReleaseBigNumFromByteArray(BIGNUM* bn) { ++ if (bn != NULL) { ++ BN_free(bn); ++ } ++} ++ ++jbyteArray KAE_GetByteArrayFromBigNum(JNIEnv* env, const BIGNUM* bn, const char* sourceName) { ++ if (bn == NULL) { ++ return NULL; ++ } ++ // bn size need plus 1, for example 65535 , BN_num_bytes return 2 ++ int bnSize = BN_num_bytes(bn); ++ if (bnSize <= 0) { ++ return NULL; ++ } ++ bnSize += 1; ++ jbyteArray javaBytes = (*env)->NewByteArray(env, bnSize); ++ if (javaBytes == NULL) { ++ KAE_ThrowOOMException(env, "new byte array failed"); ++ return NULL; ++ } ++ jbyte* bytes = (*env)->GetByteArrayElements(env, javaBytes, NULL); ++ if (bytes == NULL) { ++ KAE_ThrowNullPointerException(env,"GetByteArrayElements failed"); ++ return NULL; ++ } ++ unsigned char* tmp = (unsigned char*) bytes; ++ if (BN_bn2bin(bn, tmp + 1) <= 0) { ++ KAE_ThrowFromOpenssl(env, "BN_bn2bin", KAE_ThrowRuntimeException); ++ javaBytes = NULL; ++ goto cleanup; ++ } ++ (*env)->SetByteArrayRegion(env, javaBytes, 0, bnSize, bytes); ++ ++cleanup: ++ (*env)->ReleaseByteArrayElements(env, javaBytes, bytes, 0); ++ return javaBytes; ++} +diff --git a/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h +new file mode 100644 +index 00000000..35715e1c +--- /dev/null ++++ b/jdk/src/solaris/native/org/openeuler/security/openssl/kae_util.h +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#ifndef KAE_UTIL_H ++#define KAE_UTIL_H ++ ++#include ++#include ++ ++/* jbyteArray convert to BIGNUM */ ++BIGNUM* KAE_GetBigNumFromByteArray(JNIEnv* env, jbyteArray byteArray); ++ ++/* release BIGNUM allocat from */ ++void KAE_ReleaseBigNumFromByteArray(BIGNUM* bn); ++ ++/* BIGNUM convert to jbyteArray */ ++jbyteArray KAE_GetByteArrayFromBigNum(JNIEnv* env, const BIGNUM* bn, const char* sourceName); ++ ++#endif +diff --git a/jdk/test/java/net/URLPermission/policy.1 b/jdk/test/java/net/URLPermission/policy.1 +index 5816cdbf..40bb7258 100644 +--- a/jdk/test/java/net/URLPermission/policy.1 ++++ b/jdk/test/java/net/URLPermission/policy.1 +@@ -34,6 +34,7 @@ grant { + //permission "java.io.FilePermission" "/tmp/-", "read,write"; + permission "java.lang.RuntimePermission" "modifyThread"; + permission "java.lang.RuntimePermission" "setFactory"; ++ permission "java.util.PropertyPermission" "kae.disableKaeDispose", "read"; + }; + + // Normal permissions that aren't granted when run under jtreg +diff --git a/jdk/test/java/net/URLPermission/policy.2 b/jdk/test/java/net/URLPermission/policy.2 +index d1d774f4..21345c53 100644 +--- a/jdk/test/java/net/URLPermission/policy.2 ++++ b/jdk/test/java/net/URLPermission/policy.2 +@@ -34,6 +34,7 @@ grant { + //permission "java.io.FilePermission" "/tmp/-", "read,write"; + permission "java.lang.RuntimePermission" "modifyThread"; + permission "java.lang.RuntimePermission" "setFactory"; ++ permission "java.util.PropertyPermission" "kae.disableKaeDispose", "read"; + }; + + grant codeBase "file:${{java.ext.dirs}}/*" { +diff --git a/jdk/test/java/net/URLPermission/policy.3 b/jdk/test/java/net/URLPermission/policy.3 +index 47f213fa..d86617f7 100644 +--- a/jdk/test/java/net/URLPermission/policy.3 ++++ b/jdk/test/java/net/URLPermission/policy.3 +@@ -34,6 +34,7 @@ grant { + //permission "java.io.FilePermission" "/tmp/-", "read,write"; + permission "java.lang.RuntimePermission" "modifyThread"; + permission "java.lang.RuntimePermission" "setFactory"; ++ permission "java.util.PropertyPermission" "kae.disableKaeDispose", "read"; + }; + + // Normal permissions that aren't granted when run under jtreg +diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java +new file mode 100644 +index 00000000..0034b67c +--- /dev/null ++++ b/jdk/test/micro/org/openeuler/bench/security/openssl/AESBenchmark.java +@@ -0,0 +1,108 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import java.security.InvalidKeyException; ++import java.security.InvalidAlgorithmParameterException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.Security; ++import java.util.concurrent.TimeUnit; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import javax.crypto.spec.SecretKeySpec; ++ ++@Warmup(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS) ++public class AESBenchmark extends BenchmarkBase { ++ ++ @Param({"AES/ECB/PKCS5Padding", "AES/ECB/NoPadding", "AES/CBC/NoPadding", "AES/CBC/PKCS5Padding", "AES/CTR/NoPadding"}) ++ private String algorithm; ++ ++ @Param({"128", "192", "256"}) ++ private int keyLength; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ private int dataSize; ++ ++ private byte[][] encryptedData; ++ private Cipher encryptCipher; ++ private Cipher decryptCipher; ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, ++ InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { ++ setupProvider(); ++ ++ byte[] keystring = fillSecureRandom(new byte[keyLength / 8]); ++ SecretKeySpec ks = new SecretKeySpec(keystring, "AES"); ++ ++ encryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ encryptCipher.init(Cipher.ENCRYPT_MODE, ks); ++ decryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); ++ ++ data = fillRandom(new byte[SET_SIZE][dataSize]); ++ encryptedData = fillEncrypted(data, encryptCipher); ++ } ++ ++ @Benchmark ++ public byte[] encrypt() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return encryptCipher.doFinal(d); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsAppend = {"-Dkae.disableKaeDispose=true"}) ++ public byte[] encryptDispose() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return encryptCipher.doFinal(d); ++ } ++ ++ @Benchmark ++ public byte[] decrypt() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] e = encryptedData[index]; ++ index = (index + 1) % SET_SIZE; ++ return decryptCipher.doFinal(e); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsAppend = {"-Dkae.disableKaeDispose=true"}) ++ public byte[] decryptDispose() throws IllegalBlockSizeException, BadPaddingException { ++ byte[] e = encryptedData[index]; ++ index = (index + 1) % SET_SIZE; ++ return decryptCipher.doFinal(e); ++ } ++} ++ +diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java b/jdk/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java +new file mode 100644 +index 00000000..41c56e49 +--- /dev/null ++++ b/jdk/test/micro/org/openeuler/bench/security/openssl/BenchmarkBase.java +@@ -0,0 +1,100 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openeuler.security.openssl.KAEProvider; ++import org.openjdk.jmh.annotations.BenchmarkMode; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Measurement; ++import org.openjdk.jmh.annotations.Mode; ++import org.openjdk.jmh.annotations.OutputTimeUnit; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Scope; ++import org.openjdk.jmh.annotations.Setup; ++import org.openjdk.jmh.annotations.State; ++import org.openjdk.jmh.annotations.Threads; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import java.security.Provider; ++import java.security.SecureRandom; ++import java.security.Security; ++import java.util.Random; ++import java.util.concurrent.TimeUnit; ++ ++@BenchmarkMode(Mode.AverageTime) ++@OutputTimeUnit(TimeUnit.MICROSECONDS) ++@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS) ++@Measurement(iterations = 3, time = 2, timeUnit = TimeUnit.SECONDS) ++@Fork(jvmArgsPrepend = {"-Xms100G", "-Xmx100G", "-XX:+AlwaysPreTouch"}, value = 1) ++@Threads(1) ++@State(Scope.Thread) ++public class BenchmarkBase { ++ public static final int SET_SIZE = 128; ++ ++ byte[][] data; ++ int index = 0; ++ ++ @Param({"", "KAEProvider"}) ++ private String provider; ++ ++ public Provider prov = null; ++ ++ @Setup ++ public void setupProvider() { ++ Security.addProvider(new KAEProvider()); ++ if (provider != null && !provider.isEmpty()) { ++ prov = Security.getProvider(provider); ++ if (prov == null) { ++ throw new RuntimeException("Can't find provider \"" + provider + "\""); ++ } ++ } ++ } ++ ++ public static byte[][] fillRandom(byte[][] data) { ++ Random rnd = new Random(); ++ for (byte[] d : data) { ++ rnd.nextBytes(d); ++ } ++ return data; ++ } ++ ++ public static byte[] fillSecureRandom(byte[] data) { ++ SecureRandom rnd = new SecureRandom(); ++ rnd.nextBytes(data); ++ return data; ++ } ++ ++ public static byte[][] fillEncrypted(byte[][] data, Cipher encryptCipher) ++ throws IllegalBlockSizeException, BadPaddingException { ++ byte[][] encryptedData = new byte[data.length][]; ++ for (int i = 0; i < encryptedData.length; i++) { ++ encryptedData[i] = encryptCipher.doFinal(data[i]); ++ } ++ return encryptedData; ++ } ++ ++} +diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java +new file mode 100644 +index 00000000..96d2a24f +--- /dev/null ++++ b/jdk/test/micro/org/openeuler/bench/security/openssl/DigestBenchmark.java +@@ -0,0 +1,69 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++ ++import java.security.MessageDigest; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.Security; ++import java.util.concurrent.TimeUnit; ++ ++public class DigestBenchmark extends BenchmarkBase { ++ ++ @Param({"MD5", "SHA-256", "SHA-384"}) ++ private String algorithm; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ int dataSize; ++ ++ MessageDigest md; ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException { ++ setupProvider(); ++ data = fillRandom(new byte[SET_SIZE][dataSize]); ++ md = (prov == null) ? MessageDigest.getInstance(algorithm) : MessageDigest.getInstance(algorithm, prov); ++ } ++ ++ @Benchmark ++ public byte[] digest() { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return md.digest(d); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsAppend = {"-Dkae.disableKaeDispose=true"}) ++ public byte[] digestDispose() { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return md.digest(d); ++ } ++} ++ +diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java +new file mode 100644 +index 00000000..584484f3 +--- /dev/null ++++ b/jdk/test/micro/org/openeuler/bench/security/openssl/HMacBenchmark.java +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package org.openeuler.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Fork; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++ ++import java.security.InvalidKeyException; ++import java.security.NoSuchAlgorithmException; ++import java.security.Provider; ++import java.security.Security; ++import java.util.concurrent.TimeUnit; ++ ++import javax.crypto.KeyGenerator; ++import javax.crypto.Mac; ++ ++public class HMacBenchmark extends BenchmarkBase { ++ ++ @Param({"HmacMD5", "HmacSHA1", "HmacSHA224", "HmacSHA256", "HmacSHA384", "HmacSHA512"}) ++ private String algorithm; ++ ++ @Param({"" + 1024, "" + 10 * 1024, "" + 100 * 1024, "" + 1024 * 1024}) ++ private int dataSize; ++ ++ private Mac mac; ++ ++ @Setup ++ public void setup() throws NoSuchAlgorithmException, InvalidKeyException { ++ setupProvider(); ++ mac = (prov == null) ? Mac.getInstance(algorithm) : Mac.getInstance(algorithm, prov); ++ mac.init(KeyGenerator.getInstance(algorithm).generateKey()); ++ data = fillRandom(new byte[SET_SIZE][dataSize]); ++ } ++ ++ @Benchmark ++ public byte[] mac() { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return mac.doFinal(d); ++ } ++ ++ @Benchmark ++ @Fork(jvmArgsAppend = {"-Dkae.disableKaeDispose=true"}) ++ public byte[] macDispose() { ++ byte[] d = data[index]; ++ index = (index + 1) % SET_SIZE; ++ return mac.doFinal(d); ++ } ++} ++ +diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java +new file mode 100644 +index 00000000..2a5eb9c7 +--- /dev/null ++++ b/jdk/test/micro/org/openeuler/bench/security/openssl/RSACipherBenchmark.java +@@ -0,0 +1,107 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++ ++import javax.crypto.BadPaddingException; ++import javax.crypto.Cipher; ++import javax.crypto.IllegalBlockSizeException; ++import javax.crypto.NoSuchPaddingException; ++import java.security.InvalidKeyException; ++import java.security.KeyPair; ++import java.security.KeyPairGenerator; ++import java.security.NoSuchAlgorithmException; ++ ++public class RSACipherBenchmark extends BenchmarkBase { ++ @Param({"RSA/ECB/NoPadding", "RSA/ECB/PKCS1Padding", "RSA/ECB/OAEPPadding"}) ++ private String algorithm; ++ ++ @Param({"512", "1024", "2048", "3072", "4096"}) ++ private int keyLength; ++ ++ @Param({"true", "false"}) ++ private boolean encryptPublicKey; ++ ++ private byte[][] data; ++ private byte[][] encryptedData; ++ ++ private Cipher encryptCipher; ++ private Cipher decryptCipher; ++ private int index = 0; ++ ++ private int getMaxDataSize(int keyLength, String algorithm) { ++ int dataSize = keyLength / 8; ++ if ("RSA/ECB/PKCS1Padding".equals(algorithm)) { ++ return dataSize - 11; ++ } ++ ++ if ("RSA/ECB/OAEPPadding".equals(algorithm)) { ++ // SHA-1 digestLen is 20 ++ int digestLen = 20; ++ return dataSize - 2 - 2 * digestLen; ++ } ++ return dataSize; ++ } ++ ++ @Setup() ++ public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { ++ setupProvider(); ++ ++ int dataSize = getMaxDataSize(keyLength, algorithm); ++ data = fillRandom(new byte[SET_SIZE][dataSize - 1]); ++ ++ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); ++ kpg.initialize(keyLength); ++ KeyPair keyPair = kpg.generateKeyPair(); ++ ++ encryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ decryptCipher = (prov == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, prov); ++ if (encryptPublicKey || "RSA/ECB/OAEPPadding".equals(algorithm)) { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); ++ decryptCipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); ++ } else { ++ encryptCipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate()); ++ decryptCipher.init(Cipher.DECRYPT_MODE, keyPair.getPublic()); ++ } ++ encryptedData = fillEncrypted(data, encryptCipher); ++ } ++ ++ @Benchmark ++ public byte[] encrypt() throws BadPaddingException, IllegalBlockSizeException { ++ byte[] dataBytes = data[index]; ++ index = (index + 1) % data.length; ++ return encryptCipher.doFinal(dataBytes); ++ } ++ ++ @Benchmark ++ public byte[] decrypt() throws BadPaddingException, IllegalBlockSizeException { ++ byte[] e = encryptedData[index]; ++ index = (index + 1) % encryptedData.length; ++ return decryptCipher.doFinal(e); ++ } ++} +diff --git a/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java b/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java +new file mode 100644 +index 00000000..65bb8bf8 +--- /dev/null ++++ b/jdk/test/micro/org/openeuler/bench/security/openssl/RSAKeyPairGeneratorBenchmark.java +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package org.openeuler.bench.security.openssl; ++ ++import org.openjdk.jmh.annotations.Benchmark; ++import org.openjdk.jmh.annotations.Param; ++import org.openjdk.jmh.annotations.Setup; ++import java.util.concurrent.TimeUnit; ++import org.openjdk.jmh.annotations.Warmup; ++ ++import java.security.KeyPairGenerator; ++ ++@Warmup(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS) ++public class RSAKeyPairGeneratorBenchmark extends BenchmarkBase { ++ @Param({"RSA"}) ++ private String algorithm; ++ ++ @Param({"512", "1024", "2048", "3072", "4096"}) ++ private int keySize; ++ ++ private KeyPairGenerator keyPairGenerator; ++ ++ @Setup ++ public void setUp() throws Exception { ++ setupProvider(); ++ keyPairGenerator = createKeyPairGenerator(); ++ } ++ ++ @Benchmark ++ public void generateKeyPair() throws Exception { ++ keyPairGenerator.initialize(keySize); ++ keyPairGenerator.generateKeyPair(); ++ } ++ ++ private KeyPairGenerator createKeyPairGenerator() throws Exception { ++ if (prov != null) { ++ return KeyPairGenerator.getInstance(algorithm, prov); ++ } ++ return KeyPairGenerator.getInstance(algorithm); ++ } ++} +diff --git a/jdk/test/sun/security/krb5/auto/BasicProc.java b/jdk/test/sun/security/krb5/auto/BasicProc.java +index 50f65eab..a388c76a 100644 +--- a/jdk/test/sun/security/krb5/auto/BasicProc.java ++++ b/jdk/test/sun/security/krb5/auto/BasicProc.java +@@ -297,7 +297,9 @@ public class BasicProc { + Proc p = Proc.create("BasicProc") + .prop("java.security.manager", "") + .prop("sun.net.spi.nameservice.provider.1", "ns,mock") +- .perm(new javax.security.auth.AuthPermission("doAs")); ++ .perm(new javax.security.auth.AuthPermission("doAs")) ++ .perm(new java.util.PropertyPermission( ++ "kae.disableKaeDispose", "read")); + if (lib != null) { + p.env("KRB5_CONFIG", CONF) + .env("KRB5_TRACE", "/dev/stderr") +-- +2.19.0 +