aws / aws-encryption-sdk-dafny

AWS Encryption SDK for Dafny
Apache License 2.0
34 stars 20 forks source link

BouncyCastle dependency breaks AoT #613

Closed joeclauson closed 9 months ago

joeclauson commented 1 year ago

During a lambda execution, an error was thrown when utilizing this SDK. It appears the current BouncyCastle dependency does not support trimming or AoT.

Our C# lambdas work flawlessly using JIT, so I know the code is good. We are using these Lambdas for Cognito and that has a five second time-limit that we're brushing against or surpassing at times, so we'd like to use AoT.

Please let me know if there is any more information I can provide.

Thanks!

Here is the full error:

AWS.EncryptionSDK.AwsEncryptionSdkException: System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
---> System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
---> System.NotSupportedException: 'Org.BouncyCastle.Security.DigestUtilities+DigestAlgorithm[]' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
at System.Reflection.Runtime.General.TypeUnifier.WithVerifiedTypeHandle(RuntimeArrayTypeInfo, RuntimeTypeInfo) + 0x55
at System.Array.InternalCreate(RuntimeType, Int32, Int32*, Int32*) + 0x60
at System.Array.CreateInstance(Type elementType, Int32 length) + 0x48
at System.RuntimeType.GetEnumValues() + 0x92
at Org.BouncyCastle.Utilities.Enums.GetArbitraryValue(Type enumType) + 0xd
at Org.BouncyCastle.Security.DigestUtilities..cctor() + 0x8c
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xb9
--- End of inner exception stack trace ---
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x153
at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnNonGCStaticBase(StaticClassConstructionContext*, IntPtr) + 0x9
at Org.BouncyCastle.Security.DigestUtilities.GetDigest(String algorithm) + 0x15
at Org.BouncyCastle.Security.SecureRandom.CreatePrng(String digestName, Boolean autoSeed) + 0x13
at Org.BouncyCastle.Math.BigInteger..cctor() + 0xdfd
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xb9
--- End of inner exception stack trace ---
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x153
at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnNonGCStaticBase(StaticClassConstructionContext*, IntPtr) + 0x9
at Org.BouncyCastle.Asn1.Sec.SecNamedCurves.Secp384r1Holder.CreateParameters() + 0x50
at Org.BouncyCastle.Asn1.X9.X9ECParametersHolder.get_Parameters() + 0x2f
at Org.BouncyCastle.Asn1.X9.ECNamedCurveTable.GetByName(String name) + 0x48
at Signature.ECDSA.Verify(_IECDSAParams x, ISequence`1 vk, ISequence`1 msg, ISequence`1 sig) + 0x51
at AWS.EncryptionSDK.AwsEncryptionSdk._Decrypt(DecryptInput input) + 0x6d
at Lambda.Cognito.Clients.KmsClient.DecryptCipherText(Byte[] encryptedCode) + 0x72
at Lambda.Cognito.Services.HttpClientService.<PostRequest>d__3.MoveNext() + 0x59
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xc2
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x44
at Lambda.Cognito.Handlers.CognitoPinpointEmailHandler.<Run>d__2.MoveNext() + 0xe3
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xc2
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x44
at Lambda.Cognito.CognitoHandler.<Run>d__1.MoveNext() + 0x8a2
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xc2
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x44
at Lambda.Cognito.Function.<FunctionHandler>d__1.MoveNext() + 0x33b
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xc2
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x44
at Amazon.Lambda.RuntimeSupport.HandlerWrapper.<>c__DisplayClass19_0.<<GetHandlerWrapper>b__0>d.MoveNext() + 0xc1
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x1c
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xc2
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x44
at Amazon.Lambda.RuntimeSupport.LambdaBootstrap.<InvokeOnceAsync>d__17.MoveNext() + 0x1f7

The code, although not an exact copy, looks like this:

var encryptionSdk = AwsEncryptionSdkFactory.CreateAwsEncryptionSdk(new AwsEncryptionSdkConfig
{
  CommitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT
});

var materialProviders =
  AwsCryptographicMaterialProvidersFactory.CreateDefaultAwsCryptographicMaterialProviders();

var keyArn = "MY ARN"; // Comes from config

// Instantiate the keyring input object
var kmsKeyringInput = new CreateAwsKmsKeyringInput
{
  KmsClient = new AmazonKeyManagementServiceClient(),
  KmsKeyId = keyArn
};

var keyring = materialProviders.CreateAwsKmsKeyring(kmsKeyringInput);

// encryptedCode comes from Lambda Request
var encryptedCodeStream = new MemoryStream(encryptedCode);
var decryptInput = new DecryptInput {
  Ciphertext = encryptedCodeStream,
  Keyring = keyring
};

var decryptOutput = encryptionSdk.Decrypt(decryptInput);
decryptOutput.Plaintext.Position = 0;
var reader = new StreamReader(decryptOutput.Plaintext);
var plainTextCode = reader.ReadToEnd();
texastony commented 9 months ago

@joeclauson

I do not think our BouncyCastle dependency supports AoT. My understanding is that AoT was an experimental feature or at least limited in .NET 7.

The original AWS Encryption SDK for .NET (ESDK-.NET) was vended targeting .NET 6, with efforts at being backwards compatible to early .NET Frameworks.

Since you cut this issue, we have released the ESDK-.NET v4, but it still targets .NET 6.

V4 switched from PortableBouncyCastle to BouncyCastle.

You could try V4.

But we are not, at this time, committing to AoT support.

Much Obliged, AWS Crypto Tools