[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/asm/e_padlock-x86.pl b/ap/lib/libssl/openssl-1.1.1o/engines/asm/e_padlock-x86.pl
new file mode 100644
index 0000000..7d5c92d
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/asm/e_padlock-x86.pl
@@ -0,0 +1,629 @@
+#! /usr/bin/env perl
+# Copyright 2011-2023 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# September 2011
+#
+# Assembler helpers for Padlock engine. Compared to original engine
+# version relying on inline assembler and compiled with gcc 3.4.6 it
+# was measured to provide ~100% improvement on misaligned data in ECB
+# mode and ~75% in CBC mode. For aligned data improvement can be
+# observed for short inputs only, e.g. 45% for 64-byte messages in
+# ECB mode, 20% in CBC. Difference in performance for aligned vs.
+# misaligned data depends on misalignment and is either ~1.8x or 2.9x.
+# These are approximately same factors as for hardware support, so
+# there is little reason to rely on the latter. On the contrary, it
+# might actually hurt performance in mixture of aligned and misaligned
+# buffers, because a) if you choose to flip 'align' flag in control
+# word on per-buffer basis, then you'd have to reload key context,
+# which incurs penalty; b) if you choose to set 'align' flag
+# permanently, it limits performance even for aligned data to ~1/2.
+# All above mentioned results were collected on 1.5GHz C7. Nano on the
+# other hand handles unaligned data more gracefully. Depending on
+# algorithm and how unaligned data is, hardware can be up to 70% more
+# efficient than below software alignment procedures, nor does 'align'
+# flag have affect on aligned performance [if has any meaning at all].
+# Therefore suggestion is to unconditionally set 'align' flag on Nano
+# for optimal performance.
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../crypto/perlasm");
+require "x86asm.pl";
+
+$output=pop;
+open STDOUT,">$output";
+
+&asm_init($ARGV[0]);
+
+%PADLOCK_PREFETCH=(ecb=>128, cbc=>64);	# prefetch errata
+$PADLOCK_CHUNK=512;	# Must be a power of 2 larger than 16
+
+$ctx="edx";
+$out="edi";
+$inp="esi";
+$len="ecx";
+$chunk="ebx";
+
+&function_begin_B("padlock_capability");
+	&push	("ebx");
+	&pushf	();
+	&pop	("eax");
+	&mov	("ecx","eax");
+	&xor	("eax",1<<21);
+	&push	("eax");
+	&popf	();
+	&pushf	();
+	&pop	("eax");
+	&xor	("ecx","eax");
+	&xor	("eax","eax");
+	&bt	("ecx",21);
+	&jnc	(&label("noluck"));
+	&cpuid	();
+	&xor	("eax","eax");
+	&cmp	("ebx","0x".unpack("H*",'tneC'));
+	&jne	(&label("zhaoxin"));
+	&cmp	("edx","0x".unpack("H*",'Hrua'));
+	&jne	(&label("noluck"));
+	&cmp	("ecx","0x".unpack("H*",'slua'));
+	&jne	(&label("noluck"));
+	&jmp	(&label("zhaoxinEnd"));
+&set_label("zhaoxin");
+	&cmp	("ebx","0x".unpack("H*",'hS  '));
+	&jne	(&label("noluck"));
+	&cmp	("edx","0x".unpack("H*",'hgna'));
+	&jne	(&label("noluck"));
+	&cmp	("ecx","0x".unpack("H*",'  ia'));
+	&jne	(&label("noluck"));
+&set_label("zhaoxinEnd");
+	&mov	("eax",0xC0000000);
+	&cpuid	();
+	&mov	("edx","eax");
+	&xor	("eax","eax");
+	&cmp	("edx",0xC0000001);
+	&jb	(&label("noluck"));
+	&mov	("eax",1);
+	&cpuid	();
+	&or	("eax",0x0f);
+	&xor	("ebx","ebx");
+	&and	("eax",0x0fff);
+	&cmp	("eax",0x06ff);		# check for Nano
+	&sete	("bl");
+	&mov	("eax",0xC0000001);
+	&push	("ebx");
+	&cpuid	();
+	&pop	("ebx");
+	&mov	("eax","edx");
+	&shl	("ebx",4);		# bit#4 denotes Nano
+	&and	("eax",0xffffffef);
+	&or	("eax","ebx")
+&set_label("noluck");
+	&pop	("ebx");
+	&ret	();
+&function_end_B("padlock_capability")
+
+&function_begin_B("padlock_key_bswap");
+	&mov	("edx",&wparam(0));
+	&mov	("ecx",&DWP(240,"edx"));
+	&inc	("ecx");
+	&shl	("ecx",2);
+&set_label("bswap_loop");
+	&mov	("eax",&DWP(0,"edx"));
+	&bswap	("eax");
+	&mov	(&DWP(0,"edx"),"eax");
+	&lea	("edx",&DWP(4,"edx"));
+	&sub	("ecx",1);
+	&jnz	(&label("bswap_loop"));
+	&ret	();
+&function_end_B("padlock_key_bswap");
+
+# This is heuristic key context tracing. At first one
+# believes that one should use atomic swap instructions,
+# but it's not actually necessary. Point is that if
+# padlock_saved_context was changed by another thread
+# after we've read it and before we compare it with ctx,
+# our key *shall* be reloaded upon thread context switch
+# and we are therefore set in either case...
+&static_label("padlock_saved_context");
+
+&function_begin_B("padlock_verify_context");
+	&mov	($ctx,&wparam(0));
+	&lea	("eax",($::win32 or $::coff) ? &DWP(&label("padlock_saved_context")) :
+		       &DWP(&label("padlock_saved_context")."-".&label("verify_pic_point")));
+	&pushf	();
+	&call	("_padlock_verify_ctx");
+&set_label("verify_pic_point");
+	&lea	("esp",&DWP(4,"esp"));
+	&ret	();
+&function_end_B("padlock_verify_context");
+
+&function_begin_B("_padlock_verify_ctx");
+	&add	("eax",&DWP(0,"esp")) if(!($::win32 or $::coff));# &padlock_saved_context
+	&bt	(&DWP(4,"esp"),30);		# eflags
+	&jnc	(&label("verified"));
+	&cmp	($ctx,&DWP(0,"eax"));
+	&je	(&label("verified"));
+	&pushf	();
+	&popf	();
+&set_label("verified");
+	&mov	(&DWP(0,"eax"),$ctx);
+	&ret	();
+&function_end_B("_padlock_verify_ctx");
+
+&function_begin_B("padlock_reload_key");
+	&pushf	();
+	&popf	();
+	&ret	();
+&function_end_B("padlock_reload_key");
+
+&function_begin_B("padlock_aes_block");
+	&push	("edi");
+	&push	("esi");
+	&push	("ebx");
+	&mov	($out,&wparam(0));		# must be 16-byte aligned
+	&mov	($inp,&wparam(1));		# must be 16-byte aligned
+	&mov	($ctx,&wparam(2));
+	&mov	($len,1);
+	&lea	("ebx",&DWP(32,$ctx));		# key
+	&lea	($ctx,&DWP(16,$ctx));		# control word
+	&data_byte(0xf3,0x0f,0xa7,0xc8);	# rep xcryptecb
+	&pop	("ebx");
+	&pop	("esi");
+	&pop	("edi");
+	&ret	();
+&function_end_B("padlock_aes_block");
+
+sub generate_mode {
+my ($mode,$opcode) = @_;
+# int padlock_$mode_encrypt(void *out, const void *inp,
+#		struct padlock_cipher_data *ctx, size_t len);
+&function_begin("padlock_${mode}_encrypt");
+	&mov	($out,&wparam(0));
+	&mov	($inp,&wparam(1));
+	&mov	($ctx,&wparam(2));
+	&mov	($len,&wparam(3));
+	&test	($ctx,15);
+	&jnz	(&label("${mode}_abort"));
+	&test	($len,15);
+	&jnz	(&label("${mode}_abort"));
+	&lea	("eax",($::win32 or $::coff) ? &DWP(&label("padlock_saved_context")) :
+		       &DWP(&label("padlock_saved_context")."-".&label("${mode}_pic_point")));
+	&pushf	();
+	&cld	();
+	&call	("_padlock_verify_ctx");
+&set_label("${mode}_pic_point");
+	&lea	($ctx,&DWP(16,$ctx));	# control word
+	&xor	("eax","eax");
+					if ($mode eq "ctr32") {
+	&movq	("mm0",&QWP(-16,$ctx));	# load [upper part of] counter
+					} else {
+	&xor	("ebx","ebx");
+	&test	(&DWP(0,$ctx),1<<5);	# align bit in control word
+	&jnz	(&label("${mode}_aligned"));
+	&test	($out,0x0f);
+	&setz	("al");			# !out_misaligned
+	&test	($inp,0x0f);
+	&setz	("bl");			# !inp_misaligned
+	&test	("eax","ebx");
+	&jnz	(&label("${mode}_aligned"));
+	&neg	("eax");
+					}
+	&mov	($chunk,$PADLOCK_CHUNK);
+	&not	("eax");		# out_misaligned?-1:0
+	&lea	("ebp",&DWP(-24,"esp"));
+	&cmp	($len,$chunk);
+	&cmovc	($chunk,$len);		# chunk=len>PADLOCK_CHUNK?PADLOCK_CHUNK:len
+	&and	("eax",$chunk);		# out_misaligned?chunk:0
+	&mov	($chunk,$len);
+	&neg	("eax");
+	&and	($chunk,$PADLOCK_CHUNK-1);	# chunk=len%PADLOCK_CHUNK
+	&lea	("esp",&DWP(0,"eax","ebp"));	# alloca
+	&mov	("eax",$PADLOCK_CHUNK);
+	&cmovz	($chunk,"eax");			# chunk=chunk?:PADLOCK_CHUNK
+	&mov	("eax","ebp");
+	&and	("ebp",-16);
+	&and	("esp",-16);
+	&mov	(&DWP(16,"ebp"),"eax");
+    if ($PADLOCK_PREFETCH{$mode}) {
+	&cmp	($len,$chunk);
+	&ja	(&label("${mode}_loop"));
+	&mov	("eax",$inp);		# check if prefetch crosses page
+	&cmp	("ebp","esp");
+	&cmove	("eax",$out);
+	&add	("eax",$len);
+	&neg	("eax");
+	&and	("eax",0xfff);		# distance to page boundary
+	&cmp	("eax",$PADLOCK_PREFETCH{$mode});
+	&mov	("eax",-$PADLOCK_PREFETCH{$mode});
+	&cmovae	("eax",$chunk);		# mask=distance<prefetch?-prefetch:-1
+	&and	($chunk,"eax");
+	&jz	(&label("${mode}_unaligned_tail"));
+    }
+	&jmp	(&label("${mode}_loop"));
+
+&set_label("${mode}_loop",16);
+	&mov	(&DWP(0,"ebp"),$out);		# save parameters
+	&mov	(&DWP(4,"ebp"),$inp);
+	&mov	(&DWP(8,"ebp"),$len);
+	&mov	($len,$chunk);
+	&mov	(&DWP(12,"ebp"),$chunk);	# chunk
+						if ($mode eq "ctr32") {
+	&mov	("ecx",&DWP(-4,$ctx));
+	&xor	($out,$out);
+	&mov	("eax",&DWP(-8,$ctx));		# borrow $len
+&set_label("${mode}_prepare");
+	&mov	(&DWP(12,"esp",$out),"ecx");
+	&bswap	("ecx");
+	&movq	(&QWP(0,"esp",$out),"mm0");
+	&inc	("ecx");
+	&mov	(&DWP(8,"esp",$out),"eax");
+	&bswap	("ecx");
+	&lea	($out,&DWP(16,$out));
+	&cmp	($out,$chunk);
+	&jb	(&label("${mode}_prepare"));
+
+	&mov	(&DWP(-4,$ctx),"ecx");
+	&lea	($inp,&DWP(0,"esp"));
+	&lea	($out,&DWP(0,"esp"));
+	&mov	($len,$chunk);
+						} else {
+	&test	($out,0x0f);			# out_misaligned
+	&cmovnz	($out,"esp");
+	&test	($inp,0x0f);			# inp_misaligned
+	&jz	(&label("${mode}_inp_aligned"));
+	&shr	($len,2);
+	&data_byte(0xf3,0xa5);			# rep movsl
+	&sub	($out,$chunk);
+	&mov	($len,$chunk);
+	&mov	($inp,$out);
+&set_label("${mode}_inp_aligned");
+						}
+	&lea	("eax",&DWP(-16,$ctx));		# ivp
+	&lea	("ebx",&DWP(16,$ctx));		# key
+	&shr	($len,4);			# len/=AES_BLOCK_SIZE
+	&data_byte(0xf3,0x0f,0xa7,$opcode);	# rep xcrypt*
+						if ($mode !~ /ecb|ctr/) {
+	&movaps	("xmm0",&QWP(0,"eax"));
+	&movaps	(&QWP(-16,$ctx),"xmm0");	# copy [or refresh] iv
+						}
+	&mov	($out,&DWP(0,"ebp"));		# restore parameters
+	&mov	($chunk,&DWP(12,"ebp"));
+						if ($mode eq "ctr32") {
+	&mov	($inp,&DWP(4,"ebp"));
+	&xor	($len,$len);
+&set_label("${mode}_xor");
+	&movups	("xmm1",&QWP(0,$inp,$len));
+	&lea	($len,&DWP(16,$len));
+	&pxor	("xmm1",&QWP(-16,"esp",$len));
+	&movups	(&QWP(-16,$out,$len),"xmm1");
+	&cmp	($len,$chunk);
+	&jb	(&label("${mode}_xor"));
+						} else {
+	&test	($out,0x0f);
+	&jz	(&label("${mode}_out_aligned"));
+	&mov	($len,$chunk);
+	&lea	($inp,&DWP(0,"esp"));
+	&shr	($len,2);
+	&data_byte(0xf3,0xa5);			# rep movsl
+	&sub	($out,$chunk);
+&set_label("${mode}_out_aligned");
+	&mov	($inp,&DWP(4,"ebp"));
+						}
+	&mov	($len,&DWP(8,"ebp"));
+	&add	($out,$chunk);
+	&add	($inp,$chunk);
+	&sub	($len,$chunk);
+	&mov	($chunk,$PADLOCK_CHUNK);
+    if (!$PADLOCK_PREFETCH{$mode}) {
+	&jnz	(&label("${mode}_loop"));
+    } else {
+	&jz	(&label("${mode}_break"));
+	&cmp	($len,$chunk);
+	&jae	(&label("${mode}_loop"));
+
+&set_label("${mode}_unaligned_tail");
+	&xor	("eax","eax");
+	&cmp	("esp","ebp");
+	&cmove	("eax",$len);
+	&sub	("esp","eax");			# alloca
+	&mov	("eax", $out);			# save parameters
+	&mov	($chunk,$len);
+	&shr	($len,2);
+	&lea	($out,&DWP(0,"esp"));
+	&data_byte(0xf3,0xa5);			# rep movsl
+	&mov	($inp,"esp");
+	&mov	($out,"eax");			# restore parameters
+	&mov	($len,$chunk);
+	&jmp	(&label("${mode}_loop"));
+
+&set_label("${mode}_break",16);
+    }
+						if ($mode ne "ctr32") {
+	&cmp	("esp","ebp");
+	&je	(&label("${mode}_done"));
+						}
+	&pxor	("xmm0","xmm0");
+	&lea	("eax",&DWP(0,"esp"));
+&set_label("${mode}_bzero");
+	&movaps	(&QWP(0,"eax"),"xmm0");
+	&lea	("eax",&DWP(16,"eax"));
+	&cmp	("ebp","eax");
+	&ja	(&label("${mode}_bzero"));
+
+&set_label("${mode}_done");
+	&mov	("ebp",&DWP(16,"ebp"));
+	&lea	("esp",&DWP(24,"ebp"));
+						if ($mode ne "ctr32") {
+	&jmp	(&label("${mode}_exit"));
+
+&set_label("${mode}_aligned",16);
+    if ($PADLOCK_PREFETCH{$mode}) {
+	&lea	("ebp",&DWP(0,$inp,$len));
+	&neg	("ebp");
+	&and	("ebp",0xfff);			# distance to page boundary
+	&xor	("eax","eax");
+	&cmp	("ebp",$PADLOCK_PREFETCH{$mode});
+	&mov	("ebp",$PADLOCK_PREFETCH{$mode}-1);
+	&cmovae	("ebp","eax");
+	&and	("ebp",$len);			# remainder
+	&sub	($len,"ebp");
+	&jz	(&label("${mode}_aligned_tail"));
+    }
+	&lea	("eax",&DWP(-16,$ctx));		# ivp
+	&lea	("ebx",&DWP(16,$ctx));		# key
+	&shr	($len,4);			# len/=AES_BLOCK_SIZE
+	&data_byte(0xf3,0x0f,0xa7,$opcode);	# rep xcrypt*
+						if ($mode ne "ecb") {
+	&movaps	("xmm0",&QWP(0,"eax"));
+	&movaps	(&QWP(-16,$ctx),"xmm0");	# copy [or refresh] iv
+						}
+    if ($PADLOCK_PREFETCH{$mode}) {
+	&test	("ebp","ebp");
+	&jz	(&label("${mode}_exit"));
+
+&set_label("${mode}_aligned_tail");
+	&mov	($len,"ebp");
+	&lea	("ebp",&DWP(-24,"esp"));
+	&mov	("esp","ebp");
+	&mov	("eax","ebp");
+	&sub	("esp",$len);
+	&and	("ebp",-16);
+	&and	("esp",-16);
+	&mov	(&DWP(16,"ebp"),"eax");
+	&mov	("eax", $out);			# save parameters
+	&mov	($chunk,$len);
+	&shr	($len,2);
+	&lea	($out,&DWP(0,"esp"));
+	&data_byte(0xf3,0xa5);			# rep movsl
+	&mov	($inp,"esp");
+	&mov	($out,"eax");			# restore parameters
+	&mov	($len,$chunk);
+	&jmp	(&label("${mode}_loop"));
+    }
+&set_label("${mode}_exit");			}
+	&mov	("eax",1);
+	&lea	("esp",&DWP(4,"esp"));		# popf
+	&emms	()				if ($mode eq "ctr32");
+&set_label("${mode}_abort");
+&function_end("padlock_${mode}_encrypt");
+}
+
+&generate_mode("ecb",0xc8);
+&generate_mode("cbc",0xd0);
+&generate_mode("cfb",0xe0);
+&generate_mode("ofb",0xe8);
+&generate_mode("ctr32",0xc8);	# yes, it implements own CTR with ECB opcode,
+				# because hardware CTR was introduced later
+				# and even has errata on certain C7 stepping.
+				# own implementation *always* works, though
+				# ~15% slower than dedicated hardware...
+
+&function_begin_B("padlock_xstore");
+	&push	("edi");
+	&mov	("edi",&wparam(0));
+	&mov	("edx",&wparam(1));
+	&data_byte(0x0f,0xa7,0xc0);		# xstore
+	&pop	("edi");
+	&ret	();
+&function_end_B("padlock_xstore");
+
+&function_begin_B("_win32_segv_handler");
+	&mov	("eax",1);			# ExceptionContinueSearch
+	&mov	("edx",&wparam(0));		# *ExceptionRecord
+	&mov	("ecx",&wparam(2));		# *ContextRecord
+	&cmp	(&DWP(0,"edx"),0xC0000005)	# ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION
+	&jne	(&label("ret"));
+	&add	(&DWP(184,"ecx"),4);		# skip over rep sha*
+	&mov	("eax",0);			# ExceptionContinueExecution
+&set_label("ret");
+	&ret	();
+&function_end_B("_win32_segv_handler");
+&safeseh("_win32_segv_handler")			if ($::win32);
+
+&function_begin_B("padlock_sha1_oneshot");
+	&push	("edi");
+	&push	("esi");
+	&xor	("eax","eax");
+	&mov	("edi",&wparam(0));
+	&mov	("esi",&wparam(1));
+	&mov	("ecx",&wparam(2));
+    if ($::win32 or $::coff) {
+    	&push	(&::islabel("_win32_segv_handler"));
+	&data_byte(0x64,0xff,0x30);		# push	%fs:(%eax)
+	&data_byte(0x64,0x89,0x20);		# mov	%esp,%fs:(%eax)
+    }
+	&mov	("edx","esp");			# put aside %esp
+	&add	("esp",-128);			# 32 is enough but spec says 128
+	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context
+	&and	("esp",-16);
+	&mov	("eax",&DWP(16,"edi"));
+	&movaps	(&QWP(0,"esp"),"xmm0");
+	&mov	("edi","esp");
+	&mov	(&DWP(16,"esp"),"eax");
+	&xor	("eax","eax");
+	&data_byte(0xf3,0x0f,0xa6,0xc8);	# rep xsha1
+	&movaps	("xmm0",&QWP(0,"esp"));
+	&mov	("eax",&DWP(16,"esp"));
+	&mov	("esp","edx");			# restore %esp
+    if ($::win32 or $::coff) {
+	&data_byte(0x64,0x8f,0x05,0,0,0,0);	# pop	%fs:0
+	&lea	("esp",&DWP(4,"esp"));
+    }
+	&mov	("edi",&wparam(0));
+	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context
+	&mov	(&DWP(16,"edi"),"eax");
+	&pop	("esi");
+	&pop	("edi");
+	&ret	();
+&function_end_B("padlock_sha1_oneshot");
+
+&function_begin_B("padlock_sha1_blocks");
+	&push	("edi");
+	&push	("esi");
+	&mov	("edi",&wparam(0));
+	&mov	("esi",&wparam(1));
+	&mov	("edx","esp");			# put aside %esp
+	&mov	("ecx",&wparam(2));
+	&add	("esp",-128);
+	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context
+	&and	("esp",-16);
+	&mov	("eax",&DWP(16,"edi"));
+	&movaps	(&QWP(0,"esp"),"xmm0");
+	&mov	("edi","esp");
+	&mov	(&DWP(16,"esp"),"eax");
+	&mov	("eax",-1);
+	&data_byte(0xf3,0x0f,0xa6,0xc8);	# rep xsha1
+	&movaps	("xmm0",&QWP(0,"esp"));
+	&mov	("eax",&DWP(16,"esp"));
+	&mov	("esp","edx");			# restore %esp
+	&mov	("edi",&wparam(0));
+	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context
+	&mov	(&DWP(16,"edi"),"eax");
+ 	&pop	("esi");
+	&pop	("edi");
+	&ret	();
+&function_end_B("padlock_sha1_blocks");
+
+&function_begin_B("padlock_sha256_oneshot");
+	&push	("edi");
+	&push	("esi");
+	&xor	("eax","eax");
+	&mov	("edi",&wparam(0));
+	&mov	("esi",&wparam(1));
+	&mov	("ecx",&wparam(2));
+    if ($::win32 or $::coff) {
+    	&push	(&::islabel("_win32_segv_handler"));
+	&data_byte(0x64,0xff,0x30);		# push	%fs:(%eax)
+	&data_byte(0x64,0x89,0x20);		# mov	%esp,%fs:(%eax)
+    }
+	&mov	("edx","esp");			# put aside %esp
+	&add	("esp",-128);
+	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context
+	&and	("esp",-16);
+	&movups	("xmm1",&QWP(16,"edi"));
+	&movaps	(&QWP(0,"esp"),"xmm0");
+	&mov	("edi","esp");
+	&movaps	(&QWP(16,"esp"),"xmm1");
+	&xor	("eax","eax");
+	&data_byte(0xf3,0x0f,0xa6,0xd0);	# rep xsha256
+	&movaps	("xmm0",&QWP(0,"esp"));
+	&movaps	("xmm1",&QWP(16,"esp"));
+	&mov	("esp","edx");			# restore %esp
+    if ($::win32 or $::coff) {
+	&data_byte(0x64,0x8f,0x05,0,0,0,0);	# pop	%fs:0
+	&lea	("esp",&DWP(4,"esp"));
+    }
+	&mov	("edi",&wparam(0));
+	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context
+	&movups	(&QWP(16,"edi"),"xmm1");
+	&pop	("esi");
+	&pop	("edi");
+	&ret	();
+&function_end_B("padlock_sha256_oneshot");
+
+&function_begin_B("padlock_sha256_blocks");
+	&push	("edi");
+	&push	("esi");
+	&mov	("edi",&wparam(0));
+	&mov	("esi",&wparam(1));
+	&mov	("ecx",&wparam(2));
+	&mov	("edx","esp");			# put aside %esp
+	&add	("esp",-128);
+	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context
+	&and	("esp",-16);
+	&movups	("xmm1",&QWP(16,"edi"));
+	&movaps	(&QWP(0,"esp"),"xmm0");
+	&mov	("edi","esp");
+	&movaps	(&QWP(16,"esp"),"xmm1");
+	&mov	("eax",-1);
+	&data_byte(0xf3,0x0f,0xa6,0xd0);	# rep xsha256
+	&movaps	("xmm0",&QWP(0,"esp"));
+	&movaps	("xmm1",&QWP(16,"esp"));
+	&mov	("esp","edx");			# restore %esp
+	&mov	("edi",&wparam(0));
+	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context
+	&movups	(&QWP(16,"edi"),"xmm1");
+	&pop	("esi");
+	&pop	("edi");
+	&ret	();
+&function_end_B("padlock_sha256_blocks");
+
+&function_begin_B("padlock_sha512_blocks");
+	&push	("edi");
+	&push	("esi");
+	&mov	("edi",&wparam(0));
+	&mov	("esi",&wparam(1));
+	&mov	("ecx",&wparam(2));
+	&mov	("edx","esp");			# put aside %esp
+	&add	("esp",-128);
+	&movups	("xmm0",&QWP(0,"edi"));		# copy-in context
+	&and	("esp",-16);
+	&movups	("xmm1",&QWP(16,"edi"));
+	&movups	("xmm2",&QWP(32,"edi"));
+	&movups	("xmm3",&QWP(48,"edi"));
+	&movaps	(&QWP(0,"esp"),"xmm0");
+	&mov	("edi","esp");
+	&movaps	(&QWP(16,"esp"),"xmm1");
+	&movaps	(&QWP(32,"esp"),"xmm2");
+	&movaps	(&QWP(48,"esp"),"xmm3");
+	&data_byte(0xf3,0x0f,0xa6,0xe0);	# rep xsha512
+	&movaps	("xmm0",&QWP(0,"esp"));
+	&movaps	("xmm1",&QWP(16,"esp"));
+	&movaps	("xmm2",&QWP(32,"esp"));
+	&movaps	("xmm3",&QWP(48,"esp"));
+	&mov	("esp","edx");			# restore %esp
+	&mov	("edi",&wparam(0));
+	&movups	(&QWP(0,"edi"),"xmm0");		# copy-out context
+	&movups	(&QWP(16,"edi"),"xmm1");
+	&movups	(&QWP(32,"edi"),"xmm2");
+	&movups	(&QWP(48,"edi"),"xmm3");
+	&pop	("esi");
+	&pop	("edi");
+	&ret	();
+&function_end_B("padlock_sha512_blocks");
+
+&asciz	("VIA Padlock x86 module, CRYPTOGAMS by <appro\@openssl.org>");
+&align	(16);
+
+&dataseg();
+# Essentially this variable belongs in thread local storage.
+# Having this variable global on the other hand can only cause
+# few bogus key reloads [if any at all on signle-CPU system],
+# so we accept the penalty...
+&set_label("padlock_saved_context",4);
+&data_word(0);
+
+&asm_finish();
+
+close STDOUT;
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/asm/e_padlock-x86_64.pl b/ap/lib/libssl/openssl-1.1.1o/engines/asm/e_padlock-x86_64.pl
new file mode 100644
index 0000000..f60bec1
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/asm/e_padlock-x86_64.pl
@@ -0,0 +1,585 @@
+#! /usr/bin/env perl
+# Copyright 2011-2023 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# September 2011
+#
+# Assembler helpers for Padlock engine. See even e_padlock-x86.pl for
+# details.
+
+$flavour = shift;
+$output  = shift;
+if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+
+$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../crypto/perlasm/x86_64-xlate.pl" and -f $xlate) or
+die "can't locate x86_64-xlate.pl";
+
+open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
+*STDOUT=*OUT;
+
+$code=".text\n";
+
+%PADLOCK_PREFETCH=(ecb=>128, cbc=>64, ctr32=>32);	# prefetch errata
+$PADLOCK_CHUNK=512;	# Must be a power of 2 between 32 and 2^20
+
+$ctx="%rdx";
+$out="%rdi";
+$inp="%rsi";
+$len="%rcx";
+$chunk="%rbx";
+
+($arg1,$arg2,$arg3,$arg4)=$win64?("%rcx","%rdx","%r8", "%r9") : # Win64 order
+                                 ("%rdi","%rsi","%rdx","%rcx"); # Unix order
+
+$code.=<<___;
+.globl	padlock_capability
+.type	padlock_capability,\@abi-omnipotent
+.align	16
+padlock_capability:
+	mov	%rbx,%r8
+	xor	%eax,%eax
+	cpuid
+	xor	%eax,%eax
+	cmp	\$`"0x".unpack("H*",'tneC')`,%ebx
+	jne	.Lzhaoxin
+	cmp	\$`"0x".unpack("H*",'Hrua')`,%edx
+	jne	.Lnoluck
+	cmp	\$`"0x".unpack("H*",'slua')`,%ecx
+	jne	.Lnoluck
+	jmp	.LzhaoxinEnd
+.Lzhaoxin:
+	cmp	\$`"0x".unpack("H*",'hS  ')`,%ebx
+	jne	.Lnoluck
+	cmp	\$`"0x".unpack("H*",'hgna')`,%edx
+	jne	.Lnoluck
+	cmp	\$`"0x".unpack("H*",'  ia')`,%ecx
+	jne	.Lnoluck
+.LzhaoxinEnd:
+	mov	\$0xC0000000,%eax
+	cpuid
+	mov	%eax,%edx
+	xor	%eax,%eax
+	cmp	\$0xC0000001,%edx
+	jb	.Lnoluck
+	mov	\$0xC0000001,%eax
+	cpuid
+	mov	%edx,%eax
+	and	\$0xffffffef,%eax
+	or	\$0x10,%eax		# set Nano bit#4
+.Lnoluck:
+	mov	%r8,%rbx
+	ret
+.size	padlock_capability,.-padlock_capability
+
+.globl	padlock_key_bswap
+.type	padlock_key_bswap,\@abi-omnipotent,0
+.align	16
+padlock_key_bswap:
+	mov	240($arg1),%edx
+	inc	%edx
+	shl	\$2,%edx
+.Lbswap_loop:
+	mov	($arg1),%eax
+	bswap	%eax
+	mov	%eax,($arg1)
+	lea	4($arg1),$arg1
+	sub	\$1,%edx
+	jnz	.Lbswap_loop
+	ret
+.size	padlock_key_bswap,.-padlock_key_bswap
+
+.globl	padlock_verify_context
+.type	padlock_verify_context,\@abi-omnipotent
+.align	16
+padlock_verify_context:
+	mov	$arg1,$ctx
+	pushf
+	lea	.Lpadlock_saved_context(%rip),%rax
+	call	_padlock_verify_ctx
+	lea	8(%rsp),%rsp
+	ret
+.size	padlock_verify_context,.-padlock_verify_context
+
+.type	_padlock_verify_ctx,\@abi-omnipotent
+.align	16
+_padlock_verify_ctx:
+	mov	8(%rsp),%r8
+	bt	\$30,%r8
+	jnc	.Lverified
+	cmp	(%rax),$ctx
+	je	.Lverified
+	pushf
+	popf
+.Lverified:
+	mov	$ctx,(%rax)
+	ret
+.size	_padlock_verify_ctx,.-_padlock_verify_ctx
+
+.globl	padlock_reload_key
+.type	padlock_reload_key,\@abi-omnipotent
+.align	16
+padlock_reload_key:
+	pushf
+	popf
+	ret
+.size	padlock_reload_key,.-padlock_reload_key
+
+.globl	padlock_aes_block
+.type	padlock_aes_block,\@function,3
+.align	16
+padlock_aes_block:
+	mov	%rbx,%r8
+	mov	\$1,$len
+	lea	32($ctx),%rbx		# key
+	lea	16($ctx),$ctx		# control word
+	.byte	0xf3,0x0f,0xa7,0xc8	# rep xcryptecb
+	mov	%r8,%rbx
+	ret
+.size	padlock_aes_block,.-padlock_aes_block
+
+.globl	padlock_xstore
+.type	padlock_xstore,\@function,2
+.align	16
+padlock_xstore:
+	mov	%esi,%edx
+	.byte	0x0f,0xa7,0xc0		# xstore
+	ret
+.size	padlock_xstore,.-padlock_xstore
+
+.globl	padlock_sha1_oneshot
+.type	padlock_sha1_oneshot,\@function,3
+.align	16
+padlock_sha1_oneshot:
+	mov	%rdx,%rcx
+	mov	%rdi,%rdx		# put aside %rdi
+	movups	(%rdi),%xmm0		# copy-in context
+	sub	\$128+8,%rsp
+	mov	16(%rdi),%eax
+	movaps	%xmm0,(%rsp)
+	mov	%rsp,%rdi
+	mov	%eax,16(%rsp)
+	xor	%rax,%rax
+	.byte	0xf3,0x0f,0xa6,0xc8	# rep xsha1
+	movaps	(%rsp),%xmm0
+	mov	16(%rsp),%eax
+	add	\$128+8,%rsp
+	movups	%xmm0,(%rdx)		# copy-out context
+	mov	%eax,16(%rdx)
+	ret
+.size	padlock_sha1_oneshot,.-padlock_sha1_oneshot
+
+.globl	padlock_sha1_blocks
+.type	padlock_sha1_blocks,\@function,3
+.align	16
+padlock_sha1_blocks:
+	mov	%rdx,%rcx
+	mov	%rdi,%rdx		# put aside %rdi
+	movups	(%rdi),%xmm0		# copy-in context
+	sub	\$128+8,%rsp
+	mov	16(%rdi),%eax
+	movaps	%xmm0,(%rsp)
+	mov	%rsp,%rdi
+	mov	%eax,16(%rsp)
+	mov	\$-1,%rax
+	.byte	0xf3,0x0f,0xa6,0xc8	# rep xsha1
+	movaps	(%rsp),%xmm0
+	mov	16(%rsp),%eax
+	add	\$128+8,%rsp
+	movups	%xmm0,(%rdx)		# copy-out context
+	mov	%eax,16(%rdx)
+	ret
+.size	padlock_sha1_blocks,.-padlock_sha1_blocks
+
+.globl	padlock_sha256_oneshot
+.type	padlock_sha256_oneshot,\@function,3
+.align	16
+padlock_sha256_oneshot:
+	mov	%rdx,%rcx
+	mov	%rdi,%rdx		# put aside %rdi
+	movups	(%rdi),%xmm0		# copy-in context
+	sub	\$128+8,%rsp
+	movups	16(%rdi),%xmm1
+	movaps	%xmm0,(%rsp)
+	mov	%rsp,%rdi
+	movaps	%xmm1,16(%rsp)
+	xor	%rax,%rax
+	.byte	0xf3,0x0f,0xa6,0xd0	# rep xsha256
+	movaps	(%rsp),%xmm0
+	movaps	16(%rsp),%xmm1
+	add	\$128+8,%rsp
+	movups	%xmm0,(%rdx)		# copy-out context
+	movups	%xmm1,16(%rdx)
+	ret
+.size	padlock_sha256_oneshot,.-padlock_sha256_oneshot
+
+.globl	padlock_sha256_blocks
+.type	padlock_sha256_blocks,\@function,3
+.align	16
+padlock_sha256_blocks:
+	mov	%rdx,%rcx
+	mov	%rdi,%rdx		# put aside %rdi
+	movups	(%rdi),%xmm0		# copy-in context
+	sub	\$128+8,%rsp
+	movups	16(%rdi),%xmm1
+	movaps	%xmm0,(%rsp)
+	mov	%rsp,%rdi
+	movaps	%xmm1,16(%rsp)
+	mov	\$-1,%rax
+	.byte	0xf3,0x0f,0xa6,0xd0	# rep xsha256
+	movaps	(%rsp),%xmm0
+	movaps	16(%rsp),%xmm1
+	add	\$128+8,%rsp
+	movups	%xmm0,(%rdx)		# copy-out context
+	movups	%xmm1,16(%rdx)
+	ret
+.size	padlock_sha256_blocks,.-padlock_sha256_blocks
+
+.globl	padlock_sha512_blocks
+.type	padlock_sha512_blocks,\@function,3
+.align	16
+padlock_sha512_blocks:
+	mov	%rdx,%rcx
+	mov	%rdi,%rdx		# put aside %rdi
+	movups	(%rdi),%xmm0		# copy-in context
+	sub	\$128+8,%rsp
+	movups	16(%rdi),%xmm1
+	movups	32(%rdi),%xmm2
+	movups	48(%rdi),%xmm3
+	movaps	%xmm0,(%rsp)
+	mov	%rsp,%rdi
+	movaps	%xmm1,16(%rsp)
+	movaps	%xmm2,32(%rsp)
+	movaps	%xmm3,48(%rsp)
+	.byte	0xf3,0x0f,0xa6,0xe0	# rep xha512
+	movaps	(%rsp),%xmm0
+	movaps	16(%rsp),%xmm1
+	movaps	32(%rsp),%xmm2
+	movaps	48(%rsp),%xmm3
+	add	\$128+8,%rsp
+	movups	%xmm0,(%rdx)		# copy-out context
+	movups	%xmm1,16(%rdx)
+	movups	%xmm2,32(%rdx)
+	movups	%xmm3,48(%rdx)
+	ret
+.size	padlock_sha512_blocks,.-padlock_sha512_blocks
+___
+
+sub generate_mode {
+my ($mode,$opcode) = @_;
+# int padlock_$mode_encrypt(void *out, const void *inp,
+#		struct padlock_cipher_data *ctx, size_t len);
+$code.=<<___;
+.globl	padlock_${mode}_encrypt
+.type	padlock_${mode}_encrypt,\@function,4
+.align	16
+padlock_${mode}_encrypt:
+	push	%rbp
+	push	%rbx
+
+	xor	%eax,%eax
+	test	\$15,$ctx
+	jnz	.L${mode}_abort
+	test	\$15,$len
+	jnz	.L${mode}_abort
+	lea	.Lpadlock_saved_context(%rip),%rax
+	pushf
+	cld
+	call	_padlock_verify_ctx
+	lea	16($ctx),$ctx		# control word
+	xor	%eax,%eax
+	xor	%ebx,%ebx
+	testl	\$`1<<5`,($ctx)		# align bit in control word
+	jnz	.L${mode}_aligned
+	test	\$0x0f,$out
+	setz	%al			# !out_misaligned
+	test	\$0x0f,$inp
+	setz	%bl			# !inp_misaligned
+	test	%ebx,%eax
+	jnz	.L${mode}_aligned
+	neg	%rax
+	mov	\$$PADLOCK_CHUNK,$chunk
+	not	%rax			# out_misaligned?-1:0
+	lea	(%rsp),%rbp
+	cmp	$chunk,$len
+	cmovc	$len,$chunk		# chunk=len>PADLOCK_CHUNK?PADLOCK_CHUNK:len
+	and	$chunk,%rax		# out_misaligned?chunk:0
+	mov	$len,$chunk
+	neg	%rax
+	and	\$$PADLOCK_CHUNK-1,$chunk	# chunk%=PADLOCK_CHUNK
+	lea	(%rax,%rbp),%rsp
+	mov	\$$PADLOCK_CHUNK,%rax
+	cmovz	%rax,$chunk			# chunk=chunk?:PADLOCK_CHUNK
+___
+$code.=<<___				if ($mode eq "ctr32");
+.L${mode}_reenter:
+	mov	-4($ctx),%eax		# pull 32-bit counter
+	bswap	%eax
+	neg	%eax
+	and	\$`$PADLOCK_CHUNK/16-1`,%eax
+	mov	\$$PADLOCK_CHUNK,$chunk
+	shl	\$4,%eax
+	cmovz	$chunk,%rax
+	cmp	%rax,$len
+	cmova	%rax,$chunk		# don't let counter cross PADLOCK_CHUNK
+	cmovbe	$len,$chunk
+___
+$code.=<<___				if ($PADLOCK_PREFETCH{$mode});
+	cmp	$chunk,$len
+	ja	.L${mode}_loop
+	mov	$inp,%rax		# check if prefetch crosses page
+	cmp	%rsp,%rbp
+	cmove	$out,%rax
+	add	$len,%rax
+	neg	%rax
+	and	\$0xfff,%rax		# distance to page boundary
+	cmp	\$$PADLOCK_PREFETCH{$mode},%rax
+	mov	\$-$PADLOCK_PREFETCH{$mode},%rax
+	cmovae	$chunk,%rax		# mask=distance<prefetch?-prefetch:-1
+	and	%rax,$chunk
+	jz	.L${mode}_unaligned_tail
+___
+$code.=<<___;
+	jmp	.L${mode}_loop
+.align	16
+.L${mode}_loop:
+	cmp	$len,$chunk		# ctr32 artefact
+	cmova	$len,$chunk		# ctr32 artefact
+	mov	$out,%r8		# save parameters
+	mov	$inp,%r9
+	mov	$len,%r10
+	mov	$chunk,$len
+	mov	$chunk,%r11
+	test	\$0x0f,$out		# out_misaligned
+	cmovnz	%rsp,$out
+	test	\$0x0f,$inp		# inp_misaligned
+	jz	.L${mode}_inp_aligned
+	shr	\$3,$len
+	.byte	0xf3,0x48,0xa5		# rep movsq
+	sub	$chunk,$out
+	mov	$chunk,$len
+	mov	$out,$inp
+.L${mode}_inp_aligned:
+	lea	-16($ctx),%rax		# ivp
+	lea	16($ctx),%rbx		# key
+	shr	\$4,$len
+	.byte	0xf3,0x0f,0xa7,$opcode	# rep xcrypt*
+___
+$code.=<<___				if ($mode !~ /ecb|ctr/);
+	movdqa	(%rax),%xmm0
+	movdqa	%xmm0,-16($ctx)		# copy [or refresh] iv
+___
+$code.=<<___				if ($mode eq "ctr32");
+	mov	-4($ctx),%eax		# pull 32-bit counter
+	test	\$0xffff0000,%eax
+	jnz	.L${mode}_no_carry
+	bswap	%eax
+	add	\$0x10000,%eax
+	bswap	%eax
+	mov	%eax,-4($ctx)
+.L${mode}_no_carry:
+___
+$code.=<<___;
+	mov	%r8,$out		# restore parameters
+	mov	%r11,$chunk
+	test	\$0x0f,$out
+	jz	.L${mode}_out_aligned
+	mov	$chunk,$len
+	lea	(%rsp),$inp
+	shr	\$3,$len
+	.byte	0xf3,0x48,0xa5		# rep movsq
+	sub	$chunk,$out
+.L${mode}_out_aligned:
+	mov	%r9,$inp
+	mov	%r10,$len
+	add	$chunk,$out
+	add	$chunk,$inp
+	sub	$chunk,$len
+	mov	\$$PADLOCK_CHUNK,$chunk
+___
+					if (!$PADLOCK_PREFETCH{$mode}) {
+$code.=<<___;
+	jnz	.L${mode}_loop
+___
+					} else {
+$code.=<<___;
+	jz	.L${mode}_break
+	cmp	$chunk,$len
+	jae	.L${mode}_loop
+___
+$code.=<<___				if ($mode eq "ctr32");
+	mov	$len,$chunk
+	mov	$inp,%rax		# check if prefetch crosses page
+	cmp	%rsp,%rbp
+	cmove	$out,%rax
+	add	$len,%rax
+	neg	%rax
+	and	\$0xfff,%rax		# distance to page boundary
+	cmp	\$$PADLOCK_PREFETCH{$mode},%rax
+	mov	\$-$PADLOCK_PREFETCH{$mode},%rax
+	cmovae	$chunk,%rax
+	and	%rax,$chunk
+	jnz	.L${mode}_loop
+___
+$code.=<<___;
+.L${mode}_unaligned_tail:
+	xor	%eax,%eax
+	cmp	%rsp,%rbp
+	cmove	$len,%rax
+	mov	$out,%r8		# save parameters
+	mov	$len,$chunk
+	sub	%rax,%rsp		# alloca
+	shr	\$3,$len
+	lea	(%rsp),$out
+	.byte	0xf3,0x48,0xa5		# rep movsq
+	mov	%rsp,$inp
+	mov	%r8, $out		# restore parameters
+	mov	$chunk,$len
+	jmp	.L${mode}_loop
+.align	16
+.L${mode}_break:
+___
+					}
+$code.=<<___;
+	cmp	%rbp,%rsp
+	je	.L${mode}_done
+
+	pxor	%xmm0,%xmm0
+	lea	(%rsp),%rax
+.L${mode}_bzero:
+	movaps	%xmm0,(%rax)
+	lea	16(%rax),%rax
+	cmp	%rax,%rbp
+	ja	.L${mode}_bzero
+
+.L${mode}_done:
+	lea	(%rbp),%rsp
+	jmp	.L${mode}_exit
+
+.align	16
+.L${mode}_aligned:
+___
+$code.=<<___				if ($mode eq "ctr32");
+	mov	-4($ctx),%eax		# pull 32-bit counter
+	bswap	%eax
+	neg	%eax
+	and	\$0xffff,%eax
+	mov	\$`16*0x10000`,$chunk
+	shl	\$4,%eax
+	cmovz	$chunk,%rax
+	cmp	%rax,$len
+	cmova	%rax,$chunk		# don't let counter cross 2^16
+	cmovbe	$len,$chunk
+	jbe	.L${mode}_aligned_skip
+
+.L${mode}_aligned_loop:
+	mov	$len,%r10		# save parameters
+	mov	$chunk,$len
+	mov	$chunk,%r11
+
+	lea	-16($ctx),%rax		# ivp
+	lea	16($ctx),%rbx		# key
+	shr	\$4,$len		# len/=AES_BLOCK_SIZE
+	.byte	0xf3,0x0f,0xa7,$opcode	# rep xcrypt*
+
+	mov	-4($ctx),%eax		# pull 32-bit counter
+	bswap	%eax
+	add	\$0x10000,%eax
+	bswap	%eax
+	mov	%eax,-4($ctx)
+
+	mov	%r10,$len		# restore parameters
+	sub	%r11,$len
+	mov	\$`16*0x10000`,$chunk
+	jz	.L${mode}_exit
+	cmp	$chunk,$len
+	jae	.L${mode}_aligned_loop
+
+.L${mode}_aligned_skip:
+___
+$code.=<<___				if ($PADLOCK_PREFETCH{$mode});
+	lea	($inp,$len),%rbp
+	neg	%rbp
+	and	\$0xfff,%rbp		# distance to page boundary
+	xor	%eax,%eax
+	cmp	\$$PADLOCK_PREFETCH{$mode},%rbp
+	mov	\$$PADLOCK_PREFETCH{$mode}-1,%rbp
+	cmovae	%rax,%rbp
+	and	$len,%rbp		# remainder
+	sub	%rbp,$len
+	jz	.L${mode}_aligned_tail
+___
+$code.=<<___;
+	lea	-16($ctx),%rax		# ivp
+	lea	16($ctx),%rbx		# key
+	shr	\$4,$len		# len/=AES_BLOCK_SIZE
+	.byte	0xf3,0x0f,0xa7,$opcode	# rep xcrypt*
+___
+$code.=<<___				if ($mode !~ /ecb|ctr/);
+	movdqa	(%rax),%xmm0
+	movdqa	%xmm0,-16($ctx)		# copy [or refresh] iv
+___
+$code.=<<___				if ($PADLOCK_PREFETCH{$mode});
+	test	%rbp,%rbp		# check remainder
+	jz	.L${mode}_exit
+
+.L${mode}_aligned_tail:
+	mov	$out,%r8
+	mov	%rbp,$chunk
+	mov	%rbp,$len
+	lea	(%rsp),%rbp
+	sub	$len,%rsp
+	shr	\$3,$len
+	lea	(%rsp),$out
+	.byte	0xf3,0x48,0xa5		# rep movsq
+	lea	(%r8),$out
+	lea	(%rsp),$inp
+	mov	$chunk,$len
+	jmp	.L${mode}_loop
+___
+$code.=<<___;
+.L${mode}_exit:
+	mov	\$1,%eax
+	lea	8(%rsp),%rsp
+.L${mode}_abort:
+	pop	%rbx
+	pop	%rbp
+	ret
+.size	padlock_${mode}_encrypt,.-padlock_${mode}_encrypt
+___
+}
+
+&generate_mode("ecb",0xc8);
+&generate_mode("cbc",0xd0);
+&generate_mode("cfb",0xe0);
+&generate_mode("ofb",0xe8);
+&generate_mode("ctr32",0xd8);	# all 64-bit CPUs have working CTR...
+
+$code.=<<___;
+.asciz	"VIA Padlock x86_64 module, CRYPTOGAMS by <appro\@openssl.org>"
+.align	16
+.data
+.align	8
+.Lpadlock_saved_context:
+	.quad	0
+___
+$code =~ s/\`([^\`]*)\`/eval($1)/gem;
+
+print $code;
+
+close STDOUT;
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/build.info b/ap/lib/libssl/openssl-1.1.1o/engines/build.info
new file mode 100644
index 0000000..1db7719
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/build.info
@@ -0,0 +1,46 @@
+IF[{- !$disabled{"engine"} -}]
+
+  IF[{- $disabled{"dynamic-engine"} -}]
+    LIBS=../libcrypto
+    IF[{- !$disabled{hw} && !$disabled{'hw-padlock'} -}]
+      SOURCE[../libcrypto]= e_padlock.c {- $target{padlock_asm_src} -}
+    ENDIF
+    IF[{- !$disabled{capieng} -}]
+      SOURCE[../libcrypto]=e_capi.c
+    ENDIF
+    IF[{- !$disabled{afalgeng} -}]
+      SOURCE[../libcrypto]=e_afalg.c
+    ENDIF
+  ELSE
+    IF[{- !$disabled{hw} && !$disabled{'hw-padlock'} -}]
+      ENGINES=padlock
+      SOURCE[padlock]=e_padlock.c {- $target{padlock_asm_src} -}
+      DEPEND[padlock]=../libcrypto
+      INCLUDE[padlock]=../include
+    ENDIF
+    IF[{- !$disabled{capieng} -}]
+      ENGINES=capi
+      SOURCE[capi]=e_capi.c
+      DEPEND[capi]=../libcrypto
+      INCLUDE[capi]=../include
+    ENDIF
+    IF[{- !$disabled{afalgeng} -}]
+      ENGINES=afalg
+      SOURCE[afalg]=e_afalg.c
+      DEPEND[afalg]=../libcrypto
+      INCLUDE[afalg]= ../include
+    ENDIF
+
+    ENGINES_NO_INST=ossltest dasync
+    SOURCE[dasync]=e_dasync.c
+    DEPEND[dasync]=../libcrypto
+    INCLUDE[dasync]=../include
+    SOURCE[ossltest]=e_ossltest.c
+    DEPEND[ossltest]=../libcrypto
+    INCLUDE[ossltest]=../include
+  ENDIF
+
+  GENERATE[e_padlock-x86.s]=asm/e_padlock-x86.pl \
+        $(PERLASM_SCHEME) $(LIB_CFLAGS) $(LIB_CPPFLAGS) $(PROCESSOR)
+  GENERATE[e_padlock-x86_64.s]=asm/e_padlock-x86_64.pl $(PERLASM_SCHEME)
+ENDIF
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.c b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.c
new file mode 100644
index 0000000..2d16c13
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.c
@@ -0,0 +1,861 @@
+/*
+ * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Required for vmsplice */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/engine.h>
+#include <openssl/async.h>
+#include <openssl/err.h>
+#include "internal/nelem.h"
+
+#include <sys/socket.h>
+#include <linux/version.h>
+#define K_MAJ   4
+#define K_MIN1  1
+#define K_MIN2  0
+#if LINUX_VERSION_CODE < KERNEL_VERSION(K_MAJ, K_MIN1, K_MIN2) || \
+    !defined(AF_ALG)
+# ifndef PEDANTIC
+#  warning "AFALG ENGINE requires Kernel Headers >= 4.1.0"
+#  warning "Skipping Compilation of AFALG engine"
+# endif
+void engine_load_afalg_int(void);
+void engine_load_afalg_int(void)
+{
+}
+#else
+
+# include <linux/if_alg.h>
+# include <fcntl.h>
+# include <sys/utsname.h>
+
+# include <linux/aio_abi.h>
+# include <sys/syscall.h>
+# include <errno.h>
+
+# include "e_afalg.h"
+# include "e_afalg_err.c"
+
+# ifndef SOL_ALG
+#  define SOL_ALG 279
+# endif
+
+# ifdef ALG_ZERO_COPY
+#  ifndef SPLICE_F_GIFT
+#   define SPLICE_F_GIFT    (0x08)
+#  endif
+# endif
+
+# define ALG_AES_IV_LEN 16
+# define ALG_IV_LEN(len) (sizeof(struct af_alg_iv) + (len))
+# define ALG_OP_TYPE     unsigned int
+# define ALG_OP_LEN      (sizeof(ALG_OP_TYPE))
+
+# ifdef OPENSSL_NO_DYNAMIC_ENGINE
+void engine_load_afalg_int(void);
+# endif
+
+/* Local Linkage Functions */
+static int afalg_init_aio(afalg_aio *aio);
+static int afalg_fin_cipher_aio(afalg_aio *ptr, int sfd,
+                                unsigned char *buf, size_t len);
+static int afalg_create_sk(afalg_ctx *actx, const char *ciphertype,
+                                const char *ciphername);
+static int afalg_destroy(ENGINE *e);
+static int afalg_init(ENGINE *e);
+static int afalg_finish(ENGINE *e);
+static const EVP_CIPHER *afalg_aes_cbc(int nid);
+static cbc_handles *get_cipher_handle(int nid);
+static int afalg_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+                         const int **nids, int nid);
+static int afalg_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                             const unsigned char *iv, int enc);
+static int afalg_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                           const unsigned char *in, size_t inl);
+static int afalg_cipher_cleanup(EVP_CIPHER_CTX *ctx);
+static int afalg_chk_platform(void);
+
+/* Engine Id and Name */
+static const char *engine_afalg_id = "afalg";
+static const char *engine_afalg_name = "AFALG engine support";
+
+static int afalg_cipher_nids[] = {
+    NID_aes_128_cbc,
+    NID_aes_192_cbc,
+    NID_aes_256_cbc,
+};
+
+static cbc_handles cbc_handle[] = {{AES_KEY_SIZE_128, NULL},
+                                    {AES_KEY_SIZE_192, NULL},
+                                    {AES_KEY_SIZE_256, NULL}};
+
+static ossl_inline int io_setup(unsigned n, aio_context_t *ctx)
+{
+    return syscall(__NR_io_setup, n, ctx);
+}
+
+static ossl_inline int eventfd(int n)
+{
+    return syscall(__NR_eventfd2, n, 0);
+}
+
+static ossl_inline int io_destroy(aio_context_t ctx)
+{
+    return syscall(__NR_io_destroy, ctx);
+}
+
+static ossl_inline int io_read(aio_context_t ctx, long n, struct iocb **iocb)
+{
+    return syscall(__NR_io_submit, ctx, n, iocb);
+}
+
+static ossl_inline int io_getevents(aio_context_t ctx, long min, long max,
+                               struct io_event *events,
+                               struct timespec *timeout)
+{
+    return syscall(__NR_io_getevents, ctx, min, max, events, timeout);
+}
+
+static void afalg_waitfd_cleanup(ASYNC_WAIT_CTX *ctx, const void *key,
+                                 OSSL_ASYNC_FD waitfd, void *custom)
+{
+    close(waitfd);
+}
+
+static int afalg_setup_async_event_notification(afalg_aio *aio)
+{
+    ASYNC_JOB *job;
+    ASYNC_WAIT_CTX *waitctx;
+    void *custom = NULL;
+    int ret;
+
+    if ((job = ASYNC_get_current_job()) != NULL) {
+        /* Async mode */
+        waitctx = ASYNC_get_wait_ctx(job);
+        if (waitctx == NULL) {
+            ALG_WARN("%s(%d): ASYNC_get_wait_ctx error", __FILE__, __LINE__);
+            return 0;
+        }
+        /* Get waitfd from ASYNC_WAIT_CTX if it is already set */
+        ret = ASYNC_WAIT_CTX_get_fd(waitctx, engine_afalg_id,
+                                    &aio->efd, &custom);
+        if (ret == 0) {
+            /*
+             * waitfd is not set in ASYNC_WAIT_CTX, create a new one
+             * and set it. efd will be signaled when AIO operation completes
+             */
+            aio->efd = eventfd(0);
+            if (aio->efd == -1) {
+                ALG_PERR("%s(%d): Failed to get eventfd : ", __FILE__,
+                         __LINE__);
+                AFALGerr(AFALG_F_AFALG_SETUP_ASYNC_EVENT_NOTIFICATION,
+                         AFALG_R_EVENTFD_FAILED);
+                return 0;
+            }
+            ret = ASYNC_WAIT_CTX_set_wait_fd(waitctx, engine_afalg_id,
+                                             aio->efd, custom,
+                                             afalg_waitfd_cleanup);
+            if (ret == 0) {
+                ALG_WARN("%s(%d): Failed to set wait fd", __FILE__, __LINE__);
+                close(aio->efd);
+                return 0;
+            }
+            /* make fd non-blocking in async mode */
+            if (fcntl(aio->efd, F_SETFL, O_NONBLOCK) != 0) {
+                ALG_WARN("%s(%d): Failed to set event fd as NONBLOCKING",
+                         __FILE__, __LINE__);
+            }
+        }
+        aio->mode = MODE_ASYNC;
+    } else {
+        /* Sync mode */
+        aio->efd = eventfd(0);
+        if (aio->efd == -1) {
+            ALG_PERR("%s(%d): Failed to get eventfd : ", __FILE__, __LINE__);
+            AFALGerr(AFALG_F_AFALG_SETUP_ASYNC_EVENT_NOTIFICATION,
+                     AFALG_R_EVENTFD_FAILED);
+            return 0;
+        }
+        aio->mode = MODE_SYNC;
+    }
+    return 1;
+}
+
+static int afalg_init_aio(afalg_aio *aio)
+{
+    int r = -1;
+
+    /* Initialise for AIO */
+    aio->aio_ctx = 0;
+    r = io_setup(MAX_INFLIGHTS, &aio->aio_ctx);
+    if (r < 0) {
+        ALG_PERR("%s(%d): io_setup error : ", __FILE__, __LINE__);
+        AFALGerr(AFALG_F_AFALG_INIT_AIO, AFALG_R_IO_SETUP_FAILED);
+        return 0;
+    }
+
+    memset(aio->cbt, 0, sizeof(aio->cbt));
+    aio->efd = -1;
+    aio->mode = MODE_UNINIT;
+
+    return 1;
+}
+
+static int afalg_fin_cipher_aio(afalg_aio *aio, int sfd, unsigned char *buf,
+                                size_t len)
+{
+    int r;
+    int retry = 0;
+    unsigned int done = 0;
+    struct iocb *cb;
+    struct timespec timeout;
+    struct io_event events[MAX_INFLIGHTS];
+    u_int64_t eval = 0;
+
+    timeout.tv_sec = 0;
+    timeout.tv_nsec = 0;
+
+    /* if efd has not been initialised yet do it here */
+    if (aio->mode == MODE_UNINIT) {
+        r = afalg_setup_async_event_notification(aio);
+        if (r == 0)
+            return 0;
+    }
+
+    cb = &(aio->cbt[0 % MAX_INFLIGHTS]);
+    memset(cb, '\0', sizeof(*cb));
+    cb->aio_fildes = sfd;
+    cb->aio_lio_opcode = IOCB_CMD_PREAD;
+    /*
+     * The pointer has to be converted to unsigned value first to avoid
+     * sign extension on cast to 64 bit value in 32-bit builds
+     */
+    cb->aio_buf = (size_t)buf;
+    cb->aio_offset = 0;
+    cb->aio_data = 0;
+    cb->aio_nbytes = len;
+    cb->aio_flags = IOCB_FLAG_RESFD;
+    cb->aio_resfd = aio->efd;
+
+    /*
+     * Perform AIO read on AFALG socket, this in turn performs an async
+     * crypto operation in kernel space
+     */
+    r = io_read(aio->aio_ctx, 1, &cb);
+    if (r < 0) {
+        ALG_PWARN("%s(%d): io_read failed : ", __FILE__, __LINE__);
+        return 0;
+    }
+
+    do {
+        /* While AIO read is being performed pause job */
+        ASYNC_pause_job();
+
+        /* Check for completion of AIO read */
+        r = read(aio->efd, &eval, sizeof(eval));
+        if (r < 0) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK)
+                continue;
+            ALG_PERR("%s(%d): read failed for event fd : ", __FILE__, __LINE__);
+            return 0;
+        } else if (r == 0 || eval <= 0) {
+            ALG_WARN("%s(%d): eventfd read %d bytes, eval = %lu\n", __FILE__,
+                     __LINE__, r, eval);
+        }
+        if (eval > 0) {
+
+            /* Get results of AIO read */
+            r = io_getevents(aio->aio_ctx, 1, MAX_INFLIGHTS,
+                             events, &timeout);
+            if (r > 0) {
+                /*
+                 * events.res indicates the actual status of the operation.
+                 * Handle the error condition first.
+                 */
+                if (events[0].res < 0) {
+                    /*
+                     * Underlying operation cannot be completed at the time
+                     * of previous submission. Resubmit for the operation.
+                     */
+                    if (events[0].res == -EBUSY && retry++ < 3) {
+                        r = io_read(aio->aio_ctx, 1, &cb);
+                        if (r < 0) {
+                            ALG_PERR("%s(%d): retry %d for io_read failed : ",
+                                     __FILE__, __LINE__, retry);
+                            return 0;
+                        }
+                        continue;
+                    } else {
+                        /*
+                         * Retries exceed for -EBUSY or unrecoverable error
+                         * condition for this instance of operation.
+                         */
+                        ALG_WARN
+                            ("%s(%d): Crypto Operation failed with code %lld\n",
+                             __FILE__, __LINE__, events[0].res);
+                        return 0;
+                    }
+                }
+                /* Operation successful. */
+                done = 1;
+            } else if (r < 0) {
+                ALG_PERR("%s(%d): io_getevents failed : ", __FILE__, __LINE__);
+                return 0;
+            } else {
+                ALG_WARN("%s(%d): io_geteventd read 0 bytes\n", __FILE__,
+                         __LINE__);
+            }
+        }
+    } while (!done);
+
+    return 1;
+}
+
+static ossl_inline void afalg_set_op_sk(struct cmsghdr *cmsg,
+                                   const ALG_OP_TYPE op)
+{
+    cmsg->cmsg_level = SOL_ALG;
+    cmsg->cmsg_type = ALG_SET_OP;
+    cmsg->cmsg_len = CMSG_LEN(ALG_OP_LEN);
+    memcpy(CMSG_DATA(cmsg), &op, ALG_OP_LEN);
+}
+
+static void afalg_set_iv_sk(struct cmsghdr *cmsg, const unsigned char *iv,
+                            const unsigned int len)
+{
+    struct af_alg_iv *aiv;
+
+    cmsg->cmsg_level = SOL_ALG;
+    cmsg->cmsg_type = ALG_SET_IV;
+    cmsg->cmsg_len = CMSG_LEN(ALG_IV_LEN(len));
+    aiv = (struct af_alg_iv *)CMSG_DATA(cmsg);
+    aiv->ivlen = len;
+    memcpy(aiv->iv, iv, len);
+}
+
+static ossl_inline int afalg_set_key(afalg_ctx *actx, const unsigned char *key,
+                                const int klen)
+{
+    int ret;
+    ret = setsockopt(actx->bfd, SOL_ALG, ALG_SET_KEY, key, klen);
+    if (ret < 0) {
+        ALG_PERR("%s(%d): Failed to set socket option : ", __FILE__, __LINE__);
+        AFALGerr(AFALG_F_AFALG_SET_KEY, AFALG_R_SOCKET_SET_KEY_FAILED);
+        return 0;
+    }
+    return 1;
+}
+
+static int afalg_create_sk(afalg_ctx *actx, const char *ciphertype,
+                                const char *ciphername)
+{
+    struct sockaddr_alg sa;
+    int r = -1;
+
+    actx->bfd = actx->sfd = -1;
+
+    memset(&sa, 0, sizeof(sa));
+    sa.salg_family = AF_ALG;
+    OPENSSL_strlcpy((char *) sa.salg_type, ciphertype, sizeof(sa.salg_type));
+    OPENSSL_strlcpy((char *) sa.salg_name, ciphername, sizeof(sa.salg_name));
+
+    actx->bfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
+    if (actx->bfd == -1) {
+        ALG_PERR("%s(%d): Failed to open socket : ", __FILE__, __LINE__);
+        AFALGerr(AFALG_F_AFALG_CREATE_SK, AFALG_R_SOCKET_CREATE_FAILED);
+        goto err;
+    }
+
+    r = bind(actx->bfd, (struct sockaddr *)&sa, sizeof(sa));
+    if (r < 0) {
+        ALG_PERR("%s(%d): Failed to bind socket : ", __FILE__, __LINE__);
+        AFALGerr(AFALG_F_AFALG_CREATE_SK, AFALG_R_SOCKET_BIND_FAILED);
+        goto err;
+    }
+
+    actx->sfd = accept(actx->bfd, NULL, 0);
+    if (actx->sfd < 0) {
+        ALG_PERR("%s(%d): Socket Accept Failed : ", __FILE__, __LINE__);
+        AFALGerr(AFALG_F_AFALG_CREATE_SK, AFALG_R_SOCKET_ACCEPT_FAILED);
+        goto err;
+    }
+
+    return 1;
+
+ err:
+    if (actx->bfd >= 0)
+        close(actx->bfd);
+    if (actx->sfd >= 0)
+        close(actx->sfd);
+    actx->bfd = actx->sfd = -1;
+    return 0;
+}
+
+static int afalg_start_cipher_sk(afalg_ctx *actx, const unsigned char *in,
+                                 size_t inl, const unsigned char *iv,
+                                 unsigned int enc)
+{
+    struct msghdr msg = { 0 };
+    struct cmsghdr *cmsg;
+    struct iovec iov;
+    ssize_t sbytes;
+# ifdef ALG_ZERO_COPY
+    int ret;
+# endif
+    char cbuf[CMSG_SPACE(ALG_IV_LEN(ALG_AES_IV_LEN)) + CMSG_SPACE(ALG_OP_LEN)];
+
+    memset(cbuf, 0, sizeof(cbuf));
+    msg.msg_control = cbuf;
+    msg.msg_controllen = sizeof(cbuf);
+
+    /*
+     * cipher direction (i.e. encrypt or decrypt) and iv are sent to the
+     * kernel as part of sendmsg()'s ancillary data
+     */
+    cmsg = CMSG_FIRSTHDR(&msg);
+    afalg_set_op_sk(cmsg, enc);
+    cmsg = CMSG_NXTHDR(&msg, cmsg);
+    afalg_set_iv_sk(cmsg, iv, ALG_AES_IV_LEN);
+
+    /* iov that describes input data */
+    iov.iov_base = (unsigned char *)in;
+    iov.iov_len = inl;
+
+    msg.msg_flags = MSG_MORE;
+
+# ifdef ALG_ZERO_COPY
+    /*
+     * ZERO_COPY mode
+     * Works best when buffer is 4k aligned
+     * OPENS: out of place processing (i.e. out != in)
+     */
+
+    /* Input data is not sent as part of call to sendmsg() */
+    msg.msg_iovlen = 0;
+    msg.msg_iov = NULL;
+
+    /* Sendmsg() sends iv and cipher direction to the kernel */
+    sbytes = sendmsg(actx->sfd, &msg, 0);
+    if (sbytes < 0) {
+        ALG_PERR("%s(%d): sendmsg failed for zero copy cipher operation : ",
+                 __FILE__, __LINE__);
+        return 0;
+    }
+
+    /*
+     * vmsplice and splice are used to pin the user space input buffer for
+     * kernel space processing avoiding copies from user to kernel space
+     */
+    ret = vmsplice(actx->zc_pipe[1], &iov, 1, SPLICE_F_GIFT);
+    if (ret < 0) {
+        ALG_PERR("%s(%d): vmsplice failed : ", __FILE__, __LINE__);
+        return 0;
+    }
+
+    ret = splice(actx->zc_pipe[0], NULL, actx->sfd, NULL, inl, 0);
+    if (ret < 0) {
+        ALG_PERR("%s(%d): splice failed : ", __FILE__, __LINE__);
+        return 0;
+    }
+# else
+    msg.msg_iovlen = 1;
+    msg.msg_iov = &iov;
+
+    /* Sendmsg() sends iv, cipher direction and input data to the kernel */
+    sbytes = sendmsg(actx->sfd, &msg, 0);
+    if (sbytes < 0) {
+        ALG_PERR("%s(%d): sendmsg failed for cipher operation : ", __FILE__,
+                 __LINE__);
+        return 0;
+    }
+
+    if (sbytes != (ssize_t) inl) {
+        ALG_WARN("Cipher operation send bytes %zd != inlen %zd\n", sbytes,
+                inl);
+        return 0;
+    }
+# endif
+
+    return 1;
+}
+
+static int afalg_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                             const unsigned char *iv, int enc)
+{
+    int ciphertype;
+    int ret;
+    afalg_ctx *actx;
+    const char *ciphername;
+
+    if (ctx == NULL || key == NULL) {
+        ALG_WARN("%s(%d): Null Parameter\n", __FILE__, __LINE__);
+        return 0;
+    }
+
+    if (EVP_CIPHER_CTX_cipher(ctx) == NULL) {
+        ALG_WARN("%s(%d): Cipher object NULL\n", __FILE__, __LINE__);
+        return 0;
+    }
+
+    actx = EVP_CIPHER_CTX_get_cipher_data(ctx);
+    if (actx == NULL) {
+        ALG_WARN("%s(%d): Cipher data NULL\n", __FILE__, __LINE__);
+        return 0;
+    }
+
+    ciphertype = EVP_CIPHER_CTX_nid(ctx);
+    switch (ciphertype) {
+    case NID_aes_128_cbc:
+    case NID_aes_192_cbc:
+    case NID_aes_256_cbc:
+        ciphername = "cbc(aes)";
+        break;
+    default:
+        ALG_WARN("%s(%d): Unsupported Cipher type %d\n", __FILE__, __LINE__,
+                 ciphertype);
+        return 0;
+    }
+
+    if (ALG_AES_IV_LEN != EVP_CIPHER_CTX_iv_length(ctx)) {
+        ALG_WARN("%s(%d): Unsupported IV length :%d\n", __FILE__, __LINE__,
+                 EVP_CIPHER_CTX_iv_length(ctx));
+        return 0;
+    }
+
+    /* Setup AFALG socket for crypto processing */
+    ret = afalg_create_sk(actx, "skcipher", ciphername);
+    if (ret < 1)
+        return 0;
+
+
+    ret = afalg_set_key(actx, key, EVP_CIPHER_CTX_key_length(ctx));
+    if (ret < 1)
+        goto err;
+
+    /* Setup AIO ctx to allow async AFALG crypto processing */
+    if (afalg_init_aio(&actx->aio) == 0)
+        goto err;
+
+# ifdef ALG_ZERO_COPY
+    pipe(actx->zc_pipe);
+# endif
+
+    actx->init_done = MAGIC_INIT_NUM;
+
+    return 1;
+
+err:
+    close(actx->sfd);
+    close(actx->bfd);
+    return 0;
+}
+
+static int afalg_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                           const unsigned char *in, size_t inl)
+{
+    afalg_ctx *actx;
+    int ret;
+    char nxtiv[ALG_AES_IV_LEN] = { 0 };
+
+    if (ctx == NULL || out == NULL || in == NULL) {
+        ALG_WARN("NULL parameter passed to function %s(%d)\n", __FILE__,
+                 __LINE__);
+        return 0;
+    }
+
+    actx = (afalg_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx);
+    if (actx == NULL || actx->init_done != MAGIC_INIT_NUM) {
+        ALG_WARN("%s afalg ctx passed\n",
+                 ctx == NULL ? "NULL" : "Uninitialised");
+        return 0;
+    }
+
+    /*
+     * set iv now for decrypt operation as the input buffer can be
+     * overwritten for inplace operation where in = out.
+     */
+    if (EVP_CIPHER_CTX_encrypting(ctx) == 0) {
+        memcpy(nxtiv, in + (inl - ALG_AES_IV_LEN), ALG_AES_IV_LEN);
+    }
+
+    /* Send input data to kernel space */
+    ret = afalg_start_cipher_sk(actx, (unsigned char *)in, inl,
+                                EVP_CIPHER_CTX_iv(ctx),
+                                EVP_CIPHER_CTX_encrypting(ctx));
+    if (ret < 1) {
+        return 0;
+    }
+
+    /* Perform async crypto operation in kernel space */
+    ret = afalg_fin_cipher_aio(&actx->aio, actx->sfd, out, inl);
+    if (ret < 1)
+        return 0;
+
+    if (EVP_CIPHER_CTX_encrypting(ctx)) {
+        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), out + (inl - ALG_AES_IV_LEN),
+               ALG_AES_IV_LEN);
+    } else {
+        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), nxtiv, ALG_AES_IV_LEN);
+    }
+
+    return 1;
+}
+
+static int afalg_cipher_cleanup(EVP_CIPHER_CTX *ctx)
+{
+    afalg_ctx *actx;
+
+    if (ctx == NULL) {
+        ALG_WARN("NULL parameter passed to function %s(%d)\n", __FILE__,
+                 __LINE__);
+        return 0;
+    }
+
+    actx = (afalg_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx);
+    if (actx == NULL || actx->init_done != MAGIC_INIT_NUM)
+        return 1;
+
+    close(actx->sfd);
+    close(actx->bfd);
+# ifdef ALG_ZERO_COPY
+    close(actx->zc_pipe[0]);
+    close(actx->zc_pipe[1]);
+# endif
+    /* close efd in sync mode, async mode is closed in afalg_waitfd_cleanup() */
+    if (actx->aio.mode == MODE_SYNC)
+        close(actx->aio.efd);
+    io_destroy(actx->aio.aio_ctx);
+
+    return 1;
+}
+
+static cbc_handles *get_cipher_handle(int nid)
+{
+    switch (nid) {
+    case NID_aes_128_cbc:
+        return &cbc_handle[AES_CBC_128];
+    case NID_aes_192_cbc:
+        return &cbc_handle[AES_CBC_192];
+    case NID_aes_256_cbc:
+        return &cbc_handle[AES_CBC_256];
+    default:
+        return NULL;
+    }
+}
+
+static const EVP_CIPHER *afalg_aes_cbc(int nid)
+{
+    cbc_handles *cipher_handle = get_cipher_handle(nid);
+    if (cipher_handle->_hidden == NULL
+        && ((cipher_handle->_hidden =
+         EVP_CIPHER_meth_new(nid,
+                             AES_BLOCK_SIZE,
+                             cipher_handle->key_size)) == NULL
+        || !EVP_CIPHER_meth_set_iv_length(cipher_handle->_hidden,
+                                          AES_IV_LEN)
+        || !EVP_CIPHER_meth_set_flags(cipher_handle->_hidden,
+                                      EVP_CIPH_CBC_MODE |
+                                      EVP_CIPH_FLAG_DEFAULT_ASN1)
+        || !EVP_CIPHER_meth_set_init(cipher_handle->_hidden,
+                                     afalg_cipher_init)
+        || !EVP_CIPHER_meth_set_do_cipher(cipher_handle->_hidden,
+                                          afalg_do_cipher)
+        || !EVP_CIPHER_meth_set_cleanup(cipher_handle->_hidden,
+                                        afalg_cipher_cleanup)
+        || !EVP_CIPHER_meth_set_impl_ctx_size(cipher_handle->_hidden,
+                                              sizeof(afalg_ctx)))) {
+        EVP_CIPHER_meth_free(cipher_handle->_hidden);
+        cipher_handle->_hidden= NULL;
+    }
+    return cipher_handle->_hidden;
+}
+
+static int afalg_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+                         const int **nids, int nid)
+{
+    int r = 1;
+
+    if (cipher == NULL) {
+        *nids = afalg_cipher_nids;
+        return (sizeof(afalg_cipher_nids) / sizeof(afalg_cipher_nids[0]));
+    }
+
+    switch (nid) {
+    case NID_aes_128_cbc:
+    case NID_aes_192_cbc:
+    case NID_aes_256_cbc:
+        *cipher = afalg_aes_cbc(nid);
+        break;
+    default:
+        *cipher = NULL;
+        r = 0;
+    }
+    return r;
+}
+
+static int bind_afalg(ENGINE *e)
+{
+    /* Ensure the afalg error handling is set up */
+    unsigned short i;
+    ERR_load_AFALG_strings();
+
+    if (!ENGINE_set_id(e, engine_afalg_id)
+        || !ENGINE_set_name(e, engine_afalg_name)
+        || !ENGINE_set_destroy_function(e, afalg_destroy)
+        || !ENGINE_set_init_function(e, afalg_init)
+        || !ENGINE_set_finish_function(e, afalg_finish)) {
+        AFALGerr(AFALG_F_BIND_AFALG, AFALG_R_INIT_FAILED);
+        return 0;
+    }
+
+    /*
+     * Create _hidden_aes_xxx_cbc by calling afalg_aes_xxx_cbc
+     * now, as bind_aflag can only be called by one thread at a
+     * time.
+     */
+    for(i = 0; i < OSSL_NELEM(afalg_cipher_nids); i++) {
+        if (afalg_aes_cbc(afalg_cipher_nids[i]) == NULL) {
+            AFALGerr(AFALG_F_BIND_AFALG, AFALG_R_INIT_FAILED);
+            return 0;
+        }
+    }
+
+    if (!ENGINE_set_ciphers(e, afalg_ciphers)) {
+        AFALGerr(AFALG_F_BIND_AFALG, AFALG_R_INIT_FAILED);
+        return 0;
+    }
+
+    return 1;
+}
+
+# ifndef OPENSSL_NO_DYNAMIC_ENGINE
+static int bind_helper(ENGINE *e, const char *id)
+{
+    if (id && (strcmp(id, engine_afalg_id) != 0))
+        return 0;
+
+    if (!afalg_chk_platform())
+        return 0;
+
+    if (!bind_afalg(e))
+        return 0;
+    return 1;
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
+# endif
+
+static int afalg_chk_platform(void)
+{
+    int ret;
+    int i;
+    int kver[3] = { -1, -1, -1 };
+    int sock;
+    char *str;
+    struct utsname ut;
+
+    ret = uname(&ut);
+    if (ret != 0) {
+        AFALGerr(AFALG_F_AFALG_CHK_PLATFORM,
+                 AFALG_R_FAILED_TO_GET_PLATFORM_INFO);
+        return 0;
+    }
+
+    str = strtok(ut.release, ".");
+    for (i = 0; i < 3 && str != NULL; i++) {
+        kver[i] = atoi(str);
+        str = strtok(NULL, ".");
+    }
+
+    if (KERNEL_VERSION(kver[0], kver[1], kver[2])
+        < KERNEL_VERSION(K_MAJ, K_MIN1, K_MIN2)) {
+        ALG_ERR("ASYNC AFALG not supported this kernel(%d.%d.%d)\n",
+                 kver[0], kver[1], kver[2]);
+        ALG_ERR("ASYNC AFALG requires kernel version %d.%d.%d or later\n",
+                 K_MAJ, K_MIN1, K_MIN2);
+        AFALGerr(AFALG_F_AFALG_CHK_PLATFORM,
+                 AFALG_R_KERNEL_DOES_NOT_SUPPORT_ASYNC_AFALG);
+        return 0;
+    }
+
+    /* Test if we can actually create an AF_ALG socket */
+    sock = socket(AF_ALG, SOCK_SEQPACKET, 0);
+    if (sock == -1) {
+        AFALGerr(AFALG_F_AFALG_CHK_PLATFORM, AFALG_R_SOCKET_CREATE_FAILED);
+        return 0;
+    }
+    close(sock);
+
+    return 1;
+}
+
+# ifdef OPENSSL_NO_DYNAMIC_ENGINE
+static ENGINE *engine_afalg(void)
+{
+    ENGINE *ret = ENGINE_new();
+    if (ret == NULL)
+        return NULL;
+    if (!bind_afalg(ret)) {
+        ENGINE_free(ret);
+        return NULL;
+    }
+    return ret;
+}
+
+void engine_load_afalg_int(void)
+{
+    ENGINE *toadd;
+
+    if (!afalg_chk_platform())
+        return;
+
+    toadd = engine_afalg();
+    if (toadd == NULL)
+        return;
+    ENGINE_add(toadd);
+    ENGINE_free(toadd);
+    ERR_clear_error();
+}
+# endif
+
+static int afalg_init(ENGINE *e)
+{
+    return 1;
+}
+
+static int afalg_finish(ENGINE *e)
+{
+    return 1;
+}
+
+static int free_cbc(void)
+{
+    short unsigned int i;
+    for(i = 0; i < OSSL_NELEM(afalg_cipher_nids); i++) {
+        EVP_CIPHER_meth_free(cbc_handle[i]._hidden);
+        cbc_handle[i]._hidden = NULL;
+    }
+    return 1;
+}
+
+static int afalg_destroy(ENGINE *e)
+{
+    ERR_unload_AFALG_strings();
+    free_cbc();
+    return 1;
+}
+
+#endif                          /* KERNEL VERSION */
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.ec b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.ec
new file mode 100644
index 0000000..6d7420f
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.ec
@@ -0,0 +1,3 @@
+# The INPUT HEADER is scanned for declarations
+# LIBNAME       INPUT HEADER                    ERROR-TABLE FILE
+L AFALG         e_afalg_err.h                   e_afalg_err.c
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.h b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.h
new file mode 100644
index 0000000..3323c89
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_ENGINES_E_AFALG_H
+# define OSSL_ENGINES_E_AFALG_H
+
+# if defined(__GNUC__) && __GNUC__ >= 4 && \
+     (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
+#  pragma GCC diagnostic ignored "-Wvariadic-macros"
+# endif
+
+# ifdef ALG_DEBUG
+#  define ALG_DGB(x, ...) fprintf(stderr, "ALG_DBG: " x, __VA_ARGS__)
+#  define ALG_INFO(x, ...) fprintf(stderr, "ALG_INFO: " x, __VA_ARGS__)
+#  define ALG_WARN(x, ...) fprintf(stderr, "ALG_WARN: " x, __VA_ARGS__)
+# else
+#  define ALG_DGB(x, ...)
+#  define ALG_INFO(x, ...)
+#  define ALG_WARN(x, ...)
+# endif
+
+# define ALG_ERR(x, ...) fprintf(stderr, "ALG_ERR: " x, __VA_ARGS__)
+# define ALG_PERR(x, ...) \
+                do { \
+                    fprintf(stderr, "ALG_PERR: " x, __VA_ARGS__); \
+                    perror(NULL); \
+                } while(0)
+# define ALG_PWARN(x, ...) \
+                do { \
+                    fprintf(stderr, "ALG_PERR: " x, __VA_ARGS__); \
+                    perror(NULL); \
+                } while(0)
+
+# ifndef AES_BLOCK_SIZE
+#  define AES_BLOCK_SIZE   16
+# endif
+# define AES_KEY_SIZE_128 16
+# define AES_KEY_SIZE_192 24
+# define AES_KEY_SIZE_256 32
+# define AES_IV_LEN       16
+
+# define MAX_INFLIGHTS 1
+
+typedef enum {
+    MODE_UNINIT = 0,
+    MODE_SYNC,
+    MODE_ASYNC
+} op_mode;
+
+enum {
+    AES_CBC_128 = 0,
+    AES_CBC_192,
+    AES_CBC_256
+};
+
+struct cbc_cipher_handles {
+    int key_size;
+    EVP_CIPHER *_hidden;
+};
+
+typedef struct cbc_cipher_handles cbc_handles;
+
+struct afalg_aio_st {
+    int efd;
+    op_mode mode;
+    aio_context_t aio_ctx;
+    struct io_event events[MAX_INFLIGHTS];
+    struct iocb cbt[MAX_INFLIGHTS];
+};
+typedef struct afalg_aio_st afalg_aio;
+
+/*
+ * MAGIC Number to identify correct initialisation
+ * of afalg_ctx.
+ */
+# define MAGIC_INIT_NUM 0x1890671
+
+struct afalg_ctx_st {
+    int init_done;
+    int sfd;
+    int bfd;
+# ifdef ALG_ZERO_COPY
+    int zc_pipe[2];
+# endif
+    afalg_aio aio;
+};
+
+typedef struct afalg_ctx_st afalg_ctx;
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.txt b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.txt
new file mode 100644
index 0000000..3b79305
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg.txt
@@ -0,0 +1,30 @@
+# Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+# Function codes
+AFALG_F_AFALG_CHK_PLATFORM:100:afalg_chk_platform
+AFALG_F_AFALG_CREATE_SK:101:afalg_create_sk
+AFALG_F_AFALG_INIT_AIO:102:afalg_init_aio
+AFALG_F_AFALG_SETUP_ASYNC_EVENT_NOTIFICATION:103:\
+	afalg_setup_async_event_notification
+AFALG_F_AFALG_SET_KEY:104:afalg_set_key
+AFALG_F_BIND_AFALG:105:bind_afalg
+
+#Reason codes
+AFALG_R_EVENTFD_FAILED:108:eventfd failed
+AFALG_R_FAILED_TO_GET_PLATFORM_INFO:111:failed to get platform info
+AFALG_R_INIT_FAILED:100:init failed
+AFALG_R_IO_SETUP_FAILED:105:io setup failed
+AFALG_R_KERNEL_DOES_NOT_SUPPORT_AFALG:101:kernel does not support afalg
+AFALG_R_KERNEL_DOES_NOT_SUPPORT_ASYNC_AFALG:107:\
+	kernel does not support async afalg
+AFALG_R_MEM_ALLOC_FAILED:102:mem alloc failed
+AFALG_R_SOCKET_ACCEPT_FAILED:110:socket accept failed
+AFALG_R_SOCKET_BIND_FAILED:103:socket bind failed
+AFALG_R_SOCKET_CREATE_FAILED:109:socket create failed
+AFALG_R_SOCKET_OPERATION_FAILED:104:socket operation failed
+AFALG_R_SOCKET_SET_KEY_FAILED:106:socket set key failed
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg_err.c b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg_err.c
new file mode 100644
index 0000000..18fe9c3
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg_err.c
@@ -0,0 +1,83 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/err.h>
+#include "e_afalg_err.h"
+
+#ifndef OPENSSL_NO_ERR
+
+static ERR_STRING_DATA AFALG_str_functs[] = {
+    {ERR_PACK(0, AFALG_F_AFALG_CHK_PLATFORM, 0), "afalg_chk_platform"},
+    {ERR_PACK(0, AFALG_F_AFALG_CREATE_SK, 0), "afalg_create_sk"},
+    {ERR_PACK(0, AFALG_F_AFALG_INIT_AIO, 0), "afalg_init_aio"},
+    {ERR_PACK(0, AFALG_F_AFALG_SETUP_ASYNC_EVENT_NOTIFICATION, 0),
+     "afalg_setup_async_event_notification"},
+    {ERR_PACK(0, AFALG_F_AFALG_SET_KEY, 0), "afalg_set_key"},
+    {ERR_PACK(0, AFALG_F_BIND_AFALG, 0), "bind_afalg"},
+    {0, NULL}
+};
+
+static ERR_STRING_DATA AFALG_str_reasons[] = {
+    {ERR_PACK(0, 0, AFALG_R_EVENTFD_FAILED), "eventfd failed"},
+    {ERR_PACK(0, 0, AFALG_R_FAILED_TO_GET_PLATFORM_INFO),
+    "failed to get platform info"},
+    {ERR_PACK(0, 0, AFALG_R_INIT_FAILED), "init failed"},
+    {ERR_PACK(0, 0, AFALG_R_IO_SETUP_FAILED), "io setup failed"},
+    {ERR_PACK(0, 0, AFALG_R_KERNEL_DOES_NOT_SUPPORT_AFALG),
+    "kernel does not support afalg"},
+    {ERR_PACK(0, 0, AFALG_R_KERNEL_DOES_NOT_SUPPORT_ASYNC_AFALG),
+    "kernel does not support async afalg"},
+    {ERR_PACK(0, 0, AFALG_R_MEM_ALLOC_FAILED), "mem alloc failed"},
+    {ERR_PACK(0, 0, AFALG_R_SOCKET_ACCEPT_FAILED), "socket accept failed"},
+    {ERR_PACK(0, 0, AFALG_R_SOCKET_BIND_FAILED), "socket bind failed"},
+    {ERR_PACK(0, 0, AFALG_R_SOCKET_CREATE_FAILED), "socket create failed"},
+    {ERR_PACK(0, 0, AFALG_R_SOCKET_OPERATION_FAILED),
+    "socket operation failed"},
+    {ERR_PACK(0, 0, AFALG_R_SOCKET_SET_KEY_FAILED), "socket set key failed"},
+    {0, NULL}
+};
+
+#endif
+
+static int lib_code = 0;
+static int error_loaded = 0;
+
+static int ERR_load_AFALG_strings(void)
+{
+    if (lib_code == 0)
+        lib_code = ERR_get_next_error_library();
+
+    if (!error_loaded) {
+#ifndef OPENSSL_NO_ERR
+        ERR_load_strings(lib_code, AFALG_str_functs);
+        ERR_load_strings(lib_code, AFALG_str_reasons);
+#endif
+        error_loaded = 1;
+    }
+    return 1;
+}
+
+static void ERR_unload_AFALG_strings(void)
+{
+    if (error_loaded) {
+#ifndef OPENSSL_NO_ERR
+        ERR_unload_strings(lib_code, AFALG_str_functs);
+        ERR_unload_strings(lib_code, AFALG_str_reasons);
+#endif
+        error_loaded = 0;
+    }
+}
+
+static void ERR_AFALG_error(int function, int reason, char *file, int line)
+{
+    if (lib_code == 0)
+        lib_code = ERR_get_next_error_library();
+    ERR_PUT_error(lib_code, function, reason, file, line);
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg_err.h b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg_err.h
new file mode 100644
index 0000000..3036443
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_afalg_err.h
@@ -0,0 +1,43 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_ENGINES_E_AFALG_ERR_H
+# define OSSL_ENGINES_E_AFALG_ERR_H
+
+# define AFALGerr(f, r) ERR_AFALG_error((f), (r), OPENSSL_FILE, OPENSSL_LINE)
+
+
+/*
+ * AFALG function codes.
+ */
+# define AFALG_F_AFALG_CHK_PLATFORM                       100
+# define AFALG_F_AFALG_CREATE_SK                          101
+# define AFALG_F_AFALG_INIT_AIO                           102
+# define AFALG_F_AFALG_SETUP_ASYNC_EVENT_NOTIFICATION     103
+# define AFALG_F_AFALG_SET_KEY                            104
+# define AFALG_F_BIND_AFALG                               105
+
+/*
+ * AFALG reason codes.
+ */
+# define AFALG_R_EVENTFD_FAILED                           108
+# define AFALG_R_FAILED_TO_GET_PLATFORM_INFO              111
+# define AFALG_R_INIT_FAILED                              100
+# define AFALG_R_IO_SETUP_FAILED                          105
+# define AFALG_R_KERNEL_DOES_NOT_SUPPORT_AFALG            101
+# define AFALG_R_KERNEL_DOES_NOT_SUPPORT_ASYNC_AFALG      107
+# define AFALG_R_MEM_ALLOC_FAILED                         102
+# define AFALG_R_SOCKET_ACCEPT_FAILED                     110
+# define AFALG_R_SOCKET_BIND_FAILED                       103
+# define AFALG_R_SOCKET_CREATE_FAILED                     109
+# define AFALG_R_SOCKET_OPERATION_FAILED                  104
+# define AFALG_R_SOCKET_SET_KEY_FAILED                    106
+
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_capi.c b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi.c
new file mode 100644
index 0000000..37202b8
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi.c
@@ -0,0 +1,1904 @@
+/*
+ * Copyright 2008-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifdef _WIN32
+# ifndef _WIN32_WINNT
+#  define _WIN32_WINNT 0x0400
+# endif
+# include <windows.h>
+# include <wincrypt.h>
+
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+# include <malloc.h>
+# ifndef alloca
+#  define alloca _alloca
+# endif
+
+# include <openssl/crypto.h>
+
+# ifndef OPENSSL_NO_CAPIENG
+
+#  include <openssl/buffer.h>
+#  include <openssl/bn.h>
+#  include <openssl/rsa.h>
+#  include <openssl/dsa.h>
+
+/*
+ * This module uses several "new" interfaces, among which is
+ * CertGetCertificateContextProperty. CERT_KEY_PROV_INFO_PROP_ID is
+ * one of possible values you can pass to function in question. By
+ * checking if it's defined we can see if wincrypt.h and accompanying
+ * crypt32.lib are in shape. The native MingW32 headers up to and
+ * including __W32API_VERSION 3.14 lack of struct DSSPUBKEY and the
+ * defines CERT_STORE_PROV_SYSTEM_A and CERT_STORE_READONLY_FLAG,
+ * so we check for these too and avoid compiling.
+ * Yes, it's rather "weak" test and if compilation fails,
+ * then re-configure with -DOPENSSL_NO_CAPIENG.
+ */
+#  if defined(CERT_KEY_PROV_INFO_PROP_ID) && \
+    defined(CERT_STORE_PROV_SYSTEM_A) && \
+    defined(CERT_STORE_READONLY_FLAG)
+#   define __COMPILE_CAPIENG
+#  endif                        /* CERT_KEY_PROV_INFO_PROP_ID */
+# endif                         /* OPENSSL_NO_CAPIENG */
+#endif                          /* _WIN32 */
+
+#ifdef __COMPILE_CAPIENG
+
+# undef X509_EXTENSIONS
+
+/* Definitions which may be missing from earlier version of headers */
+# ifndef CERT_STORE_OPEN_EXISTING_FLAG
+#  define CERT_STORE_OPEN_EXISTING_FLAG                   0x00004000
+# endif
+
+# ifndef CERT_STORE_CREATE_NEW_FLAG
+#  define CERT_STORE_CREATE_NEW_FLAG                      0x00002000
+# endif
+
+# ifndef CERT_SYSTEM_STORE_CURRENT_USER
+#  define CERT_SYSTEM_STORE_CURRENT_USER                  0x00010000
+# endif
+
+# ifndef ALG_SID_SHA_256
+#  define ALG_SID_SHA_256   12
+# endif
+# ifndef ALG_SID_SHA_384
+#  define ALG_SID_SHA_384   13
+# endif
+# ifndef ALG_SID_SHA_512
+#  define ALG_SID_SHA_512   14
+# endif
+
+# ifndef CALG_SHA_256
+#  define CALG_SHA_256      (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
+# endif
+# ifndef CALG_SHA_384
+#  define CALG_SHA_384      (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384)
+# endif
+# ifndef CALG_SHA_512
+#  define CALG_SHA_512      (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512)
+# endif
+
+# ifndef PROV_RSA_AES
+#  define PROV_RSA_AES 24
+# endif
+
+# include <openssl/engine.h>
+# include <openssl/pem.h>
+# include <openssl/x509v3.h>
+
+# include "e_capi_err.h"
+# include "e_capi_err.c"
+
+static const char *engine_capi_id = "capi";
+static const char *engine_capi_name = "CryptoAPI ENGINE";
+
+typedef struct CAPI_CTX_st CAPI_CTX;
+typedef struct CAPI_KEY_st CAPI_KEY;
+
+static void capi_addlasterror(void);
+static void capi_adderror(DWORD err);
+
+static void CAPI_trace(CAPI_CTX *ctx, char *format, ...);
+
+static int capi_list_providers(CAPI_CTX *ctx, BIO *out);
+static int capi_list_containers(CAPI_CTX *ctx, BIO *out);
+int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *storename);
+void capi_free_key(CAPI_KEY *key);
+
+static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id,
+                                     HCERTSTORE hstore);
+
+CAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id);
+
+static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
+                                   UI_METHOD *ui_method, void *callback_data);
+static int capi_rsa_sign(int dtype, const unsigned char *m,
+                         unsigned int m_len, unsigned char *sigret,
+                         unsigned int *siglen, const RSA *rsa);
+static int capi_rsa_priv_enc(int flen, const unsigned char *from,
+                             unsigned char *to, RSA *rsa, int padding);
+static int capi_rsa_priv_dec(int flen, const unsigned char *from,
+                             unsigned char *to, RSA *rsa, int padding);
+static int capi_rsa_free(RSA *rsa);
+
+# ifndef OPENSSL_NO_DSA
+static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
+                                 DSA *dsa);
+static int capi_dsa_free(DSA *dsa);
+# endif
+
+static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
+                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
+                                     EVP_PKEY **pkey, STACK_OF(X509) **pother,
+                                     UI_METHOD *ui_method,
+                                     void *callback_data);
+
+static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
+# ifdef OPENSSL_CAPIENG_DIALOG
+static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
+# endif
+
+void engine_load_capi_int(void);
+
+typedef PCCERT_CONTEXT(WINAPI *CERTDLG)(HCERTSTORE, HWND, LPCWSTR,
+                                        LPCWSTR, DWORD, DWORD, void *);
+typedef HWND(WINAPI *GETCONSWIN)(void);
+
+/*
+ * This structure contains CAPI ENGINE specific data: it contains various
+ * global options and affects how other functions behave.
+ */
+
+# define CAPI_DBG_TRACE  2
+# define CAPI_DBG_ERROR  1
+
+struct CAPI_CTX_st {
+    int debug_level;
+    char *debug_file;
+    /* Parameters to use for container lookup */
+    DWORD keytype;
+    LPSTR cspname;
+    DWORD csptype;
+    /* Certificate store name to use */
+    LPSTR storename;
+    LPSTR ssl_client_store;
+    /* System store flags */
+    DWORD store_flags;
+/* Lookup string meanings in load_private_key */
+# define CAPI_LU_SUBSTR          1  /* Substring of subject: uses "storename" */
+# define CAPI_LU_FNAME           2  /* Friendly name: uses storename */
+# define CAPI_LU_CONTNAME        3  /* Container name: uses cspname, keytype */
+    int lookup_method;
+/* Info to dump with dumpcerts option */
+# define CAPI_DMP_SUMMARY        0x1    /* Issuer and serial name strings */
+# define CAPI_DMP_FNAME          0x2    /* Friendly name */
+# define CAPI_DMP_FULL           0x4    /* Full X509_print dump */
+# define CAPI_DMP_PEM            0x8    /* Dump PEM format certificate */
+# define CAPI_DMP_PSKEY          0x10   /* Dump pseudo key (if possible) */
+# define CAPI_DMP_PKEYINFO       0x20   /* Dump key info (if possible) */
+    DWORD dump_flags;
+    int (*client_cert_select) (ENGINE *e, SSL *ssl, STACK_OF(X509) *certs);
+    CERTDLG certselectdlg;
+    GETCONSWIN getconswindow;
+};
+
+static CAPI_CTX *capi_ctx_new(void);
+static void capi_ctx_free(CAPI_CTX *ctx);
+static int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type,
+                                 int check);
+static int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx);
+
+# define CAPI_CMD_LIST_CERTS             ENGINE_CMD_BASE
+# define CAPI_CMD_LOOKUP_CERT            (ENGINE_CMD_BASE + 1)
+# define CAPI_CMD_DEBUG_LEVEL            (ENGINE_CMD_BASE + 2)
+# define CAPI_CMD_DEBUG_FILE             (ENGINE_CMD_BASE + 3)
+# define CAPI_CMD_KEYTYPE                (ENGINE_CMD_BASE + 4)
+# define CAPI_CMD_LIST_CSPS              (ENGINE_CMD_BASE + 5)
+# define CAPI_CMD_SET_CSP_IDX            (ENGINE_CMD_BASE + 6)
+# define CAPI_CMD_SET_CSP_NAME           (ENGINE_CMD_BASE + 7)
+# define CAPI_CMD_SET_CSP_TYPE           (ENGINE_CMD_BASE + 8)
+# define CAPI_CMD_LIST_CONTAINERS        (ENGINE_CMD_BASE + 9)
+# define CAPI_CMD_LIST_OPTIONS           (ENGINE_CMD_BASE + 10)
+# define CAPI_CMD_LOOKUP_METHOD          (ENGINE_CMD_BASE + 11)
+# define CAPI_CMD_STORE_NAME             (ENGINE_CMD_BASE + 12)
+# define CAPI_CMD_STORE_FLAGS            (ENGINE_CMD_BASE + 13)
+
+static const ENGINE_CMD_DEFN capi_cmd_defns[] = {
+    {CAPI_CMD_LIST_CERTS,
+     "list_certs",
+     "List all certificates in store",
+     ENGINE_CMD_FLAG_NO_INPUT},
+    {CAPI_CMD_LOOKUP_CERT,
+     "lookup_cert",
+     "Lookup and output certificates",
+     ENGINE_CMD_FLAG_STRING},
+    {CAPI_CMD_DEBUG_LEVEL,
+     "debug_level",
+     "debug level (1=errors, 2=trace)",
+     ENGINE_CMD_FLAG_NUMERIC},
+    {CAPI_CMD_DEBUG_FILE,
+     "debug_file",
+     "debugging filename)",
+     ENGINE_CMD_FLAG_STRING},
+    {CAPI_CMD_KEYTYPE,
+     "key_type",
+     "Key type: 1=AT_KEYEXCHANGE (default), 2=AT_SIGNATURE",
+     ENGINE_CMD_FLAG_NUMERIC},
+    {CAPI_CMD_LIST_CSPS,
+     "list_csps",
+     "List all CSPs",
+     ENGINE_CMD_FLAG_NO_INPUT},
+    {CAPI_CMD_SET_CSP_IDX,
+     "csp_idx",
+     "Set CSP by index",
+     ENGINE_CMD_FLAG_NUMERIC},
+    {CAPI_CMD_SET_CSP_NAME,
+     "csp_name",
+     "Set CSP name, (default CSP used if not specified)",
+     ENGINE_CMD_FLAG_STRING},
+    {CAPI_CMD_SET_CSP_TYPE,
+     "csp_type",
+     "Set CSP type, (default RSA_PROV_FULL)",
+     ENGINE_CMD_FLAG_NUMERIC},
+    {CAPI_CMD_LIST_CONTAINERS,
+     "list_containers",
+     "list container names",
+     ENGINE_CMD_FLAG_NO_INPUT},
+    {CAPI_CMD_LIST_OPTIONS,
+     "list_options",
+     "Set list options (1=summary,2=friendly name, 4=full printout, 8=PEM output, 16=XXX, "
+     "32=private key info)",
+     ENGINE_CMD_FLAG_NUMERIC},
+    {CAPI_CMD_LOOKUP_METHOD,
+     "lookup_method",
+     "Set key lookup method (1=substring, 2=friendlyname, 3=container name)",
+     ENGINE_CMD_FLAG_NUMERIC},
+    {CAPI_CMD_STORE_NAME,
+     "store_name",
+     "certificate store name, default \"MY\"",
+     ENGINE_CMD_FLAG_STRING},
+    {CAPI_CMD_STORE_FLAGS,
+     "store_flags",
+     "Certificate store flags: 1 = system store",
+     ENGINE_CMD_FLAG_NUMERIC},
+
+    {0, NULL, NULL, 0}
+};
+
+static int capi_idx = -1;
+static int rsa_capi_idx = -1;
+static int dsa_capi_idx = -1;
+static int cert_capi_idx = -1;
+
+static int capi_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
+{
+    int ret = 1;
+    CAPI_CTX *ctx;
+    BIO *out;
+    LPSTR tmpstr;
+    if (capi_idx == -1) {
+        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_ENGINE_NOT_INITIALIZED);
+        return 0;
+    }
+    ctx = ENGINE_get_ex_data(e, capi_idx);
+    out = BIO_new_fp(stdout, BIO_NOCLOSE);
+    if (out == NULL) {
+        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_FILE_OPEN_ERROR);
+        return 0;
+    }
+    switch (cmd) {
+    case CAPI_CMD_LIST_CSPS:
+        ret = capi_list_providers(ctx, out);
+        break;
+
+    case CAPI_CMD_LIST_CERTS:
+        ret = capi_list_certs(ctx, out, NULL);
+        break;
+
+    case CAPI_CMD_LOOKUP_CERT:
+        ret = capi_list_certs(ctx, out, p);
+        break;
+
+    case CAPI_CMD_LIST_CONTAINERS:
+        ret = capi_list_containers(ctx, out);
+        break;
+
+    case CAPI_CMD_STORE_NAME:
+        tmpstr = OPENSSL_strdup(p);
+        if (tmpstr != NULL) {
+            OPENSSL_free(ctx->storename);
+            ctx->storename = tmpstr;
+            CAPI_trace(ctx, "Setting store name to %s\n", p);
+        } else {
+            CAPIerr(CAPI_F_CAPI_CTRL, ERR_R_MALLOC_FAILURE);
+            ret = 0;
+        }
+        break;
+
+    case CAPI_CMD_STORE_FLAGS:
+        if (i & 1) {
+            ctx->store_flags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
+            ctx->store_flags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
+        } else {
+            ctx->store_flags |= CERT_SYSTEM_STORE_CURRENT_USER;
+            ctx->store_flags &= ~CERT_SYSTEM_STORE_LOCAL_MACHINE;
+        }
+        CAPI_trace(ctx, "Setting flags to %d\n", i);
+        break;
+
+    case CAPI_CMD_DEBUG_LEVEL:
+        ctx->debug_level = (int)i;
+        CAPI_trace(ctx, "Setting debug level to %d\n", ctx->debug_level);
+        break;
+
+    case CAPI_CMD_DEBUG_FILE:
+        tmpstr = OPENSSL_strdup(p);
+        if (tmpstr != NULL) {
+            ctx->debug_file = tmpstr;
+            CAPI_trace(ctx, "Setting debug file to %s\n", ctx->debug_file);
+        } else {
+            CAPIerr(CAPI_F_CAPI_CTRL, ERR_R_MALLOC_FAILURE);
+            ret = 0;
+        }
+        break;
+
+    case CAPI_CMD_KEYTYPE:
+        ctx->keytype = i;
+        CAPI_trace(ctx, "Setting key type to %d\n", ctx->keytype);
+        break;
+
+    case CAPI_CMD_SET_CSP_IDX:
+        ret = capi_ctx_set_provname_idx(ctx, i);
+        break;
+
+    case CAPI_CMD_LIST_OPTIONS:
+        ctx->dump_flags = i;
+        break;
+
+    case CAPI_CMD_LOOKUP_METHOD:
+        if (i < 1 || i > 3) {
+            CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_INVALID_LOOKUP_METHOD);
+            BIO_free(out);
+            return 0;
+        }
+        ctx->lookup_method = i;
+        break;
+
+    case CAPI_CMD_SET_CSP_NAME:
+        ret = capi_ctx_set_provname(ctx, p, ctx->csptype, 1);
+        break;
+
+    case CAPI_CMD_SET_CSP_TYPE:
+        ctx->csptype = i;
+        break;
+
+    default:
+        CAPIerr(CAPI_F_CAPI_CTRL, CAPI_R_UNKNOWN_COMMAND);
+        ret = 0;
+    }
+
+    BIO_free(out);
+    return ret;
+
+}
+
+static RSA_METHOD *capi_rsa_method = NULL;
+# ifndef OPENSSL_NO_DSA
+static DSA_METHOD *capi_dsa_method = NULL;
+# endif
+
+static int use_aes_csp = 0;
+static const WCHAR rsa_aes_cspname[] =
+    L"Microsoft Enhanced RSA and AES Cryptographic Provider";
+static const WCHAR rsa_enh_cspname[] =
+    L"Microsoft Enhanced Cryptographic Provider v1.0";
+
+static int capi_init(ENGINE *e)
+{
+    CAPI_CTX *ctx;
+    const RSA_METHOD *ossl_rsa_meth;
+# ifndef OPENSSL_NO_DSA
+    const DSA_METHOD *ossl_dsa_meth;
+# endif
+    HCRYPTPROV hprov;
+
+    if (capi_idx < 0) {
+        capi_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0);
+        if (capi_idx < 0)
+            goto memerr;
+
+        cert_capi_idx = X509_get_ex_new_index(0, NULL, NULL, NULL, 0);
+
+        /* Setup RSA_METHOD */
+        rsa_capi_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
+        ossl_rsa_meth = RSA_PKCS1_OpenSSL();
+        if (   !RSA_meth_set_pub_enc(capi_rsa_method,
+                                     RSA_meth_get_pub_enc(ossl_rsa_meth))
+            || !RSA_meth_set_pub_dec(capi_rsa_method,
+                                     RSA_meth_get_pub_dec(ossl_rsa_meth))
+            || !RSA_meth_set_priv_enc(capi_rsa_method, capi_rsa_priv_enc)
+            || !RSA_meth_set_priv_dec(capi_rsa_method, capi_rsa_priv_dec)
+            || !RSA_meth_set_mod_exp(capi_rsa_method,
+                                     RSA_meth_get_mod_exp(ossl_rsa_meth))
+            || !RSA_meth_set_bn_mod_exp(capi_rsa_method,
+                                        RSA_meth_get_bn_mod_exp(ossl_rsa_meth))
+            || !RSA_meth_set_finish(capi_rsa_method, capi_rsa_free)
+            || !RSA_meth_set_sign(capi_rsa_method, capi_rsa_sign)) {
+            goto memerr;
+        }
+
+# ifndef OPENSSL_NO_DSA
+        /* Setup DSA Method */
+        dsa_capi_idx = DSA_get_ex_new_index(0, NULL, NULL, NULL, 0);
+        ossl_dsa_meth = DSA_OpenSSL();
+        if (   !DSA_meth_set_sign(capi_dsa_method, capi_dsa_do_sign)
+            || !DSA_meth_set_verify(capi_dsa_method,
+                                    DSA_meth_get_verify(ossl_dsa_meth))
+            || !DSA_meth_set_finish(capi_dsa_method, capi_dsa_free)
+            || !DSA_meth_set_mod_exp(capi_dsa_method,
+                                     DSA_meth_get_mod_exp(ossl_dsa_meth))
+            || !DSA_meth_set_bn_mod_exp(capi_dsa_method,
+                                    DSA_meth_get_bn_mod_exp(ossl_dsa_meth))) {
+            goto memerr;
+        }
+# endif
+    }
+
+    ctx = capi_ctx_new();
+    if (ctx == NULL)
+        goto memerr;
+
+    ENGINE_set_ex_data(e, capi_idx, ctx);
+
+# ifdef OPENSSL_CAPIENG_DIALOG
+    {
+        HMODULE cryptui = LoadLibrary(TEXT("CRYPTUI.DLL"));
+        HMODULE kernel = GetModuleHandle(TEXT("KERNEL32.DLL"));
+        if (cryptui)
+            ctx->certselectdlg =
+                (CERTDLG) GetProcAddress(cryptui,
+                                         "CryptUIDlgSelectCertificateFromStore");
+        if (kernel)
+            ctx->getconswindow =
+                (GETCONSWIN) GetProcAddress(kernel, "GetConsoleWindow");
+        if (cryptui && !OPENSSL_isservice())
+            ctx->client_cert_select = cert_select_dialog;
+    }
+# endif
+
+    /* See if there is RSA+AES CSP */
+    if (CryptAcquireContextW(&hprov, NULL, rsa_aes_cspname, PROV_RSA_AES,
+                             CRYPT_VERIFYCONTEXT)) {
+        use_aes_csp = 1;
+        CryptReleaseContext(hprov, 0);
+    }
+
+    return 1;
+
+ memerr:
+    CAPIerr(CAPI_F_CAPI_INIT, ERR_R_MALLOC_FAILURE);
+    return 0;
+
+    return 1;
+}
+
+static int capi_destroy(ENGINE *e)
+{
+    RSA_meth_free(capi_rsa_method);
+    capi_rsa_method = NULL;
+# ifndef OPENSSL_NO_DSA
+    DSA_meth_free(capi_dsa_method);
+    capi_dsa_method = NULL;
+# endif
+    ERR_unload_CAPI_strings();
+    return 1;
+}
+
+static int capi_finish(ENGINE *e)
+{
+    CAPI_CTX *ctx;
+    ctx = ENGINE_get_ex_data(e, capi_idx);
+    capi_ctx_free(ctx);
+    ENGINE_set_ex_data(e, capi_idx, NULL);
+    return 1;
+}
+
+/*
+ * CryptoAPI key application data. This contains a handle to the private key
+ * container (for sign operations) and a handle to the key (for decrypt
+ * operations).
+ */
+
+struct CAPI_KEY_st {
+    /* Associated certificate context (if any) */
+    PCCERT_CONTEXT pcert;
+    HCRYPTPROV hprov;
+    HCRYPTKEY key;
+    DWORD keyspec;
+};
+
+static int bind_capi(ENGINE *e)
+{
+    capi_rsa_method = RSA_meth_new("CryptoAPI RSA method", 0);
+    if (capi_rsa_method == NULL)
+        return 0;
+# ifndef OPENSSL_NO_DSA
+    capi_dsa_method = DSA_meth_new("CryptoAPI DSA method", 0);
+    if (capi_dsa_method == NULL)
+        goto memerr;
+# endif
+    if (!ENGINE_set_id(e, engine_capi_id)
+        || !ENGINE_set_name(e, engine_capi_name)
+        || !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL)
+        || !ENGINE_set_init_function(e, capi_init)
+        || !ENGINE_set_finish_function(e, capi_finish)
+        || !ENGINE_set_destroy_function(e, capi_destroy)
+        || !ENGINE_set_RSA(e, capi_rsa_method)
+# ifndef OPENSSL_NO_DSA
+        || !ENGINE_set_DSA(e, capi_dsa_method)
+# endif
+        || !ENGINE_set_load_privkey_function(e, capi_load_privkey)
+        || !ENGINE_set_load_ssl_client_cert_function(e,
+                                                     capi_load_ssl_client_cert)
+        || !ENGINE_set_cmd_defns(e, capi_cmd_defns)
+        || !ENGINE_set_ctrl_function(e, capi_ctrl))
+        goto memerr;
+    ERR_load_CAPI_strings();
+
+    return 1;
+ memerr:
+    RSA_meth_free(capi_rsa_method);
+    capi_rsa_method = NULL;
+# ifndef OPENSSL_NO_DSA
+    DSA_meth_free(capi_dsa_method);
+    capi_dsa_method = NULL;
+# endif
+    return 0;
+}
+
+# ifndef OPENSSL_NO_DYNAMIC_ENGINE
+static int bind_helper(ENGINE *e, const char *id)
+{
+    if (id && (strcmp(id, engine_capi_id) != 0))
+        return 0;
+    if (!bind_capi(e))
+        return 0;
+    return 1;
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
+# else
+static ENGINE *engine_capi(void)
+{
+    ENGINE *ret = ENGINE_new();
+    if (ret == NULL)
+        return NULL;
+    if (!bind_capi(ret)) {
+        ENGINE_free(ret);
+        return NULL;
+    }
+    return ret;
+}
+
+void engine_load_capi_int(void)
+{
+    /* Copied from eng_[openssl|dyn].c */
+    ENGINE *toadd = engine_capi();
+    if (!toadd)
+        return;
+    ENGINE_add(toadd);
+    ENGINE_free(toadd);
+    ERR_clear_error();
+}
+# endif
+
+static int lend_tobn(BIGNUM *bn, unsigned char *bin, int binlen)
+{
+    int i;
+    /*
+     * Reverse buffer in place: since this is a keyblob structure that will
+     * be freed up after conversion anyway it doesn't matter if we change
+     * it.
+     */
+    for (i = 0; i < binlen / 2; i++) {
+        unsigned char c;
+        c = bin[i];
+        bin[i] = bin[binlen - i - 1];
+        bin[binlen - i - 1] = c;
+    }
+
+    if (!BN_bin2bn(bin, binlen, bn))
+        return 0;
+    return 1;
+}
+
+/* Given a CAPI_KEY get an EVP_PKEY structure */
+
+static EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY *key)
+{
+    unsigned char *pubkey = NULL;
+    DWORD len;
+    BLOBHEADER *bh;
+    RSA *rkey = NULL;
+    DSA *dkey = NULL;
+    EVP_PKEY *ret = NULL;
+    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, NULL, &len)) {
+        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR);
+        capi_addlasterror();
+        return NULL;
+    }
+
+    pubkey = OPENSSL_malloc(len);
+
+    if (pubkey == NULL)
+        goto memerr;
+
+    if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) {
+        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
+        capi_addlasterror();
+        goto err;
+    }
+
+    bh = (BLOBHEADER *) pubkey;
+    if (bh->bType != PUBLICKEYBLOB) {
+        CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_INVALID_PUBLIC_KEY_BLOB);
+        goto err;
+    }
+    if (bh->aiKeyAlg == CALG_RSA_SIGN || bh->aiKeyAlg == CALG_RSA_KEYX) {
+        RSAPUBKEY *rp;
+        DWORD rsa_modlen;
+        BIGNUM *e = NULL, *n = NULL;
+        unsigned char *rsa_modulus;
+        rp = (RSAPUBKEY *) (bh + 1);
+        if (rp->magic != 0x31415352) {
+            char magstr[10];
+            BIO_snprintf(magstr, 10, "%lx", rp->magic);
+            CAPIerr(CAPI_F_CAPI_GET_PKEY,
+                    CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
+            ERR_add_error_data(2, "magic=0x", magstr);
+            goto err;
+        }
+        rsa_modulus = (unsigned char *)(rp + 1);
+        rkey = RSA_new_method(eng);
+        if (!rkey)
+            goto memerr;
+
+        e = BN_new();
+        n = BN_new();
+
+        if (e == NULL || n == NULL) {
+            BN_free(e);
+            BN_free(n);
+            goto memerr;
+        }
+
+        RSA_set0_key(rkey, n, e, NULL);
+
+        if (!BN_set_word(e, rp->pubexp))
+            goto memerr;
+
+        rsa_modlen = rp->bitlen / 8;
+        if (!lend_tobn(n, rsa_modulus, rsa_modlen))
+            goto memerr;
+
+        RSA_set_ex_data(rkey, rsa_capi_idx, key);
+
+        if ((ret = EVP_PKEY_new()) == NULL)
+            goto memerr;
+
+        EVP_PKEY_assign_RSA(ret, rkey);
+        rkey = NULL;
+
+# ifndef OPENSSL_NO_DSA
+    } else if (bh->aiKeyAlg == CALG_DSS_SIGN) {
+        DSSPUBKEY *dp;
+        DWORD dsa_plen;
+        unsigned char *btmp;
+        BIGNUM *p, *q, *g, *pub_key;
+        dp = (DSSPUBKEY *) (bh + 1);
+        if (dp->magic != 0x31535344) {
+            char magstr[10];
+            BIO_snprintf(magstr, 10, "%lx", dp->magic);
+            CAPIerr(CAPI_F_CAPI_GET_PKEY,
+                    CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER);
+            ERR_add_error_data(2, "magic=0x", magstr);
+            goto err;
+        }
+        dsa_plen = dp->bitlen / 8;
+        btmp = (unsigned char *)(dp + 1);
+        dkey = DSA_new_method(eng);
+        if (!dkey)
+            goto memerr;
+        p = BN_new();
+        q = BN_new();
+        g = BN_new();
+        pub_key = BN_new();
+        if (p == NULL || q == NULL || g == NULL || pub_key == NULL) {
+            BN_free(p);
+            BN_free(q);
+            BN_free(g);
+            BN_free(pub_key);
+            goto memerr;
+        }
+        DSA_set0_pqg(dkey, p, q, g);
+        DSA_set0_key(dkey, pub_key, NULL);
+        if (!lend_tobn(p, btmp, dsa_plen))
+            goto memerr;
+        btmp += dsa_plen;
+        if (!lend_tobn(q, btmp, 20))
+            goto memerr;
+        btmp += 20;
+        if (!lend_tobn(g, btmp, dsa_plen))
+            goto memerr;
+        btmp += dsa_plen;
+        if (!lend_tobn(pub_key, btmp, dsa_plen))
+            goto memerr;
+        btmp += dsa_plen;
+
+        DSA_set_ex_data(dkey, dsa_capi_idx, key);
+
+        if ((ret = EVP_PKEY_new()) == NULL)
+            goto memerr;
+
+        EVP_PKEY_assign_DSA(ret, dkey);
+        dkey = NULL;
+# endif
+    } else {
+        char algstr[10];
+        BIO_snprintf(algstr, 10, "%ux", bh->aiKeyAlg);
+        CAPIerr(CAPI_F_CAPI_GET_PKEY,
+                CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM);
+        ERR_add_error_data(2, "aiKeyAlg=0x", algstr);
+        goto err;
+    }
+
+ err:
+    OPENSSL_free(pubkey);
+    if (!ret) {
+        RSA_free(rkey);
+# ifndef OPENSSL_NO_DSA
+        DSA_free(dkey);
+# endif
+    }
+
+    return ret;
+
+ memerr:
+    CAPIerr(CAPI_F_CAPI_GET_PKEY, ERR_R_MALLOC_FAILURE);
+    goto err;
+
+}
+
+static EVP_PKEY *capi_load_privkey(ENGINE *eng, const char *key_id,
+                                   UI_METHOD *ui_method, void *callback_data)
+{
+    CAPI_CTX *ctx;
+    CAPI_KEY *key;
+    EVP_PKEY *ret;
+    ctx = ENGINE_get_ex_data(eng, capi_idx);
+
+    if (!ctx) {
+        CAPIerr(CAPI_F_CAPI_LOAD_PRIVKEY, CAPI_R_CANT_FIND_CAPI_CONTEXT);
+        return NULL;
+    }
+
+    key = capi_find_key(ctx, key_id);
+
+    if (!key)
+        return NULL;
+
+    ret = capi_get_pkey(eng, key);
+
+    if (!ret)
+        capi_free_key(key);
+    return ret;
+
+}
+
+/* CryptoAPI RSA operations */
+
+int capi_rsa_priv_enc(int flen, const unsigned char *from,
+                      unsigned char *to, RSA *rsa, int padding)
+{
+    CAPIerr(CAPI_F_CAPI_RSA_PRIV_ENC, CAPI_R_FUNCTION_NOT_SUPPORTED);
+    return -1;
+}
+
+int capi_rsa_sign(int dtype, const unsigned char *m, unsigned int m_len,
+                  unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
+{
+    ALG_ID alg;
+    HCRYPTHASH hash;
+    DWORD slen;
+    unsigned int i;
+    int ret = -1;
+    CAPI_KEY *capi_key;
+    CAPI_CTX *ctx;
+
+    ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx);
+
+    CAPI_trace(ctx, "Called CAPI_rsa_sign()\n");
+
+    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
+    if (!capi_key) {
+        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_GET_KEY);
+        return -1;
+    }
+    /* Convert the signature type to a CryptoAPI algorithm ID */
+    switch (dtype) {
+    case NID_sha256:
+        alg = CALG_SHA_256;
+        break;
+
+    case NID_sha384:
+        alg = CALG_SHA_384;
+        break;
+
+    case NID_sha512:
+        alg = CALG_SHA_512;
+        break;
+
+    case NID_sha1:
+        alg = CALG_SHA1;
+        break;
+
+    case NID_md5:
+        alg = CALG_MD5;
+        break;
+
+    case NID_md5_sha1:
+        alg = CALG_SSL3_SHAMD5;
+        break;
+    default:
+        {
+            char algstr[10];
+            BIO_snprintf(algstr, 10, "%x", dtype);
+            CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_UNSUPPORTED_ALGORITHM_NID);
+            ERR_add_error_data(2, "NID=0x", algstr);
+            return -1;
+        }
+    }
+
+    /* Create the hash object */
+    if (!CryptCreateHash(capi_key->hprov, alg, 0, 0, &hash)) {
+        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
+        capi_addlasterror();
+        return -1;
+    }
+    /* Set the hash value to the value passed */
+
+    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)m, 0)) {
+        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
+        capi_addlasterror();
+        goto err;
+    }
+
+    /* Finally sign it */
+    slen = RSA_size(rsa);
+    if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, sigret, &slen)) {
+        CAPIerr(CAPI_F_CAPI_RSA_SIGN, CAPI_R_ERROR_SIGNING_HASH);
+        capi_addlasterror();
+        goto err;
+    } else {
+        ret = 1;
+        /* Inplace byte reversal of signature */
+        for (i = 0; i < slen / 2; i++) {
+            unsigned char c;
+            c = sigret[i];
+            sigret[i] = sigret[slen - i - 1];
+            sigret[slen - i - 1] = c;
+        }
+        *siglen = slen;
+    }
+
+    /* Now cleanup */
+
+ err:
+    CryptDestroyHash(hash);
+
+    return ret;
+}
+
+int capi_rsa_priv_dec(int flen, const unsigned char *from,
+                      unsigned char *to, RSA *rsa, int padding)
+{
+    int i;
+    unsigned char *tmpbuf;
+    CAPI_KEY *capi_key;
+    CAPI_CTX *ctx;
+    DWORD flags = 0;
+    DWORD dlen;
+
+    if (flen <= 0)
+        return flen;
+
+    ctx = ENGINE_get_ex_data(RSA_get0_engine(rsa), capi_idx);
+
+    CAPI_trace(ctx, "Called capi_rsa_priv_dec()\n");
+
+    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
+    if (!capi_key) {
+        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_CANT_GET_KEY);
+        return -1;
+    }
+
+    switch (padding) {
+    case RSA_PKCS1_PADDING:
+        /* Nothing to do */
+        break;
+#ifdef CRYPT_DECRYPT_RSA_NO_PADDING_CHECK
+    case RSA_NO_PADDING:
+        flags = CRYPT_DECRYPT_RSA_NO_PADDING_CHECK;
+        break;
+#endif
+    default:
+        {
+            char errstr[10];
+            BIO_snprintf(errstr, 10, "%d", padding);
+            CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_UNSUPPORTED_PADDING);
+            ERR_add_error_data(2, "padding=", errstr);
+            return -1;
+        }
+    }
+
+    /* Create temp reverse order version of input */
+    if ((tmpbuf = OPENSSL_malloc(flen)) == NULL) {
+        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+    for (i = 0; i < flen; i++)
+        tmpbuf[flen - i - 1] = from[i];
+
+    /* Finally decrypt it */
+    dlen = flen;
+    if (!CryptDecrypt(capi_key->key, 0, TRUE, flags, tmpbuf, &dlen)) {
+        CAPIerr(CAPI_F_CAPI_RSA_PRIV_DEC, CAPI_R_DECRYPT_ERROR);
+        capi_addlasterror();
+        OPENSSL_cleanse(tmpbuf, dlen);
+        OPENSSL_free(tmpbuf);
+        return -1;
+    } else {
+        memcpy(to, tmpbuf, (flen = (int)dlen));
+    }
+    OPENSSL_cleanse(tmpbuf, flen);
+    OPENSSL_free(tmpbuf);
+
+    return flen;
+}
+
+static int capi_rsa_free(RSA *rsa)
+{
+    CAPI_KEY *capi_key;
+    capi_key = RSA_get_ex_data(rsa, rsa_capi_idx);
+    capi_free_key(capi_key);
+    RSA_set_ex_data(rsa, rsa_capi_idx, 0);
+    return 1;
+}
+
+# ifndef OPENSSL_NO_DSA
+/* CryptoAPI DSA operations */
+
+static DSA_SIG *capi_dsa_do_sign(const unsigned char *digest, int dlen,
+                                 DSA *dsa)
+{
+    HCRYPTHASH hash;
+    DWORD slen;
+    DSA_SIG *ret = NULL;
+    CAPI_KEY *capi_key;
+    CAPI_CTX *ctx;
+    unsigned char csigbuf[40];
+
+    ctx = ENGINE_get_ex_data(DSA_get0_engine(dsa), capi_idx);
+
+    CAPI_trace(ctx, "Called CAPI_dsa_do_sign()\n");
+
+    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
+
+    if (!capi_key) {
+        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_GET_KEY);
+        return NULL;
+    }
+
+    if (dlen != 20) {
+        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_INVALID_DIGEST_LENGTH);
+        return NULL;
+    }
+
+    /* Create the hash object */
+    if (!CryptCreateHash(capi_key->hprov, CALG_SHA1, 0, 0, &hash)) {
+        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_CREATE_HASH_OBJECT);
+        capi_addlasterror();
+        return NULL;
+    }
+
+    /* Set the hash value to the value passed */
+    if (!CryptSetHashParam(hash, HP_HASHVAL, (unsigned char *)digest, 0)) {
+        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_CANT_SET_HASH_VALUE);
+        capi_addlasterror();
+        goto err;
+    }
+
+    /* Finally sign it */
+    slen = sizeof(csigbuf);
+    if (!CryptSignHash(hash, capi_key->keyspec, NULL, 0, csigbuf, &slen)) {
+        CAPIerr(CAPI_F_CAPI_DSA_DO_SIGN, CAPI_R_ERROR_SIGNING_HASH);
+        capi_addlasterror();
+        goto err;
+    } else {
+        BIGNUM *r = BN_new(), *s = BN_new();
+
+        if (r == NULL || s == NULL
+            || !lend_tobn(r, csigbuf, 20)
+            || !lend_tobn(s, csigbuf + 20, 20)
+            || (ret = DSA_SIG_new()) == NULL) {
+            BN_free(r); /* BN_free checks for BIGNUM * being NULL */
+            BN_free(s);
+            goto err;
+        }
+        DSA_SIG_set0(ret, r, s);
+    }
+
+    /* Now cleanup */
+
+ err:
+    OPENSSL_cleanse(csigbuf, 40);
+    CryptDestroyHash(hash);
+    return ret;
+}
+
+static int capi_dsa_free(DSA *dsa)
+{
+    CAPI_KEY *capi_key;
+    capi_key = DSA_get_ex_data(dsa, dsa_capi_idx);
+    capi_free_key(capi_key);
+    DSA_set_ex_data(dsa, dsa_capi_idx, 0);
+    return 1;
+}
+# endif
+
+static void capi_vtrace(CAPI_CTX *ctx, int level, char *format,
+                        va_list argptr)
+{
+    BIO *out;
+
+    if (!ctx || (ctx->debug_level < level) || (!ctx->debug_file))
+        return;
+    out = BIO_new_file(ctx->debug_file, "a+");
+    if (out == NULL) {
+        CAPIerr(CAPI_F_CAPI_VTRACE, CAPI_R_FILE_OPEN_ERROR);
+        return;
+    }
+    BIO_vprintf(out, format, argptr);
+    BIO_free(out);
+}
+
+static void CAPI_trace(CAPI_CTX *ctx, char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    capi_vtrace(ctx, CAPI_DBG_TRACE, format, args);
+    va_end(args);
+}
+
+static void capi_addlasterror(void)
+{
+    capi_adderror(GetLastError());
+}
+
+static void capi_adderror(DWORD err)
+{
+    char errstr[10];
+    BIO_snprintf(errstr, 10, "%lX", err);
+    ERR_add_error_data(2, "Error code= 0x", errstr);
+}
+
+static char *wide_to_asc(LPCWSTR wstr)
+{
+    char *str;
+    int len_0, sz;
+
+    if (!wstr)
+        return NULL;
+    len_0 = (int)wcslen(wstr) + 1; /* WideCharToMultiByte expects int */
+    sz = WideCharToMultiByte(CP_ACP, 0, wstr, len_0, NULL, 0, NULL, NULL);
+    if (!sz) {
+        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
+        return NULL;
+    }
+    str = OPENSSL_malloc(sz);
+    if (str == NULL) {
+        CAPIerr(CAPI_F_WIDE_TO_ASC, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    if (!WideCharToMultiByte(CP_ACP, 0, wstr, len_0, str, sz, NULL, NULL)) {
+        OPENSSL_free(str);
+        CAPIerr(CAPI_F_WIDE_TO_ASC, CAPI_R_WIN32_ERROR);
+        return NULL;
+    }
+    return str;
+}
+
+static int capi_get_provname(CAPI_CTX *ctx, LPSTR *pname, DWORD *ptype,
+                             DWORD idx)
+{
+    DWORD len, err;
+    LPTSTR name;
+    CAPI_trace(ctx, "capi_get_provname, index=%d\n", idx);
+    if (!CryptEnumProviders(idx, NULL, 0, ptype, NULL, &len)) {
+        err = GetLastError();
+        if (err == ERROR_NO_MORE_ITEMS)
+            return 2;
+        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
+        capi_adderror(err);
+        return 0;
+    }
+    name = OPENSSL_malloc(len);
+    if (name == NULL) {
+        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    if (!CryptEnumProviders(idx, NULL, 0, ptype, name, &len)) {
+        err = GetLastError();
+        OPENSSL_free(name);
+        if (err == ERROR_NO_MORE_ITEMS)
+            return 2;
+        CAPIerr(CAPI_F_CAPI_GET_PROVNAME, CAPI_R_CRYPTENUMPROVIDERS_ERROR);
+        capi_adderror(err);
+        return 0;
+    }
+    if (sizeof(TCHAR) != sizeof(char)) {
+        *pname = wide_to_asc((WCHAR *)name);
+        OPENSSL_free(name);
+        if (*pname == NULL)
+            return 0;
+    } else {
+        *pname = (char *)name;
+    }
+    CAPI_trace(ctx, "capi_get_provname, returned name=%s, type=%d\n", *pname,
+               *ptype);
+
+    return 1;
+}
+
+static int capi_list_providers(CAPI_CTX *ctx, BIO *out)
+{
+    DWORD idx, ptype;
+    int ret;
+    LPSTR provname = NULL;
+    CAPI_trace(ctx, "capi_list_providers\n");
+    BIO_printf(out, "Available CSPs:\n");
+    for (idx = 0;; idx++) {
+        ret = capi_get_provname(ctx, &provname, &ptype, idx);
+        if (ret == 2)
+            break;
+        if (ret == 0)
+            break;
+        BIO_printf(out, "%lu. %s, type %lu\n", idx, provname, ptype);
+        OPENSSL_free(provname);
+    }
+    return 1;
+}
+
+static int capi_list_containers(CAPI_CTX *ctx, BIO *out)
+{
+    int ret = 1;
+    HCRYPTPROV hprov;
+    DWORD err, idx, flags, buflen = 0, clen;
+    LPSTR cname;
+    LPWSTR cspname = NULL;
+
+    CAPI_trace(ctx, "Listing containers CSP=%s, type = %d\n", ctx->cspname,
+               ctx->csptype);
+    if (ctx->cspname != NULL) {
+        if ((clen = MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1,
+                                        NULL, 0))) {
+            cspname = alloca(clen * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1, (WCHAR *)cspname,
+                                clen);
+        }
+        if (cspname == NULL) {
+            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
+            capi_addlasterror();
+            return 0;
+        }
+    }
+    if (!CryptAcquireContextW(&hprov, NULL, cspname, ctx->csptype,
+                              CRYPT_VERIFYCONTEXT)) {
+        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS,
+                CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
+        capi_addlasterror();
+        return 0;
+    }
+    if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, NULL, &buflen,
+                           CRYPT_FIRST)) {
+        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
+        capi_addlasterror();
+        CryptReleaseContext(hprov, 0);
+        return 0;
+    }
+    CAPI_trace(ctx, "Got max container len %d\n", buflen);
+    if (buflen == 0)
+        buflen = 1024;
+    cname = OPENSSL_malloc(buflen);
+    if (cname == NULL) {
+        CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    for (idx = 0;; idx++) {
+        clen = buflen;
+        cname[0] = 0;
+
+        if (idx == 0)
+            flags = CRYPT_FIRST;
+        else
+            flags = 0;
+        if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS, (BYTE *)cname,
+                               &clen, flags)) {
+            err = GetLastError();
+            if (err == ERROR_NO_MORE_ITEMS)
+                goto done;
+            CAPIerr(CAPI_F_CAPI_LIST_CONTAINERS, CAPI_R_ENUMCONTAINERS_ERROR);
+            capi_adderror(err);
+            goto err;
+        }
+        CAPI_trace(ctx, "Container name %s, len=%d, index=%d, flags=%d\n",
+                   cname, clen, idx, flags);
+        if (!cname[0] && (clen == buflen)) {
+            CAPI_trace(ctx, "Enumerate bug: using workaround\n");
+            goto done;
+        }
+        BIO_printf(out, "%lu. %s\n", idx, cname);
+    }
+ err:
+
+    ret = 0;
+
+ done:
+    OPENSSL_free(cname);
+    CryptReleaseContext(hprov, 0);
+
+    return ret;
+}
+
+static CRYPT_KEY_PROV_INFO *capi_get_prov_info(CAPI_CTX *ctx,
+                                               PCCERT_CONTEXT cert)
+{
+    DWORD len;
+    CRYPT_KEY_PROV_INFO *pinfo;
+
+    if (!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID,
+                                           NULL, &len))
+        return NULL;
+    pinfo = OPENSSL_malloc(len);
+    if (pinfo == NULL) {
+        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    if (!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID,
+                                           pinfo, &len)) {
+        CAPIerr(CAPI_F_CAPI_GET_PROV_INFO,
+                CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO);
+        capi_addlasterror();
+        OPENSSL_free(pinfo);
+        return NULL;
+    }
+    return pinfo;
+}
+
+static void capi_dump_prov_info(CAPI_CTX *ctx, BIO *out,
+                                CRYPT_KEY_PROV_INFO *pinfo)
+{
+    char *provname = NULL, *contname = NULL;
+    if (!pinfo) {
+        BIO_printf(out, "  No Private Key\n");
+        return;
+    }
+    provname = wide_to_asc(pinfo->pwszProvName);
+    contname = wide_to_asc(pinfo->pwszContainerName);
+    if (!provname || !contname)
+        goto err;
+
+    BIO_printf(out, "  Private Key Info:\n");
+    BIO_printf(out, "    Provider Name:  %s, Provider Type %lu\n", provname,
+               pinfo->dwProvType);
+    BIO_printf(out, "    Container Name: %s, Key Type %lu\n", contname,
+               pinfo->dwKeySpec);
+ err:
+    OPENSSL_free(provname);
+    OPENSSL_free(contname);
+}
+
+static char *capi_cert_get_fname(CAPI_CTX *ctx, PCCERT_CONTEXT cert)
+{
+    LPWSTR wfname;
+    DWORD dlen;
+
+    CAPI_trace(ctx, "capi_cert_get_fname\n");
+    if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
+                                           NULL, &dlen))
+        return NULL;
+    wfname = OPENSSL_malloc(dlen);
+    if (wfname == NULL)
+        return NULL;
+    if (CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
+                                          wfname, &dlen)) {
+        char *fname = wide_to_asc(wfname);
+        OPENSSL_free(wfname);
+        return fname;
+    }
+    CAPIerr(CAPI_F_CAPI_CERT_GET_FNAME, CAPI_R_ERROR_GETTING_FRIENDLY_NAME);
+    capi_addlasterror();
+
+    OPENSSL_free(wfname);
+    return NULL;
+}
+
+static void capi_dump_cert(CAPI_CTX *ctx, BIO *out, PCCERT_CONTEXT cert)
+{
+    X509 *x;
+    const unsigned char *p;
+    unsigned long flags = ctx->dump_flags;
+    if (flags & CAPI_DMP_FNAME) {
+        char *fname;
+        fname = capi_cert_get_fname(ctx, cert);
+        if (fname) {
+            BIO_printf(out, "  Friendly Name \"%s\"\n", fname);
+            OPENSSL_free(fname);
+        } else {
+            BIO_printf(out, "  <No Friendly Name>\n");
+        }
+    }
+
+    p = cert->pbCertEncoded;
+    x = d2i_X509(NULL, &p, cert->cbCertEncoded);
+    if (!x)
+        BIO_printf(out, "  <Can't parse certificate>\n");
+    if (flags & CAPI_DMP_SUMMARY) {
+        BIO_printf(out, "  Subject: ");
+        X509_NAME_print_ex(out, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
+        BIO_printf(out, "\n  Issuer: ");
+        X509_NAME_print_ex(out, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
+        BIO_printf(out, "\n");
+    }
+    if (flags & CAPI_DMP_FULL)
+        X509_print_ex(out, x, XN_FLAG_ONELINE, 0);
+
+    if (flags & CAPI_DMP_PKEYINFO) {
+        CRYPT_KEY_PROV_INFO *pinfo;
+        pinfo = capi_get_prov_info(ctx, cert);
+        capi_dump_prov_info(ctx, out, pinfo);
+        OPENSSL_free(pinfo);
+    }
+
+    if (flags & CAPI_DMP_PEM)
+        PEM_write_bio_X509(out, x);
+    X509_free(x);
+}
+
+static HCERTSTORE capi_open_store(CAPI_CTX *ctx, char *storename)
+{
+    HCERTSTORE hstore;
+
+    if (!storename)
+        storename = ctx->storename;
+    if (!storename)
+        storename = "MY";
+    CAPI_trace(ctx, "Opening certificate store %s\n", storename);
+
+    hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
+                           ctx->store_flags, storename);
+    if (!hstore) {
+        CAPIerr(CAPI_F_CAPI_OPEN_STORE, CAPI_R_ERROR_OPENING_STORE);
+        capi_addlasterror();
+    }
+    return hstore;
+}
+
+int capi_list_certs(CAPI_CTX *ctx, BIO *out, char *id)
+{
+    char *storename;
+    int idx;
+    int ret = 1;
+    HCERTSTORE hstore;
+    PCCERT_CONTEXT cert = NULL;
+
+    storename = ctx->storename;
+    if (!storename)
+        storename = "MY";
+    CAPI_trace(ctx, "Listing certs for store %s\n", storename);
+
+    hstore = capi_open_store(ctx, storename);
+    if (!hstore)
+        return 0;
+    if (id) {
+        cert = capi_find_cert(ctx, id, hstore);
+        if (!cert) {
+            ret = 0;
+            goto err;
+        }
+        capi_dump_cert(ctx, out, cert);
+        CertFreeCertificateContext(cert);
+    } else {
+        for (idx = 0;; idx++) {
+            cert = CertEnumCertificatesInStore(hstore, cert);
+            if (!cert)
+                break;
+            BIO_printf(out, "Certificate %d\n", idx);
+            capi_dump_cert(ctx, out, cert);
+        }
+    }
+ err:
+    CertCloseStore(hstore, 0);
+    return ret;
+}
+
+static PCCERT_CONTEXT capi_find_cert(CAPI_CTX *ctx, const char *id,
+                                     HCERTSTORE hstore)
+{
+    PCCERT_CONTEXT cert = NULL;
+    char *fname = NULL;
+    int match;
+    switch (ctx->lookup_method) {
+    case CAPI_LU_SUBSTR:
+        return CertFindCertificateInStore(hstore, X509_ASN_ENCODING, 0,
+                                          CERT_FIND_SUBJECT_STR_A, id, NULL);
+    case CAPI_LU_FNAME:
+        for (;;) {
+            cert = CertEnumCertificatesInStore(hstore, cert);
+            if (!cert)
+                return NULL;
+            fname = capi_cert_get_fname(ctx, cert);
+            if (fname) {
+                if (strcmp(fname, id))
+                    match = 0;
+                else
+                    match = 1;
+                OPENSSL_free(fname);
+                if (match)
+                    return cert;
+            }
+        }
+    default:
+        return NULL;
+    }
+}
+
+static CAPI_KEY *capi_get_key(CAPI_CTX *ctx, const WCHAR *contname,
+                              const WCHAR *provname, DWORD ptype,
+                              DWORD keyspec)
+{
+    DWORD dwFlags = 0;
+    CAPI_KEY *key = OPENSSL_malloc(sizeof(*key));
+
+    if (key == NULL)
+        return NULL;
+    /* If PROV_RSA_AES supported use it instead */
+    if (ptype == PROV_RSA_FULL && use_aes_csp &&
+        wcscmp(provname, rsa_enh_cspname) == 0) {
+        provname = rsa_aes_cspname;
+        ptype = PROV_RSA_AES;
+    }
+    if (ctx && ctx->debug_level >= CAPI_DBG_TRACE && ctx->debug_file) {
+        /*
+         * above 'if' is [complementary] copy from CAPI_trace and serves
+         * as optimization to minimize [below] malloc-ations
+         */
+        char *_contname = wide_to_asc(contname);
+        char *_provname = wide_to_asc(provname);
+
+        CAPI_trace(ctx, "capi_get_key, contname=%s, provname=%s, type=%d\n",
+                   _contname, _provname, ptype);
+        OPENSSL_free(_provname);
+        OPENSSL_free(_contname);
+    }
+    if (ctx->store_flags & CERT_SYSTEM_STORE_LOCAL_MACHINE)
+        dwFlags = CRYPT_MACHINE_KEYSET;
+    if (!CryptAcquireContextW(&key->hprov, contname, provname, ptype,
+                              dwFlags)) {
+        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
+        capi_addlasterror();
+        goto err;
+    }
+    if (!CryptGetUserKey(key->hprov, keyspec, &key->key)) {
+        CAPIerr(CAPI_F_CAPI_GET_KEY, CAPI_R_GETUSERKEY_ERROR);
+        capi_addlasterror();
+        CryptReleaseContext(key->hprov, 0);
+        goto err;
+    }
+    key->keyspec = keyspec;
+    key->pcert = NULL;
+    return key;
+
+ err:
+    OPENSSL_free(key);
+    return NULL;
+}
+
+static CAPI_KEY *capi_get_cert_key(CAPI_CTX *ctx, PCCERT_CONTEXT cert)
+{
+    CAPI_KEY *key = NULL;
+    CRYPT_KEY_PROV_INFO *pinfo = NULL;
+
+    pinfo = capi_get_prov_info(ctx, cert);
+
+    if (pinfo != NULL)
+        key = capi_get_key(ctx, pinfo->pwszContainerName, pinfo->pwszProvName,
+                           pinfo->dwProvType, pinfo->dwKeySpec);
+
+    OPENSSL_free(pinfo);
+    return key;
+}
+
+CAPI_KEY *capi_find_key(CAPI_CTX *ctx, const char *id)
+{
+    PCCERT_CONTEXT cert;
+    HCERTSTORE hstore;
+    CAPI_KEY *key = NULL;
+
+    switch (ctx->lookup_method) {
+    case CAPI_LU_SUBSTR:
+    case CAPI_LU_FNAME:
+        hstore = capi_open_store(ctx, NULL);
+        if (!hstore)
+            return NULL;
+        cert = capi_find_cert(ctx, id, hstore);
+        if (cert) {
+            key = capi_get_cert_key(ctx, cert);
+            CertFreeCertificateContext(cert);
+        }
+        CertCloseStore(hstore, 0);
+        break;
+
+    case CAPI_LU_CONTNAME:
+        {
+            WCHAR *contname, *provname;
+            DWORD len;
+
+            if ((len = MultiByteToWideChar(CP_ACP, 0, id, -1, NULL, 0)) &&
+                (contname = alloca(len * sizeof(WCHAR)),
+                 MultiByteToWideChar(CP_ACP, 0, id, -1, contname, len)) &&
+                (len = MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1,
+                                           NULL, 0)) &&
+                (provname = alloca(len * sizeof(WCHAR)),
+                 MultiByteToWideChar(CP_ACP, 0, ctx->cspname, -1,
+                                     provname, len)))
+                key = capi_get_key(ctx, contname, provname,
+                                   ctx->csptype, ctx->keytype);
+        }
+        break;
+    }
+
+    return key;
+}
+
+void capi_free_key(CAPI_KEY *key)
+{
+    if (!key)
+        return;
+    CryptDestroyKey(key->key);
+    CryptReleaseContext(key->hprov, 0);
+    if (key->pcert)
+        CertFreeCertificateContext(key->pcert);
+    OPENSSL_free(key);
+}
+
+/* Initialize a CAPI_CTX structure */
+
+static CAPI_CTX *capi_ctx_new(void)
+{
+    CAPI_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+    if (ctx == NULL) {
+        CAPIerr(CAPI_F_CAPI_CTX_NEW, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    ctx->csptype = PROV_RSA_FULL;
+    ctx->dump_flags = CAPI_DMP_SUMMARY | CAPI_DMP_FNAME;
+    ctx->keytype = AT_KEYEXCHANGE;
+    ctx->store_flags = CERT_STORE_OPEN_EXISTING_FLAG |
+        CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER;
+    ctx->lookup_method = CAPI_LU_SUBSTR;
+    ctx->client_cert_select = cert_select_simple;
+    return ctx;
+}
+
+static void capi_ctx_free(CAPI_CTX *ctx)
+{
+    CAPI_trace(ctx, "Calling capi_ctx_free with %lx\n", ctx);
+    if (!ctx)
+        return;
+    OPENSSL_free(ctx->cspname);
+    OPENSSL_free(ctx->debug_file);
+    OPENSSL_free(ctx->storename);
+    OPENSSL_free(ctx->ssl_client_store);
+    OPENSSL_free(ctx);
+}
+
+static int capi_ctx_set_provname(CAPI_CTX *ctx, LPSTR pname, DWORD type,
+                                 int check)
+{
+    LPSTR tmpcspname;
+
+    CAPI_trace(ctx, "capi_ctx_set_provname, name=%s, type=%d\n", pname, type);
+    if (check) {
+        HCRYPTPROV hprov;
+        LPWSTR name = NULL;
+        DWORD len;
+
+        if ((len = MultiByteToWideChar(CP_ACP, 0, pname, -1, NULL, 0))) {
+            name = alloca(len * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, pname, -1, (WCHAR *)name, len);
+        }
+        if (name == NULL || !CryptAcquireContextW(&hprov, NULL, name, type,
+                                                  CRYPT_VERIFYCONTEXT)) {
+            CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME,
+                    CAPI_R_CRYPTACQUIRECONTEXT_ERROR);
+            capi_addlasterror();
+            return 0;
+        }
+        CryptReleaseContext(hprov, 0);
+    }
+    tmpcspname = OPENSSL_strdup(pname);
+    if (tmpcspname == NULL) {
+        CAPIerr(CAPI_F_CAPI_CTX_SET_PROVNAME, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    OPENSSL_free(ctx->cspname);
+    ctx->cspname = tmpcspname;
+    ctx->csptype = type;
+    return 1;
+}
+
+static int capi_ctx_set_provname_idx(CAPI_CTX *ctx, int idx)
+{
+    LPSTR pname;
+    DWORD type;
+    int res;
+    if (capi_get_provname(ctx, &pname, &type, idx) != 1)
+        return 0;
+    res = capi_ctx_set_provname(ctx, pname, type, 0);
+    OPENSSL_free(pname);
+    return res;
+}
+
+static int cert_issuer_match(STACK_OF(X509_NAME) *ca_dn, X509 *x)
+{
+    int i;
+    X509_NAME *nm;
+    /* Special case: empty list: match anything */
+    if (sk_X509_NAME_num(ca_dn) <= 0)
+        return 1;
+    for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) {
+        nm = sk_X509_NAME_value(ca_dn, i);
+        if (!X509_NAME_cmp(nm, X509_get_issuer_name(x)))
+            return 1;
+    }
+    return 0;
+}
+
+static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
+                                     STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
+                                     EVP_PKEY **pkey, STACK_OF(X509) **pother,
+                                     UI_METHOD *ui_method,
+                                     void *callback_data)
+{
+    STACK_OF(X509) *certs = NULL;
+    X509 *x;
+    char *storename;
+    const unsigned char *p;
+    int i, client_cert_idx;
+    HCERTSTORE hstore;
+    PCCERT_CONTEXT cert = NULL, excert = NULL;
+    CAPI_CTX *ctx;
+    CAPI_KEY *key;
+    ctx = ENGINE_get_ex_data(e, capi_idx);
+
+    *pcert = NULL;
+    *pkey = NULL;
+
+    storename = ctx->ssl_client_store;
+    if (!storename)
+        storename = "MY";
+
+    hstore = capi_open_store(ctx, storename);
+    if (!hstore)
+        return 0;
+    /* Enumerate all certificates collect any matches */
+    for (i = 0;; i++) {
+        cert = CertEnumCertificatesInStore(hstore, cert);
+        if (!cert)
+            break;
+        p = cert->pbCertEncoded;
+        x = d2i_X509(NULL, &p, cert->cbCertEncoded);
+        if (!x) {
+            CAPI_trace(ctx, "Can't Parse Certificate %d\n", i);
+            continue;
+        }
+        if (cert_issuer_match(ca_dn, x)
+            && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) {
+            key = capi_get_cert_key(ctx, cert);
+            if (!key) {
+                X509_free(x);
+                continue;
+            }
+            /*
+             * Match found: attach extra data to it so we can retrieve the
+             * key later.
+             */
+            excert = CertDuplicateCertificateContext(cert);
+            key->pcert = excert;
+            X509_set_ex_data(x, cert_capi_idx, key);
+
+            if (!certs)
+                certs = sk_X509_new_null();
+
+            sk_X509_push(certs, x);
+        } else {
+            X509_free(x);
+        }
+    }
+
+    if (cert)
+        CertFreeCertificateContext(cert);
+    if (hstore)
+        CertCloseStore(hstore, 0);
+
+    if (!certs)
+        return 0;
+
+    /* Select the appropriate certificate */
+
+    client_cert_idx = ctx->client_cert_select(e, ssl, certs);
+
+    /* Set the selected certificate and free the rest */
+
+    for (i = 0; i < sk_X509_num(certs); i++) {
+        x = sk_X509_value(certs, i);
+        if (i == client_cert_idx)
+            *pcert = x;
+        else {
+            key = X509_get_ex_data(x, cert_capi_idx);
+            capi_free_key(key);
+            X509_free(x);
+        }
+    }
+
+    sk_X509_free(certs);
+
+    if (!*pcert)
+        return 0;
+
+    /* Setup key for selected certificate */
+
+    key = X509_get_ex_data(*pcert, cert_capi_idx);
+    *pkey = capi_get_pkey(e, key);
+    X509_set_ex_data(*pcert, cert_capi_idx, NULL);
+
+    return 1;
+
+}
+
+/* Simple client cert selection function: always select first */
+
+static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
+{
+    return 0;
+}
+
+# ifdef OPENSSL_CAPIENG_DIALOG
+
+/*
+ * More complex cert selection function, using standard function
+ * CryptUIDlgSelectCertificateFromStore() to produce a dialog box.
+ */
+
+/*
+ * Definitions which are in cryptuiapi.h but this is not present in older
+ * versions of headers.
+ */
+
+#  ifndef CRYPTUI_SELECT_LOCATION_COLUMN
+#   define CRYPTUI_SELECT_LOCATION_COLUMN                   0x000000010
+#   define CRYPTUI_SELECT_INTENDEDUSE_COLUMN                0x000000004
+#  endif
+
+#  define dlg_title L"OpenSSL Application SSL Client Certificate Selection"
+#  define dlg_prompt L"Select a certificate to use for authentication"
+#  define dlg_columns      CRYPTUI_SELECT_LOCATION_COLUMN \
+                        |CRYPTUI_SELECT_INTENDEDUSE_COLUMN
+
+static int cert_select_dialog(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
+{
+    X509 *x;
+    HCERTSTORE dstore;
+    PCCERT_CONTEXT cert;
+    CAPI_CTX *ctx;
+    CAPI_KEY *key;
+    HWND hwnd;
+    int i, idx = -1;
+    if (sk_X509_num(certs) == 1)
+        return 0;
+    ctx = ENGINE_get_ex_data(e, capi_idx);
+    /* Create an in memory store of certificates */
+    dstore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
+                           CERT_STORE_CREATE_NEW_FLAG, NULL);
+    if (!dstore) {
+        CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_CREATING_STORE);
+        capi_addlasterror();
+        goto err;
+    }
+    /* Add all certificates to store */
+    for (i = 0; i < sk_X509_num(certs); i++) {
+        x = sk_X509_value(certs, i);
+        key = X509_get_ex_data(x, cert_capi_idx);
+
+        if (!CertAddCertificateContextToStore(dstore, key->pcert,
+                                              CERT_STORE_ADD_NEW, NULL)) {
+            CAPIerr(CAPI_F_CERT_SELECT_DIALOG, CAPI_R_ERROR_ADDING_CERT);
+            capi_addlasterror();
+            goto err;
+        }
+
+    }
+    hwnd = GetForegroundWindow();
+    if (!hwnd)
+        hwnd = GetActiveWindow();
+    if (!hwnd && ctx->getconswindow)
+        hwnd = ctx->getconswindow();
+    /* Call dialog to select one */
+    cert = ctx->certselectdlg(dstore, hwnd, dlg_title, dlg_prompt,
+                              dlg_columns, 0, NULL);
+
+    /* Find matching cert from list */
+    if (cert) {
+        for (i = 0; i < sk_X509_num(certs); i++) {
+            x = sk_X509_value(certs, i);
+            key = X509_get_ex_data(x, cert_capi_idx);
+            if (CertCompareCertificate
+                (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert->pCertInfo,
+                 key->pcert->pCertInfo)) {
+                idx = i;
+                break;
+            }
+        }
+    }
+
+ err:
+    if (dstore)
+        CertCloseStore(dstore, 0);
+    return idx;
+
+}
+# endif
+
+#else                           /* !__COMPILE_CAPIENG */
+# include <openssl/engine.h>
+# ifndef OPENSSL_NO_DYNAMIC_ENGINE
+OPENSSL_EXPORT
+    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns);
+OPENSSL_EXPORT
+    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns)
+{
+    return 0;
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+# else
+void engine_load_capi_int(void);
+void engine_load_capi_int(void)
+{
+}
+# endif
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_capi.ec b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi.ec
new file mode 100644
index 0000000..d9c7aa5
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi.ec
@@ -0,0 +1,3 @@
+# The INPUT HEADER is scanned for declarations
+# LIBNAME       INPUT HEADER                    ERROR-TABLE FILE
+L CAPI          e_capi_err.h                    e_capi_err.c
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_capi.txt b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi.txt
new file mode 100644
index 0000000..3f34cdf
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi.txt
@@ -0,0 +1,62 @@
+# Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+# Function codes
+CAPI_F_CAPI_CERT_GET_FNAME:99:capi_cert_get_fname
+CAPI_F_CAPI_CTRL:100:capi_ctrl
+CAPI_F_CAPI_CTX_NEW:101:capi_ctx_new
+CAPI_F_CAPI_CTX_SET_PROVNAME:102:capi_ctx_set_provname
+CAPI_F_CAPI_DSA_DO_SIGN:114:capi_dsa_do_sign
+CAPI_F_CAPI_GET_KEY:103:capi_get_key
+CAPI_F_CAPI_GET_PKEY:115:capi_get_pkey
+CAPI_F_CAPI_GET_PROVNAME:104:capi_get_provname
+CAPI_F_CAPI_GET_PROV_INFO:105:capi_get_prov_info
+CAPI_F_CAPI_INIT:106:capi_init
+CAPI_F_CAPI_LIST_CONTAINERS:107:capi_list_containers
+CAPI_F_CAPI_LOAD_PRIVKEY:108:capi_load_privkey
+CAPI_F_CAPI_OPEN_STORE:109:capi_open_store
+CAPI_F_CAPI_RSA_PRIV_DEC:110:capi_rsa_priv_dec
+CAPI_F_CAPI_RSA_PRIV_ENC:111:capi_rsa_priv_enc
+CAPI_F_CAPI_RSA_SIGN:112:capi_rsa_sign
+CAPI_F_CAPI_VTRACE:118:capi_vtrace
+CAPI_F_CERT_SELECT_DIALOG:117:cert_select_dialog
+CAPI_F_CLIENT_CERT_SELECT:116:*
+CAPI_F_WIDE_TO_ASC:113:wide_to_asc
+
+#Reason codes
+CAPI_R_CANT_CREATE_HASH_OBJECT:100:cant create hash object
+CAPI_R_CANT_FIND_CAPI_CONTEXT:101:cant find capi context
+CAPI_R_CANT_GET_KEY:102:cant get key
+CAPI_R_CANT_SET_HASH_VALUE:103:cant set hash value
+CAPI_R_CRYPTACQUIRECONTEXT_ERROR:104:cryptacquirecontext error
+CAPI_R_CRYPTENUMPROVIDERS_ERROR:105:cryptenumproviders error
+CAPI_R_DECRYPT_ERROR:106:decrypt error
+CAPI_R_ENGINE_NOT_INITIALIZED:107:engine not initialized
+CAPI_R_ENUMCONTAINERS_ERROR:108:enumcontainers error
+CAPI_R_ERROR_ADDING_CERT:109:error adding cert
+CAPI_R_ERROR_CREATING_STORE:110:error creating store
+CAPI_R_ERROR_GETTING_FRIENDLY_NAME:111:error getting friendly name
+CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO:112:error getting key provider info
+CAPI_R_ERROR_OPENING_STORE:113:error opening store
+CAPI_R_ERROR_SIGNING_HASH:114:error signing hash
+CAPI_R_FILE_OPEN_ERROR:115:file open error
+CAPI_R_FUNCTION_NOT_SUPPORTED:116:function not supported
+CAPI_R_GETUSERKEY_ERROR:117:getuserkey error
+CAPI_R_INVALID_DIGEST_LENGTH:118:invalid digest length
+CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER:119:\
+	invalid dsa public key blob magic number
+CAPI_R_INVALID_LOOKUP_METHOD:120:invalid lookup method
+CAPI_R_INVALID_PUBLIC_KEY_BLOB:121:invalid public key blob
+CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER:122:\
+	invalid rsa public key blob magic number
+CAPI_R_PUBKEY_EXPORT_ERROR:123:pubkey export error
+CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR:124:pubkey export length error
+CAPI_R_UNKNOWN_COMMAND:125:unknown command
+CAPI_R_UNSUPPORTED_ALGORITHM_NID:126:unsupported algorithm nid
+CAPI_R_UNSUPPORTED_PADDING:127:unsupported padding
+CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM:128:unsupported public key algorithm
+CAPI_R_WIN32_ERROR:129:win32 error
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_capi_err.c b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi_err.c
new file mode 100644
index 0000000..b72bc51
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi_err.c
@@ -0,0 +1,119 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/err.h>
+#include "e_capi_err.h"
+
+#ifndef OPENSSL_NO_ERR
+
+static ERR_STRING_DATA CAPI_str_functs[] = {
+    {ERR_PACK(0, CAPI_F_CAPI_CERT_GET_FNAME, 0), "capi_cert_get_fname"},
+    {ERR_PACK(0, CAPI_F_CAPI_CTRL, 0), "capi_ctrl"},
+    {ERR_PACK(0, CAPI_F_CAPI_CTX_NEW, 0), "capi_ctx_new"},
+    {ERR_PACK(0, CAPI_F_CAPI_CTX_SET_PROVNAME, 0), "capi_ctx_set_provname"},
+    {ERR_PACK(0, CAPI_F_CAPI_DSA_DO_SIGN, 0), "capi_dsa_do_sign"},
+    {ERR_PACK(0, CAPI_F_CAPI_GET_KEY, 0), "capi_get_key"},
+    {ERR_PACK(0, CAPI_F_CAPI_GET_PKEY, 0), "capi_get_pkey"},
+    {ERR_PACK(0, CAPI_F_CAPI_GET_PROVNAME, 0), "capi_get_provname"},
+    {ERR_PACK(0, CAPI_F_CAPI_GET_PROV_INFO, 0), "capi_get_prov_info"},
+    {ERR_PACK(0, CAPI_F_CAPI_INIT, 0), "capi_init"},
+    {ERR_PACK(0, CAPI_F_CAPI_LIST_CONTAINERS, 0), "capi_list_containers"},
+    {ERR_PACK(0, CAPI_F_CAPI_LOAD_PRIVKEY, 0), "capi_load_privkey"},
+    {ERR_PACK(0, CAPI_F_CAPI_OPEN_STORE, 0), "capi_open_store"},
+    {ERR_PACK(0, CAPI_F_CAPI_RSA_PRIV_DEC, 0), "capi_rsa_priv_dec"},
+    {ERR_PACK(0, CAPI_F_CAPI_RSA_PRIV_ENC, 0), "capi_rsa_priv_enc"},
+    {ERR_PACK(0, CAPI_F_CAPI_RSA_SIGN, 0), "capi_rsa_sign"},
+    {ERR_PACK(0, CAPI_F_CAPI_VTRACE, 0), "capi_vtrace"},
+    {ERR_PACK(0, CAPI_F_CERT_SELECT_DIALOG, 0), "cert_select_dialog"},
+    {ERR_PACK(0, CAPI_F_CLIENT_CERT_SELECT, 0), ""},
+    {ERR_PACK(0, CAPI_F_WIDE_TO_ASC, 0), "wide_to_asc"},
+    {0, NULL}
+};
+
+static ERR_STRING_DATA CAPI_str_reasons[] = {
+    {ERR_PACK(0, 0, CAPI_R_CANT_CREATE_HASH_OBJECT), "cant create hash object"},
+    {ERR_PACK(0, 0, CAPI_R_CANT_FIND_CAPI_CONTEXT), "cant find capi context"},
+    {ERR_PACK(0, 0, CAPI_R_CANT_GET_KEY), "cant get key"},
+    {ERR_PACK(0, 0, CAPI_R_CANT_SET_HASH_VALUE), "cant set hash value"},
+    {ERR_PACK(0, 0, CAPI_R_CRYPTACQUIRECONTEXT_ERROR),
+    "cryptacquirecontext error"},
+    {ERR_PACK(0, 0, CAPI_R_CRYPTENUMPROVIDERS_ERROR),
+    "cryptenumproviders error"},
+    {ERR_PACK(0, 0, CAPI_R_DECRYPT_ERROR), "decrypt error"},
+    {ERR_PACK(0, 0, CAPI_R_ENGINE_NOT_INITIALIZED), "engine not initialized"},
+    {ERR_PACK(0, 0, CAPI_R_ENUMCONTAINERS_ERROR), "enumcontainers error"},
+    {ERR_PACK(0, 0, CAPI_R_ERROR_ADDING_CERT), "error adding cert"},
+    {ERR_PACK(0, 0, CAPI_R_ERROR_CREATING_STORE), "error creating store"},
+    {ERR_PACK(0, 0, CAPI_R_ERROR_GETTING_FRIENDLY_NAME),
+    "error getting friendly name"},
+    {ERR_PACK(0, 0, CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO),
+    "error getting key provider info"},
+    {ERR_PACK(0, 0, CAPI_R_ERROR_OPENING_STORE), "error opening store"},
+    {ERR_PACK(0, 0, CAPI_R_ERROR_SIGNING_HASH), "error signing hash"},
+    {ERR_PACK(0, 0, CAPI_R_FILE_OPEN_ERROR), "file open error"},
+    {ERR_PACK(0, 0, CAPI_R_FUNCTION_NOT_SUPPORTED), "function not supported"},
+    {ERR_PACK(0, 0, CAPI_R_GETUSERKEY_ERROR), "getuserkey error"},
+    {ERR_PACK(0, 0, CAPI_R_INVALID_DIGEST_LENGTH), "invalid digest length"},
+    {ERR_PACK(0, 0, CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER),
+    "invalid dsa public key blob magic number"},
+    {ERR_PACK(0, 0, CAPI_R_INVALID_LOOKUP_METHOD), "invalid lookup method"},
+    {ERR_PACK(0, 0, CAPI_R_INVALID_PUBLIC_KEY_BLOB), "invalid public key blob"},
+    {ERR_PACK(0, 0, CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER),
+    "invalid rsa public key blob magic number"},
+    {ERR_PACK(0, 0, CAPI_R_PUBKEY_EXPORT_ERROR), "pubkey export error"},
+    {ERR_PACK(0, 0, CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR),
+    "pubkey export length error"},
+    {ERR_PACK(0, 0, CAPI_R_UNKNOWN_COMMAND), "unknown command"},
+    {ERR_PACK(0, 0, CAPI_R_UNSUPPORTED_ALGORITHM_NID),
+    "unsupported algorithm nid"},
+    {ERR_PACK(0, 0, CAPI_R_UNSUPPORTED_PADDING), "unsupported padding"},
+    {ERR_PACK(0, 0, CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM),
+    "unsupported public key algorithm"},
+    {ERR_PACK(0, 0, CAPI_R_WIN32_ERROR), "win32 error"},
+    {0, NULL}
+};
+
+#endif
+
+static int lib_code = 0;
+static int error_loaded = 0;
+
+static int ERR_load_CAPI_strings(void)
+{
+    if (lib_code == 0)
+        lib_code = ERR_get_next_error_library();
+
+    if (!error_loaded) {
+#ifndef OPENSSL_NO_ERR
+        ERR_load_strings(lib_code, CAPI_str_functs);
+        ERR_load_strings(lib_code, CAPI_str_reasons);
+#endif
+        error_loaded = 1;
+    }
+    return 1;
+}
+
+static void ERR_unload_CAPI_strings(void)
+{
+    if (error_loaded) {
+#ifndef OPENSSL_NO_ERR
+        ERR_unload_strings(lib_code, CAPI_str_functs);
+        ERR_unload_strings(lib_code, CAPI_str_reasons);
+#endif
+        error_loaded = 0;
+    }
+}
+
+static void ERR_CAPI_error(int function, int reason, char *file, int line)
+{
+    if (lib_code == 0)
+        lib_code = ERR_get_next_error_library();
+    ERR_PUT_error(lib_code, function, reason, file, line);
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_capi_err.h b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi_err.h
new file mode 100644
index 0000000..e3a927a
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_capi_err.h
@@ -0,0 +1,75 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_ENGINES_E_CAPI_ERR_H
+# define OSSL_ENGINES_E_CAPI_ERR_H
+
+# define CAPIerr(f, r) ERR_CAPI_error((f), (r), OPENSSL_FILE, OPENSSL_LINE)
+
+
+/*
+ * CAPI function codes.
+ */
+# define CAPI_F_CAPI_CERT_GET_FNAME                       99
+# define CAPI_F_CAPI_CTRL                                 100
+# define CAPI_F_CAPI_CTX_NEW                              101
+# define CAPI_F_CAPI_CTX_SET_PROVNAME                     102
+# define CAPI_F_CAPI_DSA_DO_SIGN                          114
+# define CAPI_F_CAPI_GET_KEY                              103
+# define CAPI_F_CAPI_GET_PKEY                             115
+# define CAPI_F_CAPI_GET_PROVNAME                         104
+# define CAPI_F_CAPI_GET_PROV_INFO                        105
+# define CAPI_F_CAPI_INIT                                 106
+# define CAPI_F_CAPI_LIST_CONTAINERS                      107
+# define CAPI_F_CAPI_LOAD_PRIVKEY                         108
+# define CAPI_F_CAPI_OPEN_STORE                           109
+# define CAPI_F_CAPI_RSA_PRIV_DEC                         110
+# define CAPI_F_CAPI_RSA_PRIV_ENC                         111
+# define CAPI_F_CAPI_RSA_SIGN                             112
+# define CAPI_F_CAPI_VTRACE                               118
+# define CAPI_F_CERT_SELECT_DIALOG                        117
+# define CAPI_F_CLIENT_CERT_SELECT                        116
+# define CAPI_F_WIDE_TO_ASC                               113
+
+/*
+ * CAPI reason codes.
+ */
+# define CAPI_R_CANT_CREATE_HASH_OBJECT                   100
+# define CAPI_R_CANT_FIND_CAPI_CONTEXT                    101
+# define CAPI_R_CANT_GET_KEY                              102
+# define CAPI_R_CANT_SET_HASH_VALUE                       103
+# define CAPI_R_CRYPTACQUIRECONTEXT_ERROR                 104
+# define CAPI_R_CRYPTENUMPROVIDERS_ERROR                  105
+# define CAPI_R_DECRYPT_ERROR                             106
+# define CAPI_R_ENGINE_NOT_INITIALIZED                    107
+# define CAPI_R_ENUMCONTAINERS_ERROR                      108
+# define CAPI_R_ERROR_ADDING_CERT                         109
+# define CAPI_R_ERROR_CREATING_STORE                      110
+# define CAPI_R_ERROR_GETTING_FRIENDLY_NAME               111
+# define CAPI_R_ERROR_GETTING_KEY_PROVIDER_INFO           112
+# define CAPI_R_ERROR_OPENING_STORE                       113
+# define CAPI_R_ERROR_SIGNING_HASH                        114
+# define CAPI_R_FILE_OPEN_ERROR                           115
+# define CAPI_R_FUNCTION_NOT_SUPPORTED                    116
+# define CAPI_R_GETUSERKEY_ERROR                          117
+# define CAPI_R_INVALID_DIGEST_LENGTH                     118
+# define CAPI_R_INVALID_DSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER  119
+# define CAPI_R_INVALID_LOOKUP_METHOD                     120
+# define CAPI_R_INVALID_PUBLIC_KEY_BLOB                   121
+# define CAPI_R_INVALID_RSA_PUBLIC_KEY_BLOB_MAGIC_NUMBER  122
+# define CAPI_R_PUBKEY_EXPORT_ERROR                       123
+# define CAPI_R_PUBKEY_EXPORT_LENGTH_ERROR                124
+# define CAPI_R_UNKNOWN_COMMAND                           125
+# define CAPI_R_UNSUPPORTED_ALGORITHM_NID                 126
+# define CAPI_R_UNSUPPORTED_PADDING                       127
+# define CAPI_R_UNSUPPORTED_PUBLIC_KEY_ALGORITHM          128
+# define CAPI_R_WIN32_ERROR                               129
+
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync.c b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync.c
new file mode 100644
index 0000000..9ad043b
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync.c
@@ -0,0 +1,807 @@
+/*
+ * Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#if defined(_WIN32)
+# include <windows.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/engine.h>
+#include <openssl/sha.h>
+#include <openssl/aes.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/async.h>
+#include <openssl/bn.h>
+#include <openssl/crypto.h>
+#include <openssl/ssl.h>
+#include <openssl/modes.h>
+
+#if defined(OPENSSL_SYS_UNIX) && defined(OPENSSL_THREADS)
+# undef ASYNC_POSIX
+# define ASYNC_POSIX
+# include <unistd.h>
+#elif defined(_WIN32)
+# undef ASYNC_WIN
+# define ASYNC_WIN
+#endif
+
+#include "e_dasync_err.c"
+
+/* Engine Id and Name */
+static const char *engine_dasync_id = "dasync";
+static const char *engine_dasync_name = "Dummy Async engine support";
+
+
+/* Engine Lifetime functions */
+static int dasync_destroy(ENGINE *e);
+static int dasync_init(ENGINE *e);
+static int dasync_finish(ENGINE *e);
+void engine_load_dasync_int(void);
+
+
+/* Set up digests. Just SHA1 for now */
+static int dasync_digests(ENGINE *e, const EVP_MD **digest,
+                          const int **nids, int nid);
+
+static void dummy_pause_job(void);
+
+/* SHA1 */
+static int dasync_sha1_init(EVP_MD_CTX *ctx);
+static int dasync_sha1_update(EVP_MD_CTX *ctx, const void *data,
+                             size_t count);
+static int dasync_sha1_final(EVP_MD_CTX *ctx, unsigned char *md);
+
+/*
+ * Holds the EVP_MD object for sha1 in this engine. Set up once only during
+ * engine bind and can then be reused many times.
+ */
+static EVP_MD *_hidden_sha1_md = NULL;
+static const EVP_MD *dasync_sha1(void)
+{
+    return _hidden_sha1_md;
+}
+static void destroy_digests(void)
+{
+    EVP_MD_meth_free(_hidden_sha1_md);
+    _hidden_sha1_md = NULL;
+}
+
+static int dasync_digest_nids(const int **nids)
+{
+    static int digest_nids[2] = { 0, 0 };
+    static int pos = 0;
+    static int init = 0;
+
+    if (!init) {
+        const EVP_MD *md;
+        if ((md = dasync_sha1()) != NULL)
+            digest_nids[pos++] = EVP_MD_type(md);
+        digest_nids[pos] = 0;
+        init = 1;
+    }
+    *nids = digest_nids;
+    return pos;
+}
+
+/* RSA */
+
+static int dasync_pub_enc(int flen, const unsigned char *from,
+                    unsigned char *to, RSA *rsa, int padding);
+static int dasync_pub_dec(int flen, const unsigned char *from,
+                    unsigned char *to, RSA *rsa, int padding);
+static int dasync_rsa_priv_enc(int flen, const unsigned char *from,
+                      unsigned char *to, RSA *rsa, int padding);
+static int dasync_rsa_priv_dec(int flen, const unsigned char *from,
+                      unsigned char *to, RSA *rsa, int padding);
+static int dasync_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
+                              BN_CTX *ctx);
+
+static int dasync_rsa_init(RSA *rsa);
+static int dasync_rsa_finish(RSA *rsa);
+
+static RSA_METHOD *dasync_rsa_method = NULL;
+
+/* AES */
+
+static int dasync_aes128_cbc_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
+                                  void *ptr);
+static int dasync_aes128_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                                  const unsigned char *iv, int enc);
+static int dasync_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                                    const unsigned char *in, size_t inl);
+static int dasync_aes128_cbc_cleanup(EVP_CIPHER_CTX *ctx);
+
+static int dasync_aes128_cbc_hmac_sha1_ctrl(EVP_CIPHER_CTX *ctx, int type,
+                                             int arg, void *ptr);
+static int dasync_aes128_cbc_hmac_sha1_init_key(EVP_CIPHER_CTX *ctx,
+                                                 const unsigned char *key,
+                                                 const unsigned char *iv,
+                                                 int enc);
+static int dasync_aes128_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx,
+                                               unsigned char *out,
+                                               const unsigned char *in,
+                                               size_t inl);
+static int dasync_aes128_cbc_hmac_sha1_cleanup(EVP_CIPHER_CTX *ctx);
+
+struct dasync_pipeline_ctx {
+    void *inner_cipher_data;
+    unsigned int numpipes;
+    unsigned char **inbufs;
+    unsigned char **outbufs;
+    size_t *lens;
+    unsigned char tlsaad[SSL_MAX_PIPELINES][EVP_AEAD_TLS1_AAD_LEN];
+    unsigned int aadctr;
+};
+
+/*
+ * Holds the EVP_CIPHER object for aes_128_cbc in this engine. Set up once only
+ * during engine bind and can then be reused many times.
+ */
+static EVP_CIPHER *_hidden_aes_128_cbc = NULL;
+static const EVP_CIPHER *dasync_aes_128_cbc(void)
+{
+    return _hidden_aes_128_cbc;
+}
+
+/*
+ * Holds the EVP_CIPHER object for aes_128_cbc_hmac_sha1 in this engine. Set up
+ * once only during engine bind and can then be reused many times.
+ *
+ * This 'stitched' cipher depends on the EVP_aes_128_cbc_hmac_sha1() cipher,
+ * which is implemented only if the AES-NI instruction set extension is available
+ * (see OPENSSL_IA32CAP(3)). If that's not the case, then this cipher will not
+ * be available either.
+ *
+ * Note: Since it is a legacy mac-then-encrypt cipher, modern TLS peers (which
+ * negotiate the encrypt-then-mac extension) won't negotiate it anyway.
+ */
+static EVP_CIPHER *_hidden_aes_128_cbc_hmac_sha1 = NULL;
+static const EVP_CIPHER *dasync_aes_128_cbc_hmac_sha1(void)
+{
+    return _hidden_aes_128_cbc_hmac_sha1;
+}
+
+static void destroy_ciphers(void)
+{
+    EVP_CIPHER_meth_free(_hidden_aes_128_cbc);
+    EVP_CIPHER_meth_free(_hidden_aes_128_cbc_hmac_sha1);
+    _hidden_aes_128_cbc = NULL;
+    _hidden_aes_128_cbc_hmac_sha1 = NULL;
+}
+
+static int dasync_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+                                   const int **nids, int nid);
+
+static int dasync_cipher_nids[] = {
+    NID_aes_128_cbc_hmac_sha1,
+    NID_aes_128_cbc,
+    0
+};
+
+static int bind_dasync(ENGINE *e)
+{
+    /* Setup RSA_METHOD */
+    if ((dasync_rsa_method = RSA_meth_new("Dummy Async RSA method", 0)) == NULL
+        || RSA_meth_set_pub_enc(dasync_rsa_method, dasync_pub_enc) == 0
+        || RSA_meth_set_pub_dec(dasync_rsa_method, dasync_pub_dec) == 0
+        || RSA_meth_set_priv_enc(dasync_rsa_method, dasync_rsa_priv_enc) == 0
+        || RSA_meth_set_priv_dec(dasync_rsa_method, dasync_rsa_priv_dec) == 0
+        || RSA_meth_set_mod_exp(dasync_rsa_method, dasync_rsa_mod_exp) == 0
+        || RSA_meth_set_bn_mod_exp(dasync_rsa_method, BN_mod_exp_mont) == 0
+        || RSA_meth_set_init(dasync_rsa_method, dasync_rsa_init) == 0
+        || RSA_meth_set_finish(dasync_rsa_method, dasync_rsa_finish) == 0) {
+        DASYNCerr(DASYNC_F_BIND_DASYNC, DASYNC_R_INIT_FAILED);
+        return 0;
+    }
+
+    /* Ensure the dasync error handling is set up */
+    ERR_load_DASYNC_strings();
+
+    if (!ENGINE_set_id(e, engine_dasync_id)
+        || !ENGINE_set_name(e, engine_dasync_name)
+        || !ENGINE_set_RSA(e, dasync_rsa_method)
+        || !ENGINE_set_digests(e, dasync_digests)
+        || !ENGINE_set_ciphers(e, dasync_ciphers)
+        || !ENGINE_set_destroy_function(e, dasync_destroy)
+        || !ENGINE_set_init_function(e, dasync_init)
+        || !ENGINE_set_finish_function(e, dasync_finish)) {
+        DASYNCerr(DASYNC_F_BIND_DASYNC, DASYNC_R_INIT_FAILED);
+        return 0;
+    }
+
+    /*
+     * Set up the EVP_CIPHER and EVP_MD objects for the ciphers/digests
+     * supplied by this engine
+     */
+    _hidden_sha1_md = EVP_MD_meth_new(NID_sha1, NID_sha1WithRSAEncryption);
+    if (_hidden_sha1_md == NULL
+        || !EVP_MD_meth_set_result_size(_hidden_sha1_md, SHA_DIGEST_LENGTH)
+        || !EVP_MD_meth_set_input_blocksize(_hidden_sha1_md, SHA_CBLOCK)
+        || !EVP_MD_meth_set_app_datasize(_hidden_sha1_md,
+                                         sizeof(EVP_MD *) + sizeof(SHA_CTX))
+        || !EVP_MD_meth_set_flags(_hidden_sha1_md, EVP_MD_FLAG_DIGALGID_ABSENT)
+        || !EVP_MD_meth_set_init(_hidden_sha1_md, dasync_sha1_init)
+        || !EVP_MD_meth_set_update(_hidden_sha1_md, dasync_sha1_update)
+        || !EVP_MD_meth_set_final(_hidden_sha1_md, dasync_sha1_final)) {
+        EVP_MD_meth_free(_hidden_sha1_md);
+        _hidden_sha1_md = NULL;
+    }
+
+    _hidden_aes_128_cbc = EVP_CIPHER_meth_new(NID_aes_128_cbc,
+                                              16 /* block size */,
+                                              16 /* key len */);
+    if (_hidden_aes_128_cbc == NULL
+            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_128_cbc,16)
+            || !EVP_CIPHER_meth_set_flags(_hidden_aes_128_cbc,
+                                          EVP_CIPH_FLAG_DEFAULT_ASN1
+                                          | EVP_CIPH_CBC_MODE
+                                          | EVP_CIPH_FLAG_PIPELINE
+                                          | EVP_CIPH_CUSTOM_COPY)
+            || !EVP_CIPHER_meth_set_init(_hidden_aes_128_cbc,
+                                         dasync_aes128_init_key)
+            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_128_cbc,
+                                              dasync_aes128_cbc_cipher)
+            || !EVP_CIPHER_meth_set_cleanup(_hidden_aes_128_cbc,
+                                            dasync_aes128_cbc_cleanup)
+            || !EVP_CIPHER_meth_set_ctrl(_hidden_aes_128_cbc,
+                                         dasync_aes128_cbc_ctrl)
+            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_128_cbc,
+                                sizeof(struct dasync_pipeline_ctx))) {
+        EVP_CIPHER_meth_free(_hidden_aes_128_cbc);
+        _hidden_aes_128_cbc = NULL;
+    }
+
+    _hidden_aes_128_cbc_hmac_sha1 = EVP_CIPHER_meth_new(
+                                                NID_aes_128_cbc_hmac_sha1,
+                                                16 /* block size */,
+                                                16 /* key len */);
+    if (_hidden_aes_128_cbc_hmac_sha1 == NULL
+            || EVP_aes_128_cbc_hmac_sha1() == NULL
+            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_128_cbc_hmac_sha1,16)
+            || !EVP_CIPHER_meth_set_flags(_hidden_aes_128_cbc_hmac_sha1,
+                                            EVP_CIPH_CBC_MODE
+                                          | EVP_CIPH_FLAG_DEFAULT_ASN1
+                                          | EVP_CIPH_FLAG_AEAD_CIPHER
+                                          | EVP_CIPH_FLAG_PIPELINE
+                                          | EVP_CIPH_CUSTOM_COPY)
+            || !EVP_CIPHER_meth_set_init(_hidden_aes_128_cbc_hmac_sha1,
+                                         dasync_aes128_cbc_hmac_sha1_init_key)
+            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_128_cbc_hmac_sha1,
+                                            dasync_aes128_cbc_hmac_sha1_cipher)
+            || !EVP_CIPHER_meth_set_cleanup(_hidden_aes_128_cbc_hmac_sha1,
+                                            dasync_aes128_cbc_hmac_sha1_cleanup)
+            || !EVP_CIPHER_meth_set_ctrl(_hidden_aes_128_cbc_hmac_sha1,
+                                         dasync_aes128_cbc_hmac_sha1_ctrl)
+            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_128_cbc_hmac_sha1,
+                                sizeof(struct dasync_pipeline_ctx))) {
+        EVP_CIPHER_meth_free(_hidden_aes_128_cbc_hmac_sha1);
+        _hidden_aes_128_cbc_hmac_sha1 = NULL;
+    }
+
+    return 1;
+}
+
+# ifndef OPENSSL_NO_DYNAMIC_ENGINE
+static int bind_helper(ENGINE *e, const char *id)
+{
+    if (id && (strcmp(id, engine_dasync_id) != 0))
+        return 0;
+    if (!bind_dasync(e))
+        return 0;
+    return 1;
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
+# endif
+
+static ENGINE *engine_dasync(void)
+{
+    ENGINE *ret = ENGINE_new();
+    if (!ret)
+        return NULL;
+    if (!bind_dasync(ret)) {
+        ENGINE_free(ret);
+        return NULL;
+    }
+    return ret;
+}
+
+void engine_load_dasync_int(void)
+{
+    ENGINE *toadd = engine_dasync();
+    if (!toadd)
+        return;
+    ENGINE_add(toadd);
+    ENGINE_free(toadd);
+    ERR_clear_error();
+}
+
+static int dasync_init(ENGINE *e)
+{
+    return 1;
+}
+
+
+static int dasync_finish(ENGINE *e)
+{
+    return 1;
+}
+
+
+static int dasync_destroy(ENGINE *e)
+{
+    destroy_digests();
+    destroy_ciphers();
+    RSA_meth_free(dasync_rsa_method);
+    ERR_unload_DASYNC_strings();
+    return 1;
+}
+
+static int dasync_digests(ENGINE *e, const EVP_MD **digest,
+                          const int **nids, int nid)
+{
+    int ok = 1;
+    if (!digest) {
+        /* We are returning a list of supported nids */
+        return dasync_digest_nids(nids);
+    }
+    /* We are being asked for a specific digest */
+    switch (nid) {
+    case NID_sha1:
+        *digest = dasync_sha1();
+        break;
+    default:
+        ok = 0;
+        *digest = NULL;
+        break;
+    }
+    return ok;
+}
+
+static int dasync_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+                                   const int **nids, int nid)
+{
+    int ok = 1;
+    if (cipher == NULL) {
+        /* We are returning a list of supported nids */
+        if (dasync_aes_128_cbc_hmac_sha1() == NULL) {
+            *nids = dasync_cipher_nids + 1;
+            return 1;
+        }
+        *nids = dasync_cipher_nids;
+        return (sizeof(dasync_cipher_nids) -
+                1) / sizeof(dasync_cipher_nids[0]);
+    }
+    /* We are being asked for a specific cipher */
+    switch (nid) {
+    case NID_aes_128_cbc:
+        *cipher = dasync_aes_128_cbc();
+        break;
+    case NID_aes_128_cbc_hmac_sha1:
+        *cipher = dasync_aes_128_cbc_hmac_sha1();
+        break;
+    default:
+        ok = 0;
+        *cipher = NULL;
+        break;
+    }
+    return ok;
+}
+
+static void wait_cleanup(ASYNC_WAIT_CTX *ctx, const void *key,
+                         OSSL_ASYNC_FD readfd, void *pvwritefd)
+{
+    OSSL_ASYNC_FD *pwritefd = (OSSL_ASYNC_FD *)pvwritefd;
+#if defined(ASYNC_WIN)
+    CloseHandle(readfd);
+    CloseHandle(*pwritefd);
+#elif defined(ASYNC_POSIX)
+    close(readfd);
+    close(*pwritefd);
+#endif
+    OPENSSL_free(pwritefd);
+}
+
+#define DUMMY_CHAR 'X'
+
+static void dummy_pause_job(void) {
+    ASYNC_JOB *job;
+    ASYNC_WAIT_CTX *waitctx;
+    OSSL_ASYNC_FD pipefds[2] = {0, 0};
+    OSSL_ASYNC_FD *writefd;
+#if defined(ASYNC_WIN)
+    DWORD numwritten, numread;
+    char buf = DUMMY_CHAR;
+#elif defined(ASYNC_POSIX)
+    char buf = DUMMY_CHAR;
+#endif
+
+    if ((job = ASYNC_get_current_job()) == NULL)
+        return;
+
+    waitctx = ASYNC_get_wait_ctx(job);
+
+    if (ASYNC_WAIT_CTX_get_fd(waitctx, engine_dasync_id, &pipefds[0],
+                              (void **)&writefd)) {
+        pipefds[1] = *writefd;
+    } else {
+        writefd = OPENSSL_malloc(sizeof(*writefd));
+        if (writefd == NULL)
+            return;
+#if defined(ASYNC_WIN)
+        if (CreatePipe(&pipefds[0], &pipefds[1], NULL, 256) == 0) {
+            OPENSSL_free(writefd);
+            return;
+        }
+#elif defined(ASYNC_POSIX)
+        if (pipe(pipefds) != 0) {
+            OPENSSL_free(writefd);
+            return;
+        }
+#endif
+        *writefd = pipefds[1];
+
+        if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, engine_dasync_id, pipefds[0],
+                                        writefd, wait_cleanup)) {
+            wait_cleanup(waitctx, engine_dasync_id, pipefds[0], writefd);
+            return;
+        }
+    }
+    /*
+     * In the Dummy async engine we are cheating. We signal that the job
+     * is complete by waking it before the call to ASYNC_pause_job(). A real
+     * async engine would only wake when the job was actually complete
+     */
+#if defined(ASYNC_WIN)
+    WriteFile(pipefds[1], &buf, 1, &numwritten, NULL);
+#elif defined(ASYNC_POSIX)
+    if (write(pipefds[1], &buf, 1) < 0)
+        return;
+#endif
+
+    /* Ignore errors - we carry on anyway */
+    ASYNC_pause_job();
+
+    /* Clear the wake signal */
+#if defined(ASYNC_WIN)
+    ReadFile(pipefds[0], &buf, 1, &numread, NULL);
+#elif defined(ASYNC_POSIX)
+    if (read(pipefds[0], &buf, 1) < 0)
+        return;
+#endif
+}
+
+/*
+ * SHA1 implementation. At the moment we just defer to the standard
+ * implementation
+ */
+#undef data
+#define data(ctx) ((SHA_CTX *)EVP_MD_CTX_md_data(ctx))
+static int dasync_sha1_init(EVP_MD_CTX *ctx)
+{
+    dummy_pause_job();
+
+    return SHA1_Init(data(ctx));
+}
+
+static int dasync_sha1_update(EVP_MD_CTX *ctx, const void *data,
+                             size_t count)
+{
+    dummy_pause_job();
+
+    return SHA1_Update(data(ctx), data, (size_t)count);
+}
+
+static int dasync_sha1_final(EVP_MD_CTX *ctx, unsigned char *md)
+{
+    dummy_pause_job();
+
+    return SHA1_Final(md, data(ctx));
+}
+
+/*
+ * RSA implementation
+ */
+
+static int dasync_pub_enc(int flen, const unsigned char *from,
+                    unsigned char *to, RSA *rsa, int padding) {
+    /* Ignore errors - we carry on anyway */
+    dummy_pause_job();
+    return RSA_meth_get_pub_enc(RSA_PKCS1_OpenSSL())
+        (flen, from, to, rsa, padding);
+}
+
+static int dasync_pub_dec(int flen, const unsigned char *from,
+                    unsigned char *to, RSA *rsa, int padding) {
+    /* Ignore errors - we carry on anyway */
+    dummy_pause_job();
+    return RSA_meth_get_pub_dec(RSA_PKCS1_OpenSSL())
+        (flen, from, to, rsa, padding);
+}
+
+static int dasync_rsa_priv_enc(int flen, const unsigned char *from,
+                      unsigned char *to, RSA *rsa, int padding)
+{
+    /* Ignore errors - we carry on anyway */
+    dummy_pause_job();
+    return RSA_meth_get_priv_enc(RSA_PKCS1_OpenSSL())
+        (flen, from, to, rsa, padding);
+}
+
+static int dasync_rsa_priv_dec(int flen, const unsigned char *from,
+                      unsigned char *to, RSA *rsa, int padding)
+{
+    /* Ignore errors - we carry on anyway */
+    dummy_pause_job();
+    return RSA_meth_get_priv_dec(RSA_PKCS1_OpenSSL())
+        (flen, from, to, rsa, padding);
+}
+
+static int dasync_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
+{
+    /* Ignore errors - we carry on anyway */
+    dummy_pause_job();
+    return RSA_meth_get_mod_exp(RSA_PKCS1_OpenSSL())(r0, I, rsa, ctx);
+}
+
+static int dasync_rsa_init(RSA *rsa)
+{
+    return RSA_meth_get_init(RSA_PKCS1_OpenSSL())(rsa);
+}
+static int dasync_rsa_finish(RSA *rsa)
+{
+    return RSA_meth_get_finish(RSA_PKCS1_OpenSSL())(rsa);
+}
+
+/* Cipher helper functions */
+
+static int dasync_cipher_ctrl_helper(EVP_CIPHER_CTX *ctx, int type, int arg,
+                                     void *ptr, int aeadcapable)
+{
+    int ret;
+    struct dasync_pipeline_ctx *pipe_ctx =
+        (struct dasync_pipeline_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
+
+    if (pipe_ctx == NULL)
+        return 0;
+
+    switch (type) {
+        case EVP_CTRL_SET_PIPELINE_OUTPUT_BUFS:
+            pipe_ctx->numpipes = arg;
+            pipe_ctx->outbufs = (unsigned char **)ptr;
+            break;
+
+        case EVP_CTRL_SET_PIPELINE_INPUT_BUFS:
+            pipe_ctx->numpipes = arg;
+            pipe_ctx->inbufs = (unsigned char **)ptr;
+            break;
+
+        case EVP_CTRL_SET_PIPELINE_INPUT_LENS:
+            pipe_ctx->numpipes = arg;
+            pipe_ctx->lens = (size_t *)ptr;
+            break;
+
+        case EVP_CTRL_AEAD_SET_MAC_KEY:
+            if (!aeadcapable)
+                return -1;
+            EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx->inner_cipher_data);
+            ret = EVP_CIPHER_meth_get_ctrl(EVP_aes_128_cbc_hmac_sha1())
+                                          (ctx, type, arg, ptr);
+            EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx);
+            return ret;
+
+        case EVP_CTRL_AEAD_TLS1_AAD:
+        {
+            unsigned char *p = ptr;
+            unsigned int len;
+
+            if (!aeadcapable || arg != EVP_AEAD_TLS1_AAD_LEN)
+                return -1;
+
+            if (pipe_ctx->aadctr >= SSL_MAX_PIPELINES)
+                return -1;
+
+            memcpy(pipe_ctx->tlsaad[pipe_ctx->aadctr], ptr,
+                   EVP_AEAD_TLS1_AAD_LEN);
+            pipe_ctx->aadctr++;
+
+            len = p[arg - 2] << 8 | p[arg - 1];
+
+            if (EVP_CIPHER_CTX_encrypting(ctx)) {
+                if ((p[arg - 4] << 8 | p[arg - 3]) >= TLS1_1_VERSION) {
+                    if (len < AES_BLOCK_SIZE)
+                        return 0;
+                    len -= AES_BLOCK_SIZE;
+                }
+
+                return ((len + SHA_DIGEST_LENGTH + AES_BLOCK_SIZE)
+                        & -AES_BLOCK_SIZE) - len;
+            } else {
+                return SHA_DIGEST_LENGTH;
+            }
+        }
+
+        case EVP_CTRL_COPY:
+        {
+            const EVP_CIPHER *cipher = aeadcapable
+                                       ? EVP_aes_128_cbc_hmac_sha1()
+                                       : EVP_aes_128_cbc();
+            size_t data_size = EVP_CIPHER_impl_ctx_size(cipher);
+            void *cipher_data = OPENSSL_malloc(data_size);
+
+            if (cipher_data == NULL)
+                return 0;
+            memcpy(cipher_data, pipe_ctx->inner_cipher_data, data_size);
+            pipe_ctx->inner_cipher_data = cipher_data;
+            return 1;
+        }
+
+        default:
+            return 0;
+    }
+
+    return 1;
+}
+
+static int dasync_cipher_init_key_helper(EVP_CIPHER_CTX *ctx,
+                                         const unsigned char *key,
+                                         const unsigned char *iv, int enc,
+                                         const EVP_CIPHER *cipher)
+{
+    int ret;
+    struct dasync_pipeline_ctx *pipe_ctx =
+        (struct dasync_pipeline_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
+
+    if (pipe_ctx->inner_cipher_data == NULL
+            && EVP_CIPHER_impl_ctx_size(cipher) != 0) {
+        pipe_ctx->inner_cipher_data = OPENSSL_zalloc(
+            EVP_CIPHER_impl_ctx_size(cipher));
+        if (pipe_ctx->inner_cipher_data == NULL) {
+            DASYNCerr(DASYNC_F_DASYNC_CIPHER_INIT_KEY_HELPER,
+                        ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+    }
+
+    pipe_ctx->numpipes = 0;
+    pipe_ctx->aadctr = 0;
+
+    EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx->inner_cipher_data);
+    ret = EVP_CIPHER_meth_get_init(cipher)(ctx, key, iv, enc);
+    EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx);
+
+    return ret;
+}
+
+static int dasync_cipher_helper(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                                const unsigned char *in, size_t inl,
+                                const EVP_CIPHER *cipher)
+{
+    int ret = 1;
+    unsigned int i, pipes;
+    struct dasync_pipeline_ctx *pipe_ctx =
+        (struct dasync_pipeline_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
+
+    pipes = pipe_ctx->numpipes;
+    EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx->inner_cipher_data);
+    if (pipes == 0) {
+        if (pipe_ctx->aadctr != 0) {
+            if (pipe_ctx->aadctr != 1)
+                return -1;
+            EVP_CIPHER_meth_get_ctrl(cipher)
+                                    (ctx, EVP_CTRL_AEAD_TLS1_AAD,
+                                     EVP_AEAD_TLS1_AAD_LEN,
+                                     pipe_ctx->tlsaad[0]);
+        }
+        ret = EVP_CIPHER_meth_get_do_cipher(cipher)
+                                           (ctx, out, in, inl);
+    } else {
+        if (pipe_ctx->aadctr > 0 && pipe_ctx->aadctr != pipes)
+            return -1;
+        for (i = 0; i < pipes; i++) {
+            if (pipe_ctx->aadctr > 0) {
+                EVP_CIPHER_meth_get_ctrl(cipher)
+                                        (ctx, EVP_CTRL_AEAD_TLS1_AAD,
+                                         EVP_AEAD_TLS1_AAD_LEN,
+                                         pipe_ctx->tlsaad[i]);
+            }
+            ret = ret && EVP_CIPHER_meth_get_do_cipher(cipher)
+                                (ctx, pipe_ctx->outbufs[i], pipe_ctx->inbufs[i],
+                                 pipe_ctx->lens[i]);
+        }
+        pipe_ctx->numpipes = 0;
+    }
+    pipe_ctx->aadctr = 0;
+    EVP_CIPHER_CTX_set_cipher_data(ctx, pipe_ctx);
+    return ret;
+}
+
+static int dasync_cipher_cleanup_helper(EVP_CIPHER_CTX *ctx,
+                                        const EVP_CIPHER *cipher)
+{
+    struct dasync_pipeline_ctx *pipe_ctx =
+        (struct dasync_pipeline_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
+
+    OPENSSL_clear_free(pipe_ctx->inner_cipher_data,
+                       EVP_CIPHER_impl_ctx_size(cipher));
+
+    return 1;
+}
+
+/*
+ * AES128 CBC Implementation
+ */
+
+static int dasync_aes128_cbc_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
+                                  void *ptr)
+{
+    return dasync_cipher_ctrl_helper(ctx, type, arg, ptr, 0);
+}
+
+static int dasync_aes128_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                             const unsigned char *iv, int enc)
+{
+    return dasync_cipher_init_key_helper(ctx, key, iv, enc, EVP_aes_128_cbc());
+}
+
+static int dasync_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                               const unsigned char *in, size_t inl)
+{
+    return dasync_cipher_helper(ctx, out, in, inl, EVP_aes_128_cbc());
+}
+
+static int dasync_aes128_cbc_cleanup(EVP_CIPHER_CTX *ctx)
+{
+    return dasync_cipher_cleanup_helper(ctx, EVP_aes_128_cbc());
+}
+
+
+/*
+ * AES128 CBC HMAC SHA1 Implementation
+ */
+
+static int dasync_aes128_cbc_hmac_sha1_ctrl(EVP_CIPHER_CTX *ctx, int type,
+                                             int arg, void *ptr)
+{
+    return dasync_cipher_ctrl_helper(ctx, type, arg, ptr, 1);
+}
+
+static int dasync_aes128_cbc_hmac_sha1_init_key(EVP_CIPHER_CTX *ctx,
+                                                const unsigned char *key,
+                                                const unsigned char *iv,
+                                                int enc)
+{
+    /*
+     * We can safely assume that EVP_aes_128_cbc_hmac_sha1() != NULL,
+     * see comment before the definition of dasync_aes_128_cbc_hmac_sha1().
+     */
+    return dasync_cipher_init_key_helper(ctx, key, iv, enc,
+                                         EVP_aes_128_cbc_hmac_sha1());
+}
+
+static int dasync_aes128_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx,
+                                               unsigned char *out,
+                                               const unsigned char *in,
+                                               size_t inl)
+{
+    return dasync_cipher_helper(ctx, out, in, inl, EVP_aes_128_cbc_hmac_sha1());
+}
+
+static int dasync_aes128_cbc_hmac_sha1_cleanup(EVP_CIPHER_CTX *ctx)
+{
+    /*
+     * We can safely assume that EVP_aes_128_cbc_hmac_sha1() != NULL,
+     * see comment before the definition of dasync_aes_128_cbc_hmac_sha1().
+     */
+    return dasync_cipher_cleanup_helper(ctx, EVP_aes_128_cbc_hmac_sha1());
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync.ec b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync.ec
new file mode 100644
index 0000000..3d56ebc
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync.ec
@@ -0,0 +1,3 @@
+# The INPUT HEADER is scanned for declarations
+# LIBNAME       INPUT HEADER                    ERROR-TABLE FILE
+L DASYNC        e_dasync_err.h                  e_dasync_err.c
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync.txt b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync.txt
new file mode 100644
index 0000000..bff64bc
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync.txt
@@ -0,0 +1,22 @@
+# Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+# Function codes
+DASYNC_F_BIND_DASYNC:107:bind_dasync
+DASYNC_F_CIPHER_AES_128_CBC_CODE:100:*
+DASYNC_F_DASYNC_AES128_CBC_HMAC_SHA1_INIT_KEY:109:*
+DASYNC_F_DASYNC_AES128_INIT_KEY:108:*
+DASYNC_F_DASYNC_BN_MOD_EXP:101:*
+DASYNC_F_DASYNC_CIPHER_INIT_KEY_HELPER:110:dasync_cipher_init_key_helper
+DASYNC_F_DASYNC_MOD_EXP:102:*
+DASYNC_F_DASYNC_PRIVATE_DECRYPT:103:*
+DASYNC_F_DASYNC_PRIVATE_ENCRYPT:104:*
+DASYNC_F_DASYNC_PUBLIC_DECRYPT:105:*
+DASYNC_F_DASYNC_PUBLIC_ENCRYPT:106:*
+
+#Reason codes
+DASYNC_R_INIT_FAILED:100:init failed
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync_err.c b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync_err.c
new file mode 100644
index 0000000..794fb71
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync_err.c
@@ -0,0 +1,73 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/err.h>
+#include "e_dasync_err.h"
+
+#ifndef OPENSSL_NO_ERR
+
+static ERR_STRING_DATA DASYNC_str_functs[] = {
+    {ERR_PACK(0, DASYNC_F_BIND_DASYNC, 0), "bind_dasync"},
+    {ERR_PACK(0, DASYNC_F_CIPHER_AES_128_CBC_CODE, 0), ""},
+    {ERR_PACK(0, DASYNC_F_DASYNC_AES128_CBC_HMAC_SHA1_INIT_KEY, 0), ""},
+    {ERR_PACK(0, DASYNC_F_DASYNC_AES128_INIT_KEY, 0), ""},
+    {ERR_PACK(0, DASYNC_F_DASYNC_BN_MOD_EXP, 0), ""},
+    {ERR_PACK(0, DASYNC_F_DASYNC_CIPHER_INIT_KEY_HELPER, 0),
+     "dasync_cipher_init_key_helper"},
+    {ERR_PACK(0, DASYNC_F_DASYNC_MOD_EXP, 0), ""},
+    {ERR_PACK(0, DASYNC_F_DASYNC_PRIVATE_DECRYPT, 0), ""},
+    {ERR_PACK(0, DASYNC_F_DASYNC_PRIVATE_ENCRYPT, 0), ""},
+    {ERR_PACK(0, DASYNC_F_DASYNC_PUBLIC_DECRYPT, 0), ""},
+    {ERR_PACK(0, DASYNC_F_DASYNC_PUBLIC_ENCRYPT, 0), ""},
+    {0, NULL}
+};
+
+static ERR_STRING_DATA DASYNC_str_reasons[] = {
+    {ERR_PACK(0, 0, DASYNC_R_INIT_FAILED), "init failed"},
+    {0, NULL}
+};
+
+#endif
+
+static int lib_code = 0;
+static int error_loaded = 0;
+
+static int ERR_load_DASYNC_strings(void)
+{
+    if (lib_code == 0)
+        lib_code = ERR_get_next_error_library();
+
+    if (!error_loaded) {
+#ifndef OPENSSL_NO_ERR
+        ERR_load_strings(lib_code, DASYNC_str_functs);
+        ERR_load_strings(lib_code, DASYNC_str_reasons);
+#endif
+        error_loaded = 1;
+    }
+    return 1;
+}
+
+static void ERR_unload_DASYNC_strings(void)
+{
+    if (error_loaded) {
+#ifndef OPENSSL_NO_ERR
+        ERR_unload_strings(lib_code, DASYNC_str_functs);
+        ERR_unload_strings(lib_code, DASYNC_str_reasons);
+#endif
+        error_loaded = 0;
+    }
+}
+
+static void ERR_DASYNC_error(int function, int reason, char *file, int line)
+{
+    if (lib_code == 0)
+        lib_code = ERR_get_next_error_library();
+    ERR_PUT_error(lib_code, function, reason, file, line);
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync_err.h b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync_err.h
new file mode 100644
index 0000000..5b74d8b
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_dasync_err.h
@@ -0,0 +1,37 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_ENGINES_E_DASYNC_ERR_H
+# define OSSL_ENGINES_E_DASYNC_ERR_H
+
+# define DASYNCerr(f, r) ERR_DASYNC_error((f), (r), OPENSSL_FILE, OPENSSL_LINE)
+
+
+/*
+ * DASYNC function codes.
+ */
+# define DASYNC_F_BIND_DASYNC                             107
+# define DASYNC_F_CIPHER_AES_128_CBC_CODE                 100
+# define DASYNC_F_DASYNC_AES128_CBC_HMAC_SHA1_INIT_KEY    109
+# define DASYNC_F_DASYNC_AES128_INIT_KEY                  108
+# define DASYNC_F_DASYNC_BN_MOD_EXP                       101
+# define DASYNC_F_DASYNC_CIPHER_INIT_KEY_HELPER           110
+# define DASYNC_F_DASYNC_MOD_EXP                          102
+# define DASYNC_F_DASYNC_PRIVATE_DECRYPT                  103
+# define DASYNC_F_DASYNC_PRIVATE_ENCRYPT                  104
+# define DASYNC_F_DASYNC_PUBLIC_DECRYPT                   105
+# define DASYNC_F_DASYNC_PUBLIC_ENCRYPT                   106
+
+/*
+ * DASYNC reason codes.
+ */
+# define DASYNC_R_INIT_FAILED                             100
+
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest.c b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest.c
new file mode 100644
index 0000000..6437624
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest.c
@@ -0,0 +1,696 @@
+/*
+ * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * This is the OSSLTEST engine. It provides deliberately crippled digest
+ * implementations for test purposes. It is highly insecure and must NOT be
+ * used for any purpose except testing
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/engine.h>
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/modes.h>
+#include <openssl/aes.h>
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
+
+#include "e_ossltest_err.c"
+
+/* Engine Id and Name */
+static const char *engine_ossltest_id = "ossltest";
+static const char *engine_ossltest_name = "OpenSSL Test engine support";
+
+
+/* Engine Lifetime functions */
+static int ossltest_destroy(ENGINE *e);
+static int ossltest_init(ENGINE *e);
+static int ossltest_finish(ENGINE *e);
+void ENGINE_load_ossltest(void);
+
+
+/* Set up digests */
+static int ossltest_digests(ENGINE *e, const EVP_MD **digest,
+                          const int **nids, int nid);
+static const RAND_METHOD *ossltest_rand_method(void);
+
+/* MD5 */
+static int digest_md5_init(EVP_MD_CTX *ctx);
+static int digest_md5_update(EVP_MD_CTX *ctx, const void *data,
+                             size_t count);
+static int digest_md5_final(EVP_MD_CTX *ctx, unsigned char *md);
+
+static EVP_MD *_hidden_md5_md = NULL;
+static const EVP_MD *digest_md5(void)
+{
+    if (_hidden_md5_md == NULL) {
+        EVP_MD *md;
+
+        if ((md = EVP_MD_meth_new(NID_md5, NID_md5WithRSAEncryption)) == NULL
+            || !EVP_MD_meth_set_result_size(md, MD5_DIGEST_LENGTH)
+            || !EVP_MD_meth_set_input_blocksize(md, MD5_CBLOCK)
+            || !EVP_MD_meth_set_app_datasize(md,
+                                             sizeof(EVP_MD *) + sizeof(MD5_CTX))
+            || !EVP_MD_meth_set_flags(md, 0)
+            || !EVP_MD_meth_set_init(md, digest_md5_init)
+            || !EVP_MD_meth_set_update(md, digest_md5_update)
+            || !EVP_MD_meth_set_final(md, digest_md5_final)) {
+            EVP_MD_meth_free(md);
+            md = NULL;
+        }
+        _hidden_md5_md = md;
+    }
+    return _hidden_md5_md;
+}
+
+/* SHA1 */
+static int digest_sha1_init(EVP_MD_CTX *ctx);
+static int digest_sha1_update(EVP_MD_CTX *ctx, const void *data,
+                              size_t count);
+static int digest_sha1_final(EVP_MD_CTX *ctx, unsigned char *md);
+
+static EVP_MD *_hidden_sha1_md = NULL;
+static const EVP_MD *digest_sha1(void)
+{
+    if (_hidden_sha1_md == NULL) {
+        EVP_MD *md;
+
+        if ((md = EVP_MD_meth_new(NID_sha1, NID_sha1WithRSAEncryption)) == NULL
+            || !EVP_MD_meth_set_result_size(md, SHA_DIGEST_LENGTH)
+            || !EVP_MD_meth_set_input_blocksize(md, SHA_CBLOCK)
+            || !EVP_MD_meth_set_app_datasize(md,
+                                             sizeof(EVP_MD *) + sizeof(SHA_CTX))
+            || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_DIGALGID_ABSENT)
+            || !EVP_MD_meth_set_init(md, digest_sha1_init)
+            || !EVP_MD_meth_set_update(md, digest_sha1_update)
+            || !EVP_MD_meth_set_final(md, digest_sha1_final)) {
+            EVP_MD_meth_free(md);
+            md = NULL;
+        }
+        _hidden_sha1_md = md;
+    }
+    return _hidden_sha1_md;
+}
+
+/* SHA256 */
+static int digest_sha256_init(EVP_MD_CTX *ctx);
+static int digest_sha256_update(EVP_MD_CTX *ctx, const void *data,
+                                size_t count);
+static int digest_sha256_final(EVP_MD_CTX *ctx, unsigned char *md);
+
+static EVP_MD *_hidden_sha256_md = NULL;
+static const EVP_MD *digest_sha256(void)
+{
+    if (_hidden_sha256_md == NULL) {
+        EVP_MD *md;
+
+        if ((md = EVP_MD_meth_new(NID_sha256, NID_sha256WithRSAEncryption)) == NULL
+            || !EVP_MD_meth_set_result_size(md, SHA256_DIGEST_LENGTH)
+            || !EVP_MD_meth_set_input_blocksize(md, SHA256_CBLOCK)
+            || !EVP_MD_meth_set_app_datasize(md,
+                                             sizeof(EVP_MD *) + sizeof(SHA256_CTX))
+            || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_DIGALGID_ABSENT)
+            || !EVP_MD_meth_set_init(md, digest_sha256_init)
+            || !EVP_MD_meth_set_update(md, digest_sha256_update)
+            || !EVP_MD_meth_set_final(md, digest_sha256_final)) {
+            EVP_MD_meth_free(md);
+            md = NULL;
+        }
+        _hidden_sha256_md = md;
+    }
+    return _hidden_sha256_md;
+}
+
+/* SHA384/SHA512 */
+static int digest_sha384_init(EVP_MD_CTX *ctx);
+static int digest_sha512_init(EVP_MD_CTX *ctx);
+static int digest_sha512_update(EVP_MD_CTX *ctx, const void *data,
+                                size_t count);
+static int digest_sha384_final(EVP_MD_CTX *ctx, unsigned char *md);
+static int digest_sha512_final(EVP_MD_CTX *ctx, unsigned char *md);
+
+static EVP_MD *_hidden_sha384_md = NULL;
+static const EVP_MD *digest_sha384(void)
+{
+    if (_hidden_sha384_md == NULL) {
+        EVP_MD *md;
+
+        if ((md = EVP_MD_meth_new(NID_sha384, NID_sha384WithRSAEncryption)) == NULL
+            || !EVP_MD_meth_set_result_size(md, SHA384_DIGEST_LENGTH)
+            || !EVP_MD_meth_set_input_blocksize(md, SHA512_CBLOCK)
+            || !EVP_MD_meth_set_app_datasize(md,
+                                             sizeof(EVP_MD *) + sizeof(SHA512_CTX))
+            || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_DIGALGID_ABSENT)
+            || !EVP_MD_meth_set_init(md, digest_sha384_init)
+            || !EVP_MD_meth_set_update(md, digest_sha512_update)
+            || !EVP_MD_meth_set_final(md, digest_sha384_final)) {
+            EVP_MD_meth_free(md);
+            md = NULL;
+        }
+        _hidden_sha384_md = md;
+    }
+    return _hidden_sha384_md;
+}
+static EVP_MD *_hidden_sha512_md = NULL;
+static const EVP_MD *digest_sha512(void)
+{
+    if (_hidden_sha512_md == NULL) {
+        EVP_MD *md;
+
+        if ((md = EVP_MD_meth_new(NID_sha512, NID_sha512WithRSAEncryption)) == NULL
+            || !EVP_MD_meth_set_result_size(md, SHA512_DIGEST_LENGTH)
+            || !EVP_MD_meth_set_input_blocksize(md, SHA512_CBLOCK)
+            || !EVP_MD_meth_set_app_datasize(md,
+                                             sizeof(EVP_MD *) + sizeof(SHA512_CTX))
+            || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_DIGALGID_ABSENT)
+            || !EVP_MD_meth_set_init(md, digest_sha512_init)
+            || !EVP_MD_meth_set_update(md, digest_sha512_update)
+            || !EVP_MD_meth_set_final(md, digest_sha512_final)) {
+            EVP_MD_meth_free(md);
+            md = NULL;
+        }
+        _hidden_sha512_md = md;
+    }
+    return _hidden_sha512_md;
+}
+static void destroy_digests(void)
+{
+    EVP_MD_meth_free(_hidden_md5_md);
+    _hidden_md5_md = NULL;
+    EVP_MD_meth_free(_hidden_sha1_md);
+    _hidden_sha1_md = NULL;
+    EVP_MD_meth_free(_hidden_sha256_md);
+    _hidden_sha256_md = NULL;
+    EVP_MD_meth_free(_hidden_sha384_md);
+    _hidden_sha384_md = NULL;
+    EVP_MD_meth_free(_hidden_sha512_md);
+    _hidden_sha512_md = NULL;
+}
+static int ossltest_digest_nids(const int **nids)
+{
+    static int digest_nids[6] = { 0, 0, 0, 0, 0, 0 };
+    static int pos = 0;
+    static int init = 0;
+
+    if (!init) {
+        const EVP_MD *md;
+        if ((md = digest_md5()) != NULL)
+            digest_nids[pos++] = EVP_MD_type(md);
+        if ((md = digest_sha1()) != NULL)
+            digest_nids[pos++] = EVP_MD_type(md);
+        if ((md = digest_sha256()) != NULL)
+            digest_nids[pos++] = EVP_MD_type(md);
+        if ((md = digest_sha384()) != NULL)
+            digest_nids[pos++] = EVP_MD_type(md);
+        if ((md = digest_sha512()) != NULL)
+            digest_nids[pos++] = EVP_MD_type(md);
+        digest_nids[pos] = 0;
+        init = 1;
+    }
+    *nids = digest_nids;
+    return pos;
+}
+
+/* Setup ciphers */
+static int ossltest_ciphers(ENGINE *, const EVP_CIPHER **,
+                            const int **, int);
+
+static int ossltest_cipher_nids[] = {
+    NID_aes_128_cbc, NID_aes_128_gcm, 0
+};
+
+/* AES128 */
+
+int ossltest_aes128_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                             const unsigned char *iv, int enc);
+int ossltest_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                               const unsigned char *in, size_t inl);
+int ossltest_aes128_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                             const unsigned char *iv, int enc);
+int ossltest_aes128_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                               const unsigned char *in, size_t inl);
+static int ossltest_aes128_gcm_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
+                                    void *ptr);
+
+static EVP_CIPHER *_hidden_aes_128_cbc = NULL;
+static const EVP_CIPHER *ossltest_aes_128_cbc(void)
+{
+    if (_hidden_aes_128_cbc == NULL
+        && ((_hidden_aes_128_cbc = EVP_CIPHER_meth_new(NID_aes_128_cbc,
+                                                       16 /* block size */,
+                                                       16 /* key len */)) == NULL
+            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_128_cbc,16)
+            || !EVP_CIPHER_meth_set_flags(_hidden_aes_128_cbc,
+                                          EVP_CIPH_FLAG_DEFAULT_ASN1
+                                          | EVP_CIPH_CBC_MODE)
+            || !EVP_CIPHER_meth_set_init(_hidden_aes_128_cbc,
+                                         ossltest_aes128_init_key)
+            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_128_cbc,
+                                              ossltest_aes128_cbc_cipher)
+            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_128_cbc,
+                                                  EVP_CIPHER_impl_ctx_size(EVP_aes_128_cbc())))) {
+        EVP_CIPHER_meth_free(_hidden_aes_128_cbc);
+        _hidden_aes_128_cbc = NULL;
+    }
+    return _hidden_aes_128_cbc;
+}
+static EVP_CIPHER *_hidden_aes_128_gcm = NULL;
+
+#define AES_GCM_FLAGS   (EVP_CIPH_FLAG_DEFAULT_ASN1 \
+                | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER \
+                | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT \
+                | EVP_CIPH_CUSTOM_COPY |EVP_CIPH_FLAG_AEAD_CIPHER \
+                | EVP_CIPH_GCM_MODE)
+
+static const EVP_CIPHER *ossltest_aes_128_gcm(void)
+{
+    if (_hidden_aes_128_gcm == NULL
+        && ((_hidden_aes_128_gcm = EVP_CIPHER_meth_new(NID_aes_128_gcm,
+                                                       1 /* block size */,
+                                                       16 /* key len */)) == NULL
+            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_128_gcm,12)
+            || !EVP_CIPHER_meth_set_flags(_hidden_aes_128_gcm, AES_GCM_FLAGS)
+            || !EVP_CIPHER_meth_set_init(_hidden_aes_128_gcm,
+                                         ossltest_aes128_gcm_init_key)
+            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_128_gcm,
+                                              ossltest_aes128_gcm_cipher)
+            || !EVP_CIPHER_meth_set_ctrl(_hidden_aes_128_gcm,
+                                              ossltest_aes128_gcm_ctrl)
+            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_128_gcm,
+                              EVP_CIPHER_impl_ctx_size(EVP_aes_128_gcm())))) {
+        EVP_CIPHER_meth_free(_hidden_aes_128_gcm);
+        _hidden_aes_128_gcm = NULL;
+    }
+    return _hidden_aes_128_gcm;
+}
+
+static void destroy_ciphers(void)
+{
+    EVP_CIPHER_meth_free(_hidden_aes_128_cbc);
+    EVP_CIPHER_meth_free(_hidden_aes_128_gcm);
+    _hidden_aes_128_cbc = NULL;
+}
+
+static int bind_ossltest(ENGINE *e)
+{
+    /* Ensure the ossltest error handling is set up */
+    ERR_load_OSSLTEST_strings();
+
+    if (!ENGINE_set_id(e, engine_ossltest_id)
+        || !ENGINE_set_name(e, engine_ossltest_name)
+        || !ENGINE_set_digests(e, ossltest_digests)
+        || !ENGINE_set_ciphers(e, ossltest_ciphers)
+        || !ENGINE_set_RAND(e, ossltest_rand_method())
+        || !ENGINE_set_destroy_function(e, ossltest_destroy)
+        || !ENGINE_set_init_function(e, ossltest_init)
+        || !ENGINE_set_finish_function(e, ossltest_finish)) {
+        OSSLTESTerr(OSSLTEST_F_BIND_OSSLTEST, OSSLTEST_R_INIT_FAILED);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_DYNAMIC_ENGINE
+static int bind_helper(ENGINE *e, const char *id)
+{
+    if (id && (strcmp(id, engine_ossltest_id) != 0))
+        return 0;
+    if (!bind_ossltest(e))
+        return 0;
+    return 1;
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+    IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
+#endif
+
+static ENGINE *engine_ossltest(void)
+{
+    ENGINE *ret = ENGINE_new();
+    if (ret == NULL)
+        return NULL;
+    if (!bind_ossltest(ret)) {
+        ENGINE_free(ret);
+        return NULL;
+    }
+    return ret;
+}
+
+void ENGINE_load_ossltest(void)
+{
+    /* Copied from eng_[openssl|dyn].c */
+    ENGINE *toadd = engine_ossltest();
+    if (!toadd)
+        return;
+    ENGINE_add(toadd);
+    ENGINE_free(toadd);
+    ERR_clear_error();
+}
+
+
+static int ossltest_init(ENGINE *e)
+{
+    return 1;
+}
+
+
+static int ossltest_finish(ENGINE *e)
+{
+    return 1;
+}
+
+
+static int ossltest_destroy(ENGINE *e)
+{
+    destroy_digests();
+    destroy_ciphers();
+    ERR_unload_OSSLTEST_strings();
+    return 1;
+}
+
+static int ossltest_digests(ENGINE *e, const EVP_MD **digest,
+                          const int **nids, int nid)
+{
+    int ok = 1;
+    if (!digest) {
+        /* We are returning a list of supported nids */
+        return ossltest_digest_nids(nids);
+    }
+    /* We are being asked for a specific digest */
+    switch (nid) {
+    case NID_md5:
+        *digest = digest_md5();
+        break;
+    case NID_sha1:
+        *digest = digest_sha1();
+        break;
+    case NID_sha256:
+        *digest = digest_sha256();
+        break;
+    case NID_sha384:
+        *digest = digest_sha384();
+        break;
+    case NID_sha512:
+        *digest = digest_sha512();
+        break;
+    default:
+        ok = 0;
+        *digest = NULL;
+        break;
+    }
+    return ok;
+}
+
+static int ossltest_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+                          const int **nids, int nid)
+{
+    int ok = 1;
+    if (!cipher) {
+        /* We are returning a list of supported nids */
+        *nids = ossltest_cipher_nids;
+        return (sizeof(ossltest_cipher_nids) - 1)
+               / sizeof(ossltest_cipher_nids[0]);
+    }
+    /* We are being asked for a specific cipher */
+    switch (nid) {
+    case NID_aes_128_cbc:
+        *cipher = ossltest_aes_128_cbc();
+        break;
+    case NID_aes_128_gcm:
+        *cipher = ossltest_aes_128_gcm();
+        break;
+    default:
+        ok = 0;
+        *cipher = NULL;
+        break;
+    }
+    return ok;
+}
+
+static void fill_known_data(unsigned char *md, unsigned int len)
+{
+    unsigned int i;
+
+    for (i=0; i<len; i++) {
+        md[i] = (unsigned char)(i & 0xff);
+    }
+}
+
+/*
+ * MD5 implementation. We go through the motions of doing MD5 by deferring to
+ * the standard implementation. Then we overwrite the result with a will defined
+ * value, so that all "MD5" digests using the test engine always end up with
+ * the same value.
+ */
+#undef data
+#define data(ctx) ((MD5_CTX *)EVP_MD_CTX_md_data(ctx))
+static int digest_md5_init(EVP_MD_CTX *ctx)
+{
+    return MD5_Init(data(ctx));
+}
+
+static int digest_md5_update(EVP_MD_CTX *ctx, const void *data,
+                             size_t count)
+{
+    return MD5_Update(data(ctx), data, (size_t)count);
+}
+
+static int digest_md5_final(EVP_MD_CTX *ctx, unsigned char *md)
+{
+    int ret;
+    ret = MD5_Final(md, data(ctx));
+
+    if (ret > 0) {
+        fill_known_data(md, MD5_DIGEST_LENGTH);
+    }
+    return ret;
+}
+
+/*
+ * SHA1 implementation.
+ */
+#undef data
+#define data(ctx) ((SHA_CTX *)EVP_MD_CTX_md_data(ctx))
+static int digest_sha1_init(EVP_MD_CTX *ctx)
+{
+    return SHA1_Init(data(ctx));
+}
+
+static int digest_sha1_update(EVP_MD_CTX *ctx, const void *data,
+                              size_t count)
+{
+    return SHA1_Update(data(ctx), data, (size_t)count);
+}
+
+static int digest_sha1_final(EVP_MD_CTX *ctx, unsigned char *md)
+{
+    int ret;
+    ret = SHA1_Final(md, data(ctx));
+
+    if (ret > 0) {
+        fill_known_data(md, SHA_DIGEST_LENGTH);
+    }
+    return ret;
+}
+
+/*
+ * SHA256 implementation.
+ */
+#undef data
+#define data(ctx) ((SHA256_CTX *)EVP_MD_CTX_md_data(ctx))
+static int digest_sha256_init(EVP_MD_CTX *ctx)
+{
+    return SHA256_Init(data(ctx));
+}
+
+static int digest_sha256_update(EVP_MD_CTX *ctx, const void *data,
+                                size_t count)
+{
+    return SHA256_Update(data(ctx), data, (size_t)count);
+}
+
+static int digest_sha256_final(EVP_MD_CTX *ctx, unsigned char *md)
+{
+    int ret;
+    ret = SHA256_Final(md, data(ctx));
+
+    if (ret > 0) {
+        fill_known_data(md, SHA256_DIGEST_LENGTH);
+    }
+    return ret;
+}
+
+/*
+ * SHA384/512 implementation.
+ */
+#undef data
+#define data(ctx) ((SHA512_CTX *)EVP_MD_CTX_md_data(ctx))
+static int digest_sha384_init(EVP_MD_CTX *ctx)
+{
+    return SHA384_Init(data(ctx));
+}
+
+static int digest_sha512_init(EVP_MD_CTX *ctx)
+{
+    return SHA512_Init(data(ctx));
+}
+
+static int digest_sha512_update(EVP_MD_CTX *ctx, const void *data,
+                                size_t count)
+{
+    return SHA512_Update(data(ctx), data, (size_t)count);
+}
+
+static int digest_sha384_final(EVP_MD_CTX *ctx, unsigned char *md)
+{
+    int ret;
+    /* Actually uses SHA512_Final! */
+    ret = SHA512_Final(md, data(ctx));
+
+    if (ret > 0) {
+        fill_known_data(md, SHA384_DIGEST_LENGTH);
+    }
+    return ret;
+}
+
+static int digest_sha512_final(EVP_MD_CTX *ctx, unsigned char *md)
+{
+    int ret;
+    ret = SHA512_Final(md, data(ctx));
+
+    if (ret > 0) {
+        fill_known_data(md, SHA512_DIGEST_LENGTH);
+    }
+    return ret;
+}
+
+/*
+ * AES128 Implementation
+ */
+
+int ossltest_aes128_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                             const unsigned char *iv, int enc)
+{
+    return EVP_CIPHER_meth_get_init(EVP_aes_128_cbc()) (ctx, key, iv, enc);
+}
+
+int ossltest_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                               const unsigned char *in, size_t inl)
+{
+    unsigned char *tmpbuf;
+    int ret;
+
+    tmpbuf = OPENSSL_malloc(inl);
+
+    /* OPENSSL_malloc will return NULL if inl == 0 */
+    if (tmpbuf == NULL && inl > 0)
+        return -1;
+
+    /* Remember what we were asked to encrypt */
+    if (tmpbuf != NULL)
+        memcpy(tmpbuf, in, inl);
+
+    /* Go through the motions of encrypting it */
+    ret = EVP_CIPHER_meth_get_do_cipher(EVP_aes_128_cbc())(ctx, out, in, inl);
+
+    /* Throw it all away and just use the plaintext as the output */
+    if (tmpbuf != NULL)
+        memcpy(out, tmpbuf, inl);
+    OPENSSL_free(tmpbuf);
+
+    return ret;
+}
+
+int ossltest_aes128_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                             const unsigned char *iv, int enc)
+{
+    return EVP_CIPHER_meth_get_init(EVP_aes_128_gcm()) (ctx, key, iv, enc);
+}
+
+
+int ossltest_aes128_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                               const unsigned char *in, size_t inl)
+{
+    unsigned char *tmpbuf = OPENSSL_malloc(inl);
+
+    /* OPENSSL_malloc will return NULL if inl == 0 */
+    if (tmpbuf == NULL && inl > 0)
+        return -1;
+
+    /* Remember what we were asked to encrypt */
+    if (tmpbuf != NULL)
+        memcpy(tmpbuf, in, inl);
+
+    /* Go through the motions of encrypting it */
+    EVP_CIPHER_meth_get_do_cipher(EVP_aes_128_gcm())(ctx, out, in, inl);
+
+    /* Throw it all away and just use the plaintext as the output */
+    if (tmpbuf != NULL && out != NULL)
+        memcpy(out, tmpbuf, inl);
+    OPENSSL_free(tmpbuf);
+
+    return inl;
+}
+
+static int ossltest_aes128_gcm_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
+                                    void *ptr)
+{
+    /* Pass the ctrl down */
+    int ret = EVP_CIPHER_meth_get_ctrl(EVP_aes_128_gcm())(ctx, type, arg, ptr);
+
+    if (ret <= 0)
+        return ret;
+
+    switch(type) {
+    case EVP_CTRL_AEAD_GET_TAG:
+        /* Always give the same tag */
+        memset(ptr, 0, EVP_GCM_TLS_TAG_LEN);
+        break;
+
+    default:
+        break;
+    }
+
+    return 1;
+}
+
+static int ossltest_rand_bytes(unsigned char *buf, int num)
+{
+    unsigned char val = 1;
+
+    while (--num >= 0)
+        *buf++ = val++;
+    return 1;
+}
+
+static int ossltest_rand_status(void)
+{
+    return 1;
+}
+
+static const RAND_METHOD *ossltest_rand_method(void)
+{
+
+    static RAND_METHOD osslt_rand_meth = {
+        NULL,
+        ossltest_rand_bytes,
+        NULL,
+        NULL,
+        ossltest_rand_bytes,
+        ossltest_rand_status
+    };
+
+    return &osslt_rand_meth;
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest.ec b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest.ec
new file mode 100644
index 0000000..a4a55ec
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest.ec
@@ -0,0 +1,3 @@
+# The INPUT HEADER is scanned for declarations
+# LIBNAME       INPUT HEADER                    ERROR-TABLE FILE
+L OSSLTEST      e_ossltest_err.h                e_ossltest_err.c
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest.txt b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest.txt
new file mode 100644
index 0000000..2b2e31a
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest.txt
@@ -0,0 +1,13 @@
+# Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+# Function codes
+OSSLTEST_F_BIND_OSSLTEST:100:bind_ossltest
+OSSLTEST_F_OSSLTEST_AES128_INIT_KEY:101:*
+
+#Reason codes
+OSSLTEST_R_INIT_FAILED:100:init failed
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest_err.c b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest_err.c
new file mode 100644
index 0000000..920a13a
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest_err.c
@@ -0,0 +1,63 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/err.h>
+#include "e_ossltest_err.h"
+
+#ifndef OPENSSL_NO_ERR
+
+static ERR_STRING_DATA OSSLTEST_str_functs[] = {
+    {ERR_PACK(0, OSSLTEST_F_BIND_OSSLTEST, 0), "bind_ossltest"},
+    {ERR_PACK(0, OSSLTEST_F_OSSLTEST_AES128_INIT_KEY, 0), ""},
+    {0, NULL}
+};
+
+static ERR_STRING_DATA OSSLTEST_str_reasons[] = {
+    {ERR_PACK(0, 0, OSSLTEST_R_INIT_FAILED), "init failed"},
+    {0, NULL}
+};
+
+#endif
+
+static int lib_code = 0;
+static int error_loaded = 0;
+
+static int ERR_load_OSSLTEST_strings(void)
+{
+    if (lib_code == 0)
+        lib_code = ERR_get_next_error_library();
+
+    if (!error_loaded) {
+#ifndef OPENSSL_NO_ERR
+        ERR_load_strings(lib_code, OSSLTEST_str_functs);
+        ERR_load_strings(lib_code, OSSLTEST_str_reasons);
+#endif
+        error_loaded = 1;
+    }
+    return 1;
+}
+
+static void ERR_unload_OSSLTEST_strings(void)
+{
+    if (error_loaded) {
+#ifndef OPENSSL_NO_ERR
+        ERR_unload_strings(lib_code, OSSLTEST_str_functs);
+        ERR_unload_strings(lib_code, OSSLTEST_str_reasons);
+#endif
+        error_loaded = 0;
+    }
+}
+
+static void ERR_OSSLTEST_error(int function, int reason, char *file, int line)
+{
+    if (lib_code == 0)
+        lib_code = ERR_get_next_error_library();
+    ERR_PUT_error(lib_code, function, reason, file, line);
+}
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest_err.h b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest_err.h
new file mode 100644
index 0000000..8e6535b
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_ossltest_err.h
@@ -0,0 +1,28 @@
+/*
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_ENGINES_E_OSSLTEST_ERR_H
+# define OSSL_ENGINES_E_OSSLTEST_ERR_H
+
+# define OSSLTESTerr(f, r) ERR_OSSLTEST_error((f), (r), OPENSSL_FILE, OPENSSL_LINE)
+
+
+/*
+ * OSSLTEST function codes.
+ */
+# define OSSLTEST_F_BIND_OSSLTEST                         100
+# define OSSLTEST_F_OSSLTEST_AES128_INIT_KEY              101
+
+/*
+ * OSSLTEST reason codes.
+ */
+# define OSSLTEST_R_INIT_FAILED                           100
+
+#endif
diff --git a/ap/lib/libssl/openssl-1.1.1o/engines/e_padlock.c b/ap/lib/libssl/openssl-1.1.1o/engines/e_padlock.c
new file mode 100644
index 0000000..a82c07e
--- /dev/null
+++ b/ap/lib/libssl/openssl-1.1.1o/engines/e_padlock.c
@@ -0,0 +1,747 @@
+/*
+ * Copyright 2004-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/opensslconf.h>
+#include <openssl/crypto.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+#include <openssl/aes.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/modes.h>
+
+#ifndef OPENSSL_NO_HW
+# ifndef OPENSSL_NO_HW_PADLOCK
+
+/* Attempt to have a single source for both 0.9.7 and 0.9.8 :-) */
+#  if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#   ifndef OPENSSL_NO_DYNAMIC_ENGINE
+#    define DYNAMIC_ENGINE
+#   endif
+#  elif (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+#   ifdef ENGINE_DYNAMIC_SUPPORT
+#    define DYNAMIC_ENGINE
+#   endif
+#  else
+#   error "Only OpenSSL >= 0.9.7 is supported"
+#  endif
+
+/*
+ * VIA PadLock AES is available *ONLY* on some x86 CPUs. Not only that it
+ * doesn't exist elsewhere, but it even can't be compiled on other platforms!
+ */
+
+#  undef COMPILE_HW_PADLOCK
+#  if defined(PADLOCK_ASM)
+#   define COMPILE_HW_PADLOCK
+#   ifdef OPENSSL_NO_DYNAMIC_ENGINE
+static ENGINE *ENGINE_padlock(void);
+#   endif
+#  endif
+
+#  ifdef OPENSSL_NO_DYNAMIC_ENGINE
+void engine_load_padlock_int(void);
+void engine_load_padlock_int(void)
+{
+/* On non-x86 CPUs it just returns. */
+#   ifdef COMPILE_HW_PADLOCK
+    ENGINE *toadd = ENGINE_padlock();
+    if (!toadd)
+        return;
+    ENGINE_add(toadd);
+    ENGINE_free(toadd);
+    ERR_clear_error();
+#   endif
+}
+
+#  endif
+
+#  ifdef COMPILE_HW_PADLOCK
+
+/* Function for ENGINE detection and control */
+static int padlock_available(void);
+static int padlock_init(ENGINE *e);
+
+/* RNG Stuff */
+static RAND_METHOD padlock_rand;
+
+/* Cipher Stuff */
+static int padlock_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+                           const int **nids, int nid);
+
+/* Engine names */
+static const char *padlock_id = "padlock";
+static char padlock_name[100];
+
+/* Available features */
+static int padlock_use_ace = 0; /* Advanced Cryptography Engine */
+static int padlock_use_rng = 0; /* Random Number Generator */
+
+/* ===== Engine "management" functions ===== */
+
+/* Prepare the ENGINE structure for registration */
+static int padlock_bind_helper(ENGINE *e)
+{
+    /* Check available features */
+    padlock_available();
+
+    /*
+     * RNG is currently disabled for reasons discussed in commentary just
+     * before padlock_rand_bytes function.
+     */
+    padlock_use_rng = 0;
+
+    /* Generate a nice engine name with available features */
+    BIO_snprintf(padlock_name, sizeof(padlock_name),
+                 "VIA PadLock (%s, %s)",
+                 padlock_use_rng ? "RNG" : "no-RNG",
+                 padlock_use_ace ? "ACE" : "no-ACE");
+
+    /* Register everything or return with an error */
+    if (!ENGINE_set_id(e, padlock_id) ||
+        !ENGINE_set_name(e, padlock_name) ||
+        !ENGINE_set_init_function(e, padlock_init) ||
+        (padlock_use_ace && !ENGINE_set_ciphers(e, padlock_ciphers)) ||
+        (padlock_use_rng && !ENGINE_set_RAND(e, &padlock_rand))) {
+        return 0;
+    }
+
+    /* Everything looks good */
+    return 1;
+}
+
+#   ifdef OPENSSL_NO_DYNAMIC_ENGINE
+/* Constructor */
+static ENGINE *ENGINE_padlock(void)
+{
+    ENGINE *eng = ENGINE_new();
+
+    if (eng == NULL) {
+        return NULL;
+    }
+
+    if (!padlock_bind_helper(eng)) {
+        ENGINE_free(eng);
+        return NULL;
+    }
+
+    return eng;
+}
+#   endif
+
+/* Check availability of the engine */
+static int padlock_init(ENGINE *e)
+{
+    return (padlock_use_rng || padlock_use_ace);
+}
+
+/*
+ * This stuff is needed if this ENGINE is being compiled into a
+ * self-contained shared-library.
+ */
+#   ifndef OPENSSL_NO_DYNAMIC_ENGINE
+static int padlock_bind_fn(ENGINE *e, const char *id)
+{
+    if (id && (strcmp(id, padlock_id) != 0)) {
+        return 0;
+    }
+
+    if (!padlock_bind_helper(e)) {
+        return 0;
+    }
+
+    return 1;
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+IMPLEMENT_DYNAMIC_BIND_FN(padlock_bind_fn)
+#   endif                       /* !OPENSSL_NO_DYNAMIC_ENGINE */
+/* ===== Here comes the "real" engine ===== */
+
+/* Some AES-related constants */
+#   define AES_BLOCK_SIZE          16
+#   define AES_KEY_SIZE_128        16
+#   define AES_KEY_SIZE_192        24
+#   define AES_KEY_SIZE_256        32
+    /*
+     * Here we store the status information relevant to the current context.
+     */
+    /*
+     * BIG FAT WARNING: Inline assembler in PADLOCK_XCRYPT_ASM() depends on
+     * the order of items in this structure.  Don't blindly modify, reorder,
+     * etc!
+     */
+struct padlock_cipher_data {
+    unsigned char iv[AES_BLOCK_SIZE]; /* Initialization vector */
+    union {
+        unsigned int pad[4];
+        struct {
+            int rounds:4;
+            int dgst:1;         /* n/a in C3 */
+            int align:1;        /* n/a in C3 */
+            int ciphr:1;        /* n/a in C3 */
+            unsigned int keygen:1;
+            int interm:1;
+            unsigned int encdec:1;
+            int ksize:2;
+        } b;
+    } cword;                    /* Control word */
+    AES_KEY ks;                 /* Encryption key */
+};
+
+/* Interface to assembler module */
+unsigned int padlock_capability(void);
+void padlock_key_bswap(AES_KEY *key);
+void padlock_verify_context(struct padlock_cipher_data *ctx);
+void padlock_reload_key(void);
+void padlock_aes_block(void *out, const void *inp,
+                       struct padlock_cipher_data *ctx);
+int padlock_ecb_encrypt(void *out, const void *inp,
+                        struct padlock_cipher_data *ctx, size_t len);
+int padlock_cbc_encrypt(void *out, const void *inp,
+                        struct padlock_cipher_data *ctx, size_t len);
+int padlock_cfb_encrypt(void *out, const void *inp,
+                        struct padlock_cipher_data *ctx, size_t len);
+int padlock_ofb_encrypt(void *out, const void *inp,
+                        struct padlock_cipher_data *ctx, size_t len);
+int padlock_ctr32_encrypt(void *out, const void *inp,
+                          struct padlock_cipher_data *ctx, size_t len);
+int padlock_xstore(void *out, int edx);
+void padlock_sha1_oneshot(void *ctx, const void *inp, size_t len);
+void padlock_sha1(void *ctx, const void *inp, size_t len);
+void padlock_sha256_oneshot(void *ctx, const void *inp, size_t len);
+void padlock_sha256(void *ctx, const void *inp, size_t len);
+
+/*
+ * Load supported features of the CPU to see if the PadLock is available.
+ */
+static int padlock_available(void)
+{
+    unsigned int edx = padlock_capability();
+
+    /* Fill up some flags */
+    padlock_use_ace = ((edx & (0x3 << 6)) == (0x3 << 6));
+    padlock_use_rng = ((edx & (0x3 << 2)) == (0x3 << 2));
+
+    return padlock_use_ace + padlock_use_rng;
+}
+
+/* ===== AES encryption/decryption ===== */
+
+#   if defined(NID_aes_128_cfb128) && ! defined (NID_aes_128_cfb)
+#    define NID_aes_128_cfb NID_aes_128_cfb128
+#   endif
+
+#   if defined(NID_aes_128_ofb128) && ! defined (NID_aes_128_ofb)
+#    define NID_aes_128_ofb NID_aes_128_ofb128
+#   endif
+
+#   if defined(NID_aes_192_cfb128) && ! defined (NID_aes_192_cfb)
+#    define NID_aes_192_cfb NID_aes_192_cfb128
+#   endif
+
+#   if defined(NID_aes_192_ofb128) && ! defined (NID_aes_192_ofb)
+#    define NID_aes_192_ofb NID_aes_192_ofb128
+#   endif
+
+#   if defined(NID_aes_256_cfb128) && ! defined (NID_aes_256_cfb)
+#    define NID_aes_256_cfb NID_aes_256_cfb128
+#   endif
+
+#   if defined(NID_aes_256_ofb128) && ! defined (NID_aes_256_ofb)
+#    define NID_aes_256_ofb NID_aes_256_ofb128
+#   endif
+
+/* List of supported ciphers. */
+static const int padlock_cipher_nids[] = {
+    NID_aes_128_ecb,
+    NID_aes_128_cbc,
+    NID_aes_128_cfb,
+    NID_aes_128_ofb,
+    NID_aes_128_ctr,
+
+    NID_aes_192_ecb,
+    NID_aes_192_cbc,
+    NID_aes_192_cfb,
+    NID_aes_192_ofb,
+    NID_aes_192_ctr,
+
+    NID_aes_256_ecb,
+    NID_aes_256_cbc,
+    NID_aes_256_cfb,
+    NID_aes_256_ofb,
+    NID_aes_256_ctr
+};
+
+static int padlock_cipher_nids_num = (sizeof(padlock_cipher_nids) /
+                                      sizeof(padlock_cipher_nids[0]));
+
+/* Function prototypes ... */
+static int padlock_aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                                const unsigned char *iv, int enc);
+
+#   define NEAREST_ALIGNED(ptr) ( (unsigned char *)(ptr) +         \
+        ( (0x10 - ((size_t)(ptr) & 0x0F)) & 0x0F )      )
+#   define ALIGNED_CIPHER_DATA(ctx) ((struct padlock_cipher_data *)\
+        NEAREST_ALIGNED(EVP_CIPHER_CTX_get_cipher_data(ctx)))
+
+static int
+padlock_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
+                   const unsigned char *in_arg, size_t nbytes)
+{
+    return padlock_ecb_encrypt(out_arg, in_arg,
+                               ALIGNED_CIPHER_DATA(ctx), nbytes);
+}
+
+static int
+padlock_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
+                   const unsigned char *in_arg, size_t nbytes)
+{
+    struct padlock_cipher_data *cdata = ALIGNED_CIPHER_DATA(ctx);
+    int ret;
+
+    memcpy(cdata->iv, EVP_CIPHER_CTX_iv(ctx), AES_BLOCK_SIZE);
+    if ((ret = padlock_cbc_encrypt(out_arg, in_arg, cdata, nbytes)))
+        memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), cdata->iv, AES_BLOCK_SIZE);
+    return ret;
+}
+
+static int
+padlock_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
+                   const unsigned char *in_arg, size_t nbytes)
+{
+    struct padlock_cipher_data *cdata = ALIGNED_CIPHER_DATA(ctx);
+    size_t chunk;
+
+    if ((chunk = EVP_CIPHER_CTX_num(ctx))) {   /* borrow chunk variable */
+        unsigned char *ivp = EVP_CIPHER_CTX_iv_noconst(ctx);
+
+        if (chunk >= AES_BLOCK_SIZE)
+            return 0;           /* bogus value */
+
+        if (EVP_CIPHER_CTX_encrypting(ctx))
+            while (chunk < AES_BLOCK_SIZE && nbytes != 0) {
+                ivp[chunk] = *(out_arg++) = *(in_arg++) ^ ivp[chunk];
+                chunk++, nbytes--;
+        } else
+            while (chunk < AES_BLOCK_SIZE && nbytes != 0) {
+                unsigned char c = *(in_arg++);
+                *(out_arg++) = c ^ ivp[chunk];
+                ivp[chunk++] = c, nbytes--;
+            }
+
+        EVP_CIPHER_CTX_set_num(ctx, chunk % AES_BLOCK_SIZE);
+    }
+
+    if (nbytes == 0)
+        return 1;
+
+    memcpy(cdata->iv, EVP_CIPHER_CTX_iv(ctx), AES_BLOCK_SIZE);
+
+    if ((chunk = nbytes & ~(AES_BLOCK_SIZE - 1))) {
+        if (!padlock_cfb_encrypt(out_arg, in_arg, cdata, chunk))
+            return 0;
+        nbytes -= chunk;
+    }
+
+    if (nbytes) {
+        unsigned char *ivp = cdata->iv;
+
+        out_arg += chunk;
+        in_arg += chunk;
+        EVP_CIPHER_CTX_set_num(ctx, nbytes);
+        if (cdata->cword.b.encdec) {
+            cdata->cword.b.encdec = 0;
+            padlock_reload_key();
+            padlock_aes_block(ivp, ivp, cdata);
+            cdata->cword.b.encdec = 1;
+            padlock_reload_key();
+            while (nbytes) {
+                unsigned char c = *(in_arg++);
+                *(out_arg++) = c ^ *ivp;
+                *(ivp++) = c, nbytes--;
+            }
+        } else {
+            padlock_reload_key();
+            padlock_aes_block(ivp, ivp, cdata);
+            padlock_reload_key();
+            while (nbytes) {
+                *ivp = *(out_arg++) = *(in_arg++) ^ *ivp;
+                ivp++, nbytes--;
+            }
+        }
+    }
+
+    memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), cdata->iv, AES_BLOCK_SIZE);
+
+    return 1;
+}
+
+static int
+padlock_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
+                   const unsigned char *in_arg, size_t nbytes)
+{
+    struct padlock_cipher_data *cdata = ALIGNED_CIPHER_DATA(ctx);
+    size_t chunk;
+
+    /*
+     * ctx->num is maintained in byte-oriented modes, such as CFB and OFB...
+     */
+    if ((chunk = EVP_CIPHER_CTX_num(ctx))) {   /* borrow chunk variable */
+        unsigned char *ivp = EVP_CIPHER_CTX_iv_noconst(ctx);
+
+        if (chunk >= AES_BLOCK_SIZE)
+            return 0;           /* bogus value */
+
+        while (chunk < AES_BLOCK_SIZE && nbytes != 0) {
+            *(out_arg++) = *(in_arg++) ^ ivp[chunk];
+            chunk++, nbytes--;
+        }
+
+        EVP_CIPHER_CTX_set_num(ctx, chunk % AES_BLOCK_SIZE);
+    }
+
+    if (nbytes == 0)
+        return 1;
+
+    memcpy(cdata->iv, EVP_CIPHER_CTX_iv(ctx), AES_BLOCK_SIZE);
+
+    if ((chunk = nbytes & ~(AES_BLOCK_SIZE - 1))) {
+        if (!padlock_ofb_encrypt(out_arg, in_arg, cdata, chunk))
+            return 0;
+        nbytes -= chunk;
+    }
+
+    if (nbytes) {
+        unsigned char *ivp = cdata->iv;
+
+        out_arg += chunk;
+        in_arg += chunk;
+        EVP_CIPHER_CTX_set_num(ctx, nbytes);
+        padlock_reload_key();   /* empirically found */
+        padlock_aes_block(ivp, ivp, cdata);
+        padlock_reload_key();   /* empirically found */
+        while (nbytes) {
+            *(out_arg++) = *(in_arg++) ^ *ivp;
+            ivp++, nbytes--;
+        }
+    }
+
+    memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), cdata->iv, AES_BLOCK_SIZE);
+
+    return 1;
+}
+
+static void padlock_ctr32_encrypt_glue(const unsigned char *in,
+                                       unsigned char *out, size_t blocks,
+                                       struct padlock_cipher_data *ctx,
+                                       const unsigned char *ivec)
+{
+    memcpy(ctx->iv, ivec, AES_BLOCK_SIZE);
+    padlock_ctr32_encrypt(out, in, ctx, AES_BLOCK_SIZE * blocks);
+}
+
+static int
+padlock_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
+                   const unsigned char *in_arg, size_t nbytes)
+{
+    struct padlock_cipher_data *cdata = ALIGNED_CIPHER_DATA(ctx);
+    unsigned int num = EVP_CIPHER_CTX_num(ctx);
+
+    CRYPTO_ctr128_encrypt_ctr32(in_arg, out_arg, nbytes,
+                                cdata, EVP_CIPHER_CTX_iv_noconst(ctx),
+                                EVP_CIPHER_CTX_buf_noconst(ctx), &num,
+                                (ctr128_f) padlock_ctr32_encrypt_glue);
+
+    EVP_CIPHER_CTX_set_num(ctx, (size_t)num);
+    return 1;
+}
+
+#   define EVP_CIPHER_block_size_ECB       AES_BLOCK_SIZE
+#   define EVP_CIPHER_block_size_CBC       AES_BLOCK_SIZE
+#   define EVP_CIPHER_block_size_OFB       1
+#   define EVP_CIPHER_block_size_CFB       1
+#   define EVP_CIPHER_block_size_CTR       1
+
+/*
+ * Declaring so many ciphers by hand would be a pain. Instead introduce a bit
+ * of preprocessor magic :-)
+ */
+#   define DECLARE_AES_EVP(ksize,lmode,umode)      \
+static EVP_CIPHER *_hidden_aes_##ksize##_##lmode = NULL; \
+static const EVP_CIPHER *padlock_aes_##ksize##_##lmode(void) \
+{                                                                       \
+    if (_hidden_aes_##ksize##_##lmode == NULL                           \
+        && ((_hidden_aes_##ksize##_##lmode =                            \
+             EVP_CIPHER_meth_new(NID_aes_##ksize##_##lmode,             \
+                                 EVP_CIPHER_block_size_##umode,         \
+                                 AES_KEY_SIZE_##ksize)) == NULL         \
+            || !EVP_CIPHER_meth_set_iv_length(_hidden_aes_##ksize##_##lmode, \
+                                              AES_BLOCK_SIZE)           \
+            || !EVP_CIPHER_meth_set_flags(_hidden_aes_##ksize##_##lmode, \
+                                          0 | EVP_CIPH_##umode##_MODE)  \
+            || !EVP_CIPHER_meth_set_init(_hidden_aes_##ksize##_##lmode, \
+                                         padlock_aes_init_key)          \
+            || !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_##ksize##_##lmode, \
+                                              padlock_##lmode##_cipher) \
+            || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_##ksize##_##lmode, \
+                                                  sizeof(struct padlock_cipher_data) + 16) \
+            || !EVP_CIPHER_meth_set_set_asn1_params(_hidden_aes_##ksize##_##lmode, \
+                                                    EVP_CIPHER_set_asn1_iv) \
+            || !EVP_CIPHER_meth_set_get_asn1_params(_hidden_aes_##ksize##_##lmode, \
+                                                    EVP_CIPHER_get_asn1_iv))) { \
+        EVP_CIPHER_meth_free(_hidden_aes_##ksize##_##lmode);            \
+        _hidden_aes_##ksize##_##lmode = NULL;                           \
+    }                                                                   \
+    return _hidden_aes_##ksize##_##lmode;                               \
+}
+
+DECLARE_AES_EVP(128, ecb, ECB)
+DECLARE_AES_EVP(128, cbc, CBC)
+DECLARE_AES_EVP(128, cfb, CFB)
+DECLARE_AES_EVP(128, ofb, OFB)
+DECLARE_AES_EVP(128, ctr, CTR)
+
+DECLARE_AES_EVP(192, ecb, ECB)
+DECLARE_AES_EVP(192, cbc, CBC)
+DECLARE_AES_EVP(192, cfb, CFB)
+DECLARE_AES_EVP(192, ofb, OFB)
+DECLARE_AES_EVP(192, ctr, CTR)
+
+DECLARE_AES_EVP(256, ecb, ECB)
+DECLARE_AES_EVP(256, cbc, CBC)
+DECLARE_AES_EVP(256, cfb, CFB)
+DECLARE_AES_EVP(256, ofb, OFB)
+DECLARE_AES_EVP(256, ctr, CTR)
+
+static int
+padlock_ciphers(ENGINE *e, const EVP_CIPHER **cipher, const int **nids,
+                int nid)
+{
+    /* No specific cipher => return a list of supported nids ... */
+    if (!cipher) {
+        *nids = padlock_cipher_nids;
+        return padlock_cipher_nids_num;
+    }
+
+    /* ... or the requested "cipher" otherwise */
+    switch (nid) {
+    case NID_aes_128_ecb:
+        *cipher = padlock_aes_128_ecb();
+        break;
+    case NID_aes_128_cbc:
+        *cipher = padlock_aes_128_cbc();
+        break;
+    case NID_aes_128_cfb:
+        *cipher = padlock_aes_128_cfb();
+        break;
+    case NID_aes_128_ofb:
+        *cipher = padlock_aes_128_ofb();
+        break;
+    case NID_aes_128_ctr:
+        *cipher = padlock_aes_128_ctr();
+        break;
+
+    case NID_aes_192_ecb:
+        *cipher = padlock_aes_192_ecb();
+        break;
+    case NID_aes_192_cbc:
+        *cipher = padlock_aes_192_cbc();
+        break;
+    case NID_aes_192_cfb:
+        *cipher = padlock_aes_192_cfb();
+        break;
+    case NID_aes_192_ofb:
+        *cipher = padlock_aes_192_ofb();
+        break;
+    case NID_aes_192_ctr:
+        *cipher = padlock_aes_192_ctr();
+        break;
+
+    case NID_aes_256_ecb:
+        *cipher = padlock_aes_256_ecb();
+        break;
+    case NID_aes_256_cbc:
+        *cipher = padlock_aes_256_cbc();
+        break;
+    case NID_aes_256_cfb:
+        *cipher = padlock_aes_256_cfb();
+        break;
+    case NID_aes_256_ofb:
+        *cipher = padlock_aes_256_ofb();
+        break;
+    case NID_aes_256_ctr:
+        *cipher = padlock_aes_256_ctr();
+        break;
+
+    default:
+        /* Sorry, we don't support this NID */
+        *cipher = NULL;
+        return 0;
+    }
+
+    return 1;
+}
+
+/* Prepare the encryption key for PadLock usage */
+static int
+padlock_aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                     const unsigned char *iv, int enc)
+{
+    struct padlock_cipher_data *cdata;
+    int key_len = EVP_CIPHER_CTX_key_length(ctx) * 8;
+    unsigned long mode = EVP_CIPHER_CTX_mode(ctx);
+
+    if (key == NULL)
+        return 0;               /* ERROR */
+
+    cdata = ALIGNED_CIPHER_DATA(ctx);
+    memset(cdata, 0, sizeof(*cdata));
+
+    /* Prepare Control word. */
+    if (mode == EVP_CIPH_OFB_MODE || mode == EVP_CIPH_CTR_MODE)
+        cdata->cword.b.encdec = 0;
+    else
+        cdata->cword.b.encdec = (EVP_CIPHER_CTX_encrypting(ctx) == 0);
+    cdata->cword.b.rounds = 10 + (key_len - 128) / 32;
+    cdata->cword.b.ksize = (key_len - 128) / 64;
+
+    switch (key_len) {
+    case 128:
+        /*
+         * PadLock can generate an extended key for AES128 in hardware
+         */
+        memcpy(cdata->ks.rd_key, key, AES_KEY_SIZE_128);
+        cdata->cword.b.keygen = 0;
+        break;
+
+    case 192:
+    case 256:
+        /*
+         * Generate an extended AES key in software. Needed for AES192/AES256
+         */
+        /*
+         * Well, the above applies to Stepping 8 CPUs and is listed as
+         * hardware errata. They most likely will fix it at some point and
+         * then a check for stepping would be due here.
+         */
+        if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
+            && !enc)
+            AES_set_decrypt_key(key, key_len, &cdata->ks);
+        else
+            AES_set_encrypt_key(key, key_len, &cdata->ks);
+#   ifndef AES_ASM
+        /*
+         * OpenSSL C functions use byte-swapped extended key.
+         */
+        padlock_key_bswap(&cdata->ks);
+#   endif
+        cdata->cword.b.keygen = 1;
+        break;
+
+    default:
+        /* ERROR */
+        return 0;
+    }
+
+    /*
+     * This is done to cover for cases when user reuses the
+     * context for new key. The catch is that if we don't do
+     * this, padlock_eas_cipher might proceed with old key...
+     */
+    padlock_reload_key();
+
+    return 1;
+}
+
+/* ===== Random Number Generator ===== */
+/*
+ * This code is not engaged. The reason is that it does not comply
+ * with recommendations for VIA RNG usage for secure applications
+ * (posted at http://www.via.com.tw/en/viac3/c3.jsp) nor does it
+ * provide meaningful error control...
+ */
+/*
+ * Wrapper that provides an interface between the API and the raw PadLock
+ * RNG
+ */
+static int padlock_rand_bytes(unsigned char *output, int count)
+{
+    unsigned int eax, buf;
+
+    while (count >= 8) {
+        eax = padlock_xstore(output, 0);
+        if (!(eax & (1 << 6)))
+            return 0;           /* RNG disabled */
+        /* this ---vv--- covers DC bias, Raw Bits and String Filter */
+        if (eax & (0x1F << 10))
+            return 0;
+        if ((eax & 0x1F) == 0)
+            continue;           /* no data, retry... */
+        if ((eax & 0x1F) != 8)
+            return 0;           /* fatal failure...  */
+        output += 8;
+        count -= 8;
+    }
+    while (count > 0) {
+        eax = padlock_xstore(&buf, 3);
+        if (!(eax & (1 << 6)))
+            return 0;           /* RNG disabled */
+        /* this ---vv--- covers DC bias, Raw Bits and String Filter */
+        if (eax & (0x1F << 10))
+            return 0;
+        if ((eax & 0x1F) == 0)
+            continue;           /* no data, retry... */
+        if ((eax & 0x1F) != 1)
+            return 0;           /* fatal failure...  */
+        *output++ = (unsigned char)buf;
+        count--;
+    }
+    OPENSSL_cleanse(&buf, sizeof(buf));
+
+    return 1;
+}
+
+/* Dummy but necessary function */
+static int padlock_rand_status(void)
+{
+    return 1;
+}
+
+/* Prepare structure for registration */
+static RAND_METHOD padlock_rand = {
+    NULL,                       /* seed */
+    padlock_rand_bytes,         /* bytes */
+    NULL,                       /* cleanup */
+    NULL,                       /* add */
+    padlock_rand_bytes,         /* pseudorand */
+    padlock_rand_status,        /* rand status */
+};
+
+#  endif                        /* COMPILE_HW_PADLOCK */
+# endif                         /* !OPENSSL_NO_HW_PADLOCK */
+#endif                          /* !OPENSSL_NO_HW */
+
+#if defined(OPENSSL_NO_HW) || defined(OPENSSL_NO_HW_PADLOCK) \
+        || !defined(COMPILE_HW_PADLOCK)
+# ifndef OPENSSL_NO_DYNAMIC_ENGINE
+OPENSSL_EXPORT
+    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns);
+OPENSSL_EXPORT
+    int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns)
+{
+    return 0;
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+# endif
+#endif