// // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb". // private static unsafe CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *EncodeKeyTransRecipientInfo(CmsRecipient recipient, HeapBlockRetainer hb) { // "recipient" is a deep-cloned CmsRecipient object whose lifetime this class controls. Because of this, we can pull out the CERT_CONTEXT* and CERT_INFO* pointers // and embed pointers to them in the memory block we return. Yes, this code is scary. // // (The use of SafeCertContextHandle here is about using a consistent pattern to get the CERT_CONTEXT (rather than the ugly (CERT_CONTEXT*)(recipient.Certificate.Handle) pattern.) // It's not about keeping the context alive.) using (SafeCertContextHandle hCertContext = recipient.Certificate.CreateCertContextHandle()) { CERT_CONTEXT *pCertContext = hCertContext.DangerousGetCertContext(); CERT_INFO * pCertInfo = pCertContext->pCertInfo; CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *pEncodeInfo = (CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *)(hb.Alloc(sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO))); pEncodeInfo->cbSize = sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO); CRYPT_ALGORITHM_IDENTIFIER algId = pCertInfo->SubjectPublicKeyInfo.Algorithm; pEncodeInfo->KeyEncryptionAlgorithm = algId; pEncodeInfo->pvKeyEncryptionAuxInfo = IntPtr.Zero; pEncodeInfo->hCryptProv = IntPtr.Zero; pEncodeInfo->RecipientPublicKey = pCertInfo->SubjectPublicKeyInfo.PublicKey; pEncodeInfo->RecipientId = EncodeRecipientId(recipient, hCertContext, pCertContext, pCertInfo, hb); return(pEncodeInfo); } }
private Exception TryDecryptAgree(KeyAgreeRecipientInfo keyAgreeRecipientInfo, SafeProvOrNCryptKeyHandle hKey, CryptKeySpec keySpec, X509Certificate2Collection originatorCerts, X509Certificate2Collection extraStore) { unsafe { KeyAgreeRecipientInfoPalWindows pal = (KeyAgreeRecipientInfoPalWindows)(keyAgreeRecipientInfo.Pal); return(pal.WithCmsgCmsRecipientInfo <Exception>( delegate(CMSG_KEY_AGREE_RECIPIENT_INFO * pKeyAgreeRecipientInfo) { CMSG_CTRL_KEY_AGREE_DECRYPT_PARA decryptPara = default(CMSG_CTRL_KEY_AGREE_DECRYPT_PARA); decryptPara.cbSize = Marshal.SizeOf <CMSG_CTRL_KEY_AGREE_DECRYPT_PARA>(); decryptPara.hProv = hKey; decryptPara.dwKeySpec = keySpec; decryptPara.pKeyAgree = pKeyAgreeRecipientInfo; decryptPara.dwRecipientIndex = pal.Index; decryptPara.dwRecipientEncryptedKeyIndex = pal.SubIndex; CMsgKeyAgreeOriginatorChoice originatorChoice = pKeyAgreeRecipientInfo->dwOriginatorChoice; switch (originatorChoice) { case CMsgKeyAgreeOriginatorChoice.CMSG_KEY_AGREE_ORIGINATOR_CERT: { X509Certificate2Collection candidateCerts = new X509Certificate2Collection(); candidateCerts.AddRange(Helpers.GetStoreCertificates(StoreName.AddressBook, StoreLocation.CurrentUser, openExistingOnly: true)); candidateCerts.AddRange(Helpers.GetStoreCertificates(StoreName.AddressBook, StoreLocation.LocalMachine, openExistingOnly: true)); candidateCerts.AddRange(originatorCerts); candidateCerts.AddRange(extraStore); SubjectIdentifier originatorId = pKeyAgreeRecipientInfo->OriginatorCertId.ToSubjectIdentifier(); using (X509Certificate2 originatorCert = candidateCerts.TryFindMatchingCertificate(originatorId)) { if (originatorCert == null) { return ErrorCode.CRYPT_E_NOT_FOUND.ToCryptographicException(); } using (SafeCertContextHandle hCertContext = originatorCert.CreateCertContextHandle()) { CERT_CONTEXT *pOriginatorCertContext = hCertContext.DangerousGetCertContext(); decryptPara.OriginatorPublicKey = pOriginatorCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey; // Do not factor this call out of the switch statement as leaving this "using" block will free up // native memory that decryptPara points to. return TryExecuteDecryptAgree(ref decryptPara); } } } case CMsgKeyAgreeOriginatorChoice.CMSG_KEY_AGREE_ORIGINATOR_PUBLIC_KEY: { decryptPara.OriginatorPublicKey = pKeyAgreeRecipientInfo->OriginatorPublicKeyInfo.PublicKey; return TryExecuteDecryptAgree(ref decryptPara); } default: return new CryptographicException(SR.Format(SR.Cryptography_Cms_Invalid_Originator_Identifier_Choice, originatorChoice)); } })); } }
// // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb". // private static unsafe CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO *EncodeKeyAgreeRecipientInfo(CmsRecipient recipient, AlgorithmIdentifier contentEncryptionAlgorithm, HeapBlockRetainer hb) { // "recipient" is a deep-cloned CmsRecipient object whose lifetime this class controls. Because of this, we can pull out the CERT_CONTEXT* and CERT_INFO* pointers without // bringing in all the SafeCertContextHandle machinery, and embed pointers to them in the memory block we return. Yes, this code is scary. using (SafeCertContextHandle hCertContext = recipient.Certificate.CreateCertContextHandle()) { CERT_CONTEXT *pCertContext = hCertContext.DangerousGetCertContext(); CERT_INFO * pCertInfo = pCertContext->pCertInfo; CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO *pEncodeInfo = (CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO *)(hb.Alloc(sizeof(CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO))); pEncodeInfo->cbSize = sizeof(CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO); pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.Esdh); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = 0; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = IntPtr.Zero; pEncodeInfo->pvKeyEncryptionAuxInfo = null; string oidValue; AlgId algId = contentEncryptionAlgorithm.Oid.Value.ToAlgId(); if (algId == AlgId.CALG_RC2) { oidValue = Oids.CmsRc2Wrap; } else { oidValue = Oids.Cms3DesWrap; } pEncodeInfo->KeyWrapAlgorithm.pszObjId = hb.AllocAsciiString(oidValue); pEncodeInfo->KeyWrapAlgorithm.Parameters.cbData = 0; pEncodeInfo->KeyWrapAlgorithm.Parameters.pbData = IntPtr.Zero; pEncodeInfo->pvKeyWrapAuxInfo = GenerateEncryptionAuxInfoIfNeeded(contentEncryptionAlgorithm, hb); pEncodeInfo->hCryptProv = IntPtr.Zero; pEncodeInfo->dwKeySpec = 0; pEncodeInfo->dwKeyChoice = CmsKeyAgreeKeyChoice.CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE; pEncodeInfo->pEphemeralAlgorithm = (CRYPT_ALGORITHM_IDENTIFIER *)(hb.Alloc(sizeof(CRYPT_ALGORITHM_IDENTIFIER))); *(pEncodeInfo->pEphemeralAlgorithm) = pCertInfo->SubjectPublicKeyInfo.Algorithm; pEncodeInfo->UserKeyingMaterial.cbData = 0; pEncodeInfo->UserKeyingMaterial.pbData = IntPtr.Zero; CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO *pEncryptedKey = (CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO *)(hb.Alloc(sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO))); pEncryptedKey->cbSize = sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO); pEncryptedKey->RecipientPublicKey = pCertInfo->SubjectPublicKeyInfo.PublicKey; pEncryptedKey->RecipientId = EncodeRecipientId(recipient, hCertContext, pCertContext, pCertInfo, hb); pEncryptedKey->Date = default(FILETIME); pEncryptedKey->pOtherAttr = null; CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO **ppEncryptedKey = (CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO **)(hb.Alloc(sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO *))); ppEncryptedKey[0] = pEncryptedKey; pEncodeInfo->cRecipientEncryptedKeys = 1; pEncodeInfo->rgpRecipientEncryptedKeys = ppEncryptedKey; return(pEncodeInfo); } }
// // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb". // private static unsafe CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *EncodeKeyTransRecipientInfo(CmsRecipient recipient, HeapBlockRetainer hb) { // "recipient" is a deep-cloned CmsRecipient object whose lifetime this class controls. Because of this, we can pull out the CERT_CONTEXT* and CERT_INFO* pointers // and embed pointers to them in the memory block we return. Yes, this code is scary. // // (The use of SafeCertContextHandle here is about using a consistent pattern to get the CERT_CONTEXT (rather than the ugly (CERT_CONTEXT*)(recipient.Certificate.Handle) pattern.) // It's not about keeping the context alive.) using (SafeCertContextHandle hCertContext = recipient.Certificate.CreateCertContextHandle()) { CERT_CONTEXT *pCertContext = hCertContext.DangerousGetCertContext(); CERT_INFO * pCertInfo = pCertContext->pCertInfo; CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *pEncodeInfo = (CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *)(hb.Alloc(sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO))); pEncodeInfo->cbSize = sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO); if (recipient.RSAEncryptionPadding is null) { CRYPT_ALGORITHM_IDENTIFIER algId = pCertInfo->SubjectPublicKeyInfo.Algorithm; pEncodeInfo->KeyEncryptionAlgorithm = algId; } else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.Pkcs1) { pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.Rsa); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaPkcsParameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaPkcsParameters); } else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA1) { pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha1Parameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha1Parameters); } else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA256) { pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha256Parameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha256Parameters); } else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA384) { pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha384Parameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha384Parameters); } else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA512) { pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha512Parameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha512Parameters); } else { throw ErrorCode.CRYPT_E_UNKNOWN_ALGO.ToCryptographicException(); } pEncodeInfo->pvKeyEncryptionAuxInfo = IntPtr.Zero; pEncodeInfo->hCryptProv = IntPtr.Zero; pEncodeInfo->RecipientPublicKey = pCertInfo->SubjectPublicKeyInfo.PublicKey; pEncodeInfo->RecipientId = EncodeRecipientId(recipient, hCertContext, pCertContext, pCertInfo, hb); return(pEncodeInfo); } }
// // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb". // private static unsafe CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *EncodeKeyTransRecipientInfo(CmsRecipient recipient, HeapBlockRetainer hb) { // "recipient" is a deep-cloned CmsRecipient object whose lifetime this class controls. Because of this, we can pull out the CERT_CONTEXT* and CERT_INFO* pointers // and embed pointers to them in the memory block we return. Yes, this code is scary. // // (The use of SafeCertContextHandle here is about using a consistent pattern to get the CERT_CONTEXT (rather than the ugly (CERT_CONTEXT*)(recipient.Certificate.Handle) pattern.) // It's not about keeping the context alive.) using (SafeCertContextHandle hCertContext = recipient.Certificate.CreateCertContextHandle()) { CERT_CONTEXT *pCertContext = hCertContext.DangerousGetCertContext(); CERT_INFO * pCertInfo = pCertContext->pCertInfo; CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *pEncodeInfo = (CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *)(hb.Alloc(sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO))); pEncodeInfo->cbSize = sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO); RSAEncryptionPadding padding = recipient.RSAEncryptionPadding; if (padding is null) { if (recipient.Certificate.GetKeyAlgorithm() == Oids.RsaOaep) { byte[] parameters = recipient.Certificate.GetKeyAlgorithmParameters(); if (parameters == null || parameters.Length == 0) { padding = RSAEncryptionPadding.OaepSHA1; } else if (!PkcsHelpers.TryGetRsaOaepEncryptionPadding(parameters, out padding, out _)) { throw ErrorCode.CRYPT_E_UNKNOWN_ALGO.ToCryptographicException(); } } else { // gost falls in here padding = RSAEncryptionPadding.Pkcs1; } } if (padding == RSAEncryptionPadding.Pkcs1) { // begin: gost switch (recipient.Certificate.GetKeyAlgorithm()) { case Oids.Gost3410: case Oids.Gost3410_2012_256: case Oids.Gost3410_2012_512: { // copy from cert info explicitly pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(recipient.Certificate.GetKeyAlgorithm()); // uint, копируем pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData; // копируем из памяти и записываем var pbDataBytes = new byte[pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData]; Marshal.Copy(pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData, pbDataBytes, 0, pbDataBytes.Length); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(pbDataBytes); break; } default: { // end: gost pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.Rsa); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaPkcsParameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaPkcsParameters); break; } } } else if (padding == RSAEncryptionPadding.OaepSHA1) { pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha1Parameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha1Parameters); } else if (padding == RSAEncryptionPadding.OaepSHA256) { pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha256Parameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha256Parameters); } else if (padding == RSAEncryptionPadding.OaepSHA384) { pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha384Parameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha384Parameters); } else if (padding == RSAEncryptionPadding.OaepSHA512) { pEncodeInfo->KeyEncryptionAlgorithm.pszObjId = hb.AllocAsciiString(Oids.RsaOaep); pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha512Parameters.Length; pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha512Parameters); } else { throw ErrorCode.CRYPT_E_UNKNOWN_ALGO.ToCryptographicException(); } pEncodeInfo->pvKeyEncryptionAuxInfo = IntPtr.Zero; pEncodeInfo->hCryptProv = IntPtr.Zero; pEncodeInfo->RecipientPublicKey = pCertInfo->SubjectPublicKeyInfo.PublicKey; pEncodeInfo->RecipientId = EncodeRecipientId(recipient, hCertContext, pCertContext, pCertInfo, hb); return(pEncodeInfo); } }