/* * Copyright 2019–present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; namespace MongoDB.Libmongocrypt { /// /// A encryption or decryption session. It may not be reused. /// /// /// public class CryptContext : IDisposable, IStatus { /// /// States of the CryptContext state machine /// public enum StateCode { /// /// LibMongoCrypt hit an error /// MONGOCRYPT_CTX_ERROR = 0, /// /// LibMongoCrypt wants the collection information by running a OP_MSG command against the users' mongod. /// MONGOCRYPT_CTX_NEED_MONGO_COLLINFO = 1, /// /// LibMongoCrypt wants a command to be run against mongocryptd. /// MONGOCRYPT_CTX_NEED_MONGO_MARKINGS = 2, /// /// LibMongoCrypt wants a command to be run against mongod key vault. /// MONGOCRYPT_CTX_NEED_MONGO_KEYS = 3, /// /// LibMongoCrypt wants a request sent to KMS. /// MONGOCRYPT_CTX_NEED_KMS = 4, /// /// LibMongoCrypt is ready to do encryption, call Finish(). /// MONGOCRYPT_CTX_READY = 5, /// /// LibMongoCrypt is complete. /// MONGOCRYPT_CTX_DONE = 6, /// /// LibMongoCrypt requires new credentials. /// MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS = 7 } private ContextSafeHandle _handle; private Status _status; internal CryptContext(ContextSafeHandle handle) { _handle = handle; _status = new Status(); } /// /// Gets the state. /// /// /// The state. /// public StateCode State { get { return Library.mongocrypt_ctx_state(_handle); } } /// /// Gets a value indicating whether this instance is done. /// /// /// true if this instance is done; otherwise, false. /// public bool IsDone { get { return State == StateCode.MONGOCRYPT_CTX_DONE; } } /// /// Gets the operation. /// /// Binary payload to send to either KMS, mongod, or mongocryptd public Binary GetOperation() { Binary binary = new Binary(); Check(Library.mongocrypt_ctx_mongo_op(_handle, binary.Handle)); return binary; } /// /// Feeds the result from running a remote operation back to the libmongocrypt. /// /// The buffer. public void Feed(byte[] buffer) { unsafe { fixed (byte* p = buffer) { IntPtr ptr = (IntPtr)p; using (PinnedBinary pinned = new PinnedBinary(ptr, (uint)buffer.Length)) { Check(Library.mongocrypt_ctx_mongo_feed(_handle, pinned.Handle)); } } } } /// /// Signal the feeding is done. /// public void MarkDone() { Check(Library.mongocrypt_ctx_mongo_done(_handle)); } /// /// Finalizes for encryption. /// /// The encrypted or decrypted result. public Binary FinalizeForEncryption() { Binary binary = new Binary(); Check(Library.mongocrypt_ctx_finalize(_handle, binary.Handle)); return binary; } /// /// Gets a collection of KMS message requests to make /// /// Collection of KMS Messages public KmsRequestCollection GetKmsMessageRequests() { var requests = new List(); for (IntPtr request = Library.mongocrypt_ctx_next_kms_ctx(_handle); request != IntPtr.Zero; request = Library.mongocrypt_ctx_next_kms_ctx(_handle)) { requests.Add(new KmsRequest(request)); } return new KmsRequestCollection(requests, this); } public void SetCredentials(byte[] credentials) { PinnedBinary.RunAsPinnedBinary(_handle, credentials, _status, (h, b) => Library.mongocrypt_ctx_provide_kms_providers(h, b)); } void IStatus.Check(Status status) { Library.mongocrypt_ctx_status(_handle, status.Handle); } #region IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { // Adapted from: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.safehandle?view=netcore-3.0 if (_handle != null && !_handle.IsInvalid) { // Free the handle _handle.Dispose(); } } #endregion internal void MarkKmsDone() { Check(Library.mongocrypt_ctx_kms_done(_handle)); } private void Check(bool success) { if (!success) { _status.Check(this); } } } }