I'm working with mimekit to encrypt and decrypt mime messages and send them via Graph API, the encryption seems to work well but the receiver of the message can't decrypt the message via it's Outlook client. In other encrypted mails the reciever generated he can see a padlock in it's Outlook client and then install the certificate and then decrypt the message, but when I send the message via Graph API that padlock isn't there.
Furthermore, when I try to get the same message I already sent encrypted and then decrypt it I get the following error:
asn1 bad tag value met at Internal.Cryptography.Pal.Windows.DecryptorPalWindows.Decode(ReadOnlySpan`1 encodedMessage, Int32& version, ContentInfo& contentInfo, AlgorithmIdentifier& contentEncryptionAlgorithm, X509Certificate2Collection& originatorCerts, CryptographicAttributeObjectCollection& unprotectedAttributes)
at Internal.Cryptography.Pal.Windows.PkcsPalWindows.Decode(ReadOnlySpan`1 encodedMessage, Int32& version, ContentInfo& contentInfo, AlgorithmIdentifier& contentEncryptionAlgorithm, X509Certificate2Collection& originatorCerts, CryptographicAttributeObjectCollection& unprotectedAttributes)
at System.Security.Cryptography.Pkcs.EnvelopedCms.Decode(ReadOnlySpan`1 encodedMessage)
at System.Security.Cryptography.Pkcs.EnvelopedCms.Decode(Byte[] encodedMessage)
at MimeKit.Cryptography.WindowsSecureMimeContext.<DecryptAsync>d__45.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at MimeKit.Cryptography.ApplicationPkcs7Mime.<DecryptAsync>d__11.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at PasarelaLibrary.Bases.GraphService.BaseGraphPasarela.<Decrypt>d__12.MoveNext() in C:\Dev\Euroval\PasarelaAceuro\PasarelaLibrary\Bases\GraphService\BaseGraphPasarela.cs:line 321
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at PasarelaLibrary.Bases.GraphService.BaseGraphPasarela.<DownloadGraph>d__8.MoveNext() in C:\Dev\Euroval\PasarelaAceuro\PasarelaLibrary\Bases\GraphService\BaseGraphPasarela.cs:line 178
This is the code I'm using:
ClientSecretCredential clientSecretCredential = new ClientSecretCredential(
_settings.GraphApiSettings.TenantId,
_settings.GraphApiSettings.ClientId,
_settings.GraphApiSettings.ClientSecret,
options);
GraphServiceClient graphClient = new GraphServiceClient(clientSecretCredential, new string[] { _settings.GraphApiSettings.Scope });
var message = await graphClient.GetMessage(_settings.GraphApiSettings.UserId, fileId);
var encryptedContent = (ApplicationPkcs7Mime)await MimeEntity.LoadAsync(ParserOptions.Default,
ContentType.Parse(ParserOptions.Default, "application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m"), message);
var decriptedMessage = await Decrypt(encryptedContent);
public async Task<MimeEntity> Decrypt(ApplicationPkcs7Mime encryptedContent)
{
var context = new WindowsSecureMimeContext(StoreLocation.CurrentUser);
context.Import(StoreName.CertificateAuthority, _settings.GraphApiSettings.Certificate);
return await encryptedContent.DecryptAsync(context);
}
public static async Task<Stream> GetMessage(this GraphServiceClient graphServiceClient, string userId, string messageId)
{
var request = graphServiceClient.Users[userId].Messages[messageId].Request().GetHttpRequestMessage();
request.RequestUri = new Uri(request.RequestUri.OriginalString "/$value");
var response = await graphServiceClient.HttpProvider.SendAsync(request);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStreamAsync();
content.Position = 0;
return content;
}
please let me know if you need anything more from me to check this error. Thanks in advance!
CodePudding user response:
Try this:
ClientSecretCredential clientSecretCredential = new ClientSecretCredential(
_settings.GraphApiSettings.TenantId,
_settings.GraphApiSettings.ClientId,
_settings.GraphApiSettings.ClientSecret,
options);
GraphServiceClient graphClient = new GraphServiceClient(clientSecretCredential, new string[] { _settings.GraphApiSettings.Scope });
var messageStream = await graphClient.GetMessage(_settings.GraphApiSettings.UserId, fileId);
var message = await MimeMessage.LoadAsync(messageStream);
var encryptedContent = (ApplicationPkcs7Mime) message.Body;
var decriptedMessage = await Decrypt(encryptedContent);
public async Task<MimeEntity> Decrypt(ApplicationPkcs7Mime encryptedContent)
{
var context = new WindowsSecureMimeContext(StoreLocation.CurrentUser);
context.Import(StoreName.CertificateAuthority, _settings.GraphApiSettings.Certificate);
return await encryptedContent.DecryptAsync(context);
}
public static async Task<Stream> GetMessage(this GraphServiceClient graphServiceClient, string userId, string messageId)
{
var request = graphServiceClient.Users[userId].Messages[messageId].Request().GetHttpRequestMessage();
request.RequestUri = new Uri(request.RequestUri.OriginalString "/$value");
var response = await graphServiceClient.HttpProvider.SendAsync(request);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStreamAsync();
content.Position = 0;
return content;
}
If the stream returned by GetMessage() contains the full MIME message, then don't use the MimeEntity.LoadAsync() method that is designed for parsing HTTP multipart/form-data responses.
The reason for a MimeEntity.LoadAsync() API that takes a ContentType parameter is that the Content-Type header is the HTTP's Content-Type header, and therefor response.Content won't contain the MIME headers.
But in your case, the HTTP response will have 2 sets of headers. The HTTP response headers and the MIME headers (which will all be contained inside of the response.Content).