"can't decode PKCS7SignedData object" - ASP.NET iTextSharp - asp.net

I'm attempting to verify if a pdf has been digitally signed from the server side using iTextSharp, but am receiving the following error: "can't decode PKCS7SignedData object" on the code
PdfPKCS7 pk = af.VerifySignature(name);
Here is the function:
public string verifyPdfSignature(string pdfFile)
{
var parser = new X509CertificateParser();
PdfReader reader = new PdfReader(pdfFile);
AcroFields af = reader.AcroFields;
var names = af.GetSignatureNames();
if (names.Count == 0)
{
return "No Signature present in pdf file.";
}
foreach (string name in names)
{
if (!af.SignatureCoversWholeDocument(name))
{
return (string.Format("The signature: {0} does not cover the whole document.", name));
}
PdfPKCS7 pk = af.VerifySignature(name); //<--- ERROR HERE
var cal = pk.SignDate;
var pkc = pk.Certificates;
if (!pk.Verify())
{
return "The signature could not be verified.";
}
if (!pk.VerifyTimestampImprint())
{
return "The signature timestamp could not be verified.";
}
}
return "nothing";
}

Related

Issue with loading dicom images in WADO loader

I am working on a web based OHIF Dicom viewer. I am using clear canvas as my PACs server. So I developed one broker application in .net core which works like WADO-RS and supply information to OHIF viewer from clear canvas. In my broker application I am passing metadata to OHIF viewer in json format by using FO-dicom json converter which converts dcm file into Json string.
My code for sending metadata:
var files = Directory.GetFiles(directory);
List<JObject> lstjo = new List<JObject>();
JObject jo;
foreach (var file in files)
{
var dicomDirectory = DicomFile.Open(file, FileReadOption.ReadAll);
if (dicomDirectory.Dataset.InternalTransferSyntax.UID.UID != DicomTransferSyntax.ImplicitVRLittleEndian.UID.UID)
{
var transcoder = new DicomTranscoder(dicomDirectory.Dataset.InternalTransferSyntax, DicomTransferSyntax.ImplicitVRLittleEndian);
dicomDirectory = transcoder.Transcode(dicomDirectory);
}
JsonDicomConverter dicomConverter = new JsonDicomConverter();
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
JsonWriter writer = new JsonTextWriter(sw);
Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
dicomConverter.WriteJson(writer, dicomDirectory.Dataset, serializer);
jo = JObject.Parse(sb.ToString());
// jo.Property("7FE00010").Remove();
retJsonstring += jo.ToString() + ",";
}
if (retJsonstring.Length > 6)
{
retJsonstring = retJsonstring.Substring(0, retJsonstring.Length - 1) + "]";
}
else
{
retJsonstring += "]";
}
retJsonstring = retJsonstring.Replace("\r", "").Replace("\n", "");
}
return retJsonstring;
During passing metadata there is no issue in Ohif viewer. After then OHIF viewer sending WADORS request for frames to display. My broker application also send responding for that request in multipart.
My code for sending Multipart response :
{
var dicomFile = DicomFile.Open(path, FileReadOption.ReadAll);
string transfersyntax = dicomFile.Dataset.InternalTransferSyntax.UID.UID;
MemoryStream streamContent = new MemoryStream();
if (transfersyntax != DicomTransferSyntax.ImplicitVRLittleEndian.UID.UID)
{
var transcoder = new DicomTranscoder(dicomFile.Dataset.InternalTransferSyntax, DicomTransferSyntax.ImplicitVRLittleEndian);
dicomFile = transcoder.Transcode(dicomFile);
}
dicomFile.Save(streamContent);
DicomImage img = new DicomImage(dicomFile.Dataset, 0);
streamContent.Seek(0, SeekOrigin.Begin);
string boundary = Guid.NewGuid().ToString();
MultipartContent multipartContent = new MultipartContent();
//newFile.Save(multipartContent.Stream);
multipartContent.Stream = streamContent;// File.OpenRead(path);
multipartContent.ContentType = "application/octet-stream";
multipartContent.transfersyntax = dicomFile.Dataset.InternalTransferSyntax.UID.UID;
multipartContent.FileName = "";
multiContentResult = new MultipartResult("related", boundary) { multipartContent };
return multiContentResult;
}
Mulitpart class and MulticontentResult Class:
public class MultipartContent
{
public string ContentType { get; set; }
public string FileName { get; set; }
public Stream Stream { get; set; }
public string transfersyntax { get; set; }
}
public class MultipartResult : Collection<MultipartContent>, IActionResult
{
private readonly System.Net.Http.MultipartContent content;
public MultipartResult(string subtype = "byteranges", string boundary = null)
{
if (boundary == null)
{
this.content = new System.Net.Http.MultipartContent(subtype);
}
else
{
this.content = new System.Net.Http.MultipartContent(subtype, boundary);
}
}
public async Task ExecuteResultAsync(ActionContext context)
{
foreach (var item in this)
{
if (item.Stream != null)
{
var content = new StreamContent(item.Stream);
if (item.ContentType != null)
{
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(item.ContentType);
content.Headers.ContentType.Parameters.Add(new System.Net.Http.Headers.NameValueHeaderValue("transfer-syntax", item.transfersyntax));
}
this.content.Add(content);
}
}
context.HttpContext.Response.ContentLength = content.Headers.ContentLength;
context.HttpContext.Response.ContentType = content.Headers.ContentType.ToString();
await content.CopyToAsync(context.HttpContext.Response.Body);
}
}
After sending WAROrs response , I getting error in OHIF viewer in RangeError: offset is out of bounds in stackviewport.js during set pixeldata flat32array to scaledata flat32array like below Image
So I inspect in browser after then I come know that Pixel data size and scaledata size is different like below image..
To verify my dcm file I checked with ohif viewer by directly opened those file in https://v3-demo.ohif.org/local. It is opening properly.
So what are possible reason for this issue ? how to rectify?

vulnerability from security team in forget password controller in asp .net

I have a controller form application and the security team they said there is a vulnerability you can put any user_id fom postman inside the controller like this
ForgotPassword/user_id
how I can remove this vulnerability check the code below:
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult ForgotPassword(string emailId)
{
var helper = new Helper.Helper();
List<SqlParameter> args = new List<SqlParameter>();
args.Add(new SqlParameter("#Pin_email_id", emailId));
var req_resp = new Dictionary<string, object>();
try
{
using (DataSet dataset = helper.ExecuteSqlQuery("Web_Forgot_Password", args))
{
if (dataset != null && dataset.Tables.Count > 0 && dataset.Tables[0].Rows.Count > 0)
{
if (dataset.Tables[0].Rows[0]["Status"].ToString() == "Success")
{
req_resp["status"] = true;
req_resp["message"] = dataset.Tables[0].Rows[0]["Description"].ToString();
req_resp["code"] = dataset.Tables[0].Rows[0]["Code"].ToString();
string password = dataset.Tables[0].Rows[0]["user_password"].ToString();
SendForgotMail(emailId, dataset.Tables[0].Rows[0]["user_name"].ToString(), helper.Decrypt(password), dataset.Tables[0].Rows[0]["employee"].ToString());
return Json(req_resp);
}
else
{
req_resp["status"] = false;
req_resp["message"] = dataset.Tables[0].Rows[0]["Description"].ToString();
req_resp["code"] = dataset.Tables[0].Rows[0]["Code"].ToString();
return Json(req_resp);
}
}
else
{
req_resp["status"] = false;
req_resp["message"] = "Request Failed";
req_resp["code"] = "1005";
return Json(req_resp);
}
}
}
catch
{
var response = new
{
status = false,
message = "Request failed",
code = "1005"
};
return Json(response);
}
}
Well normally you store only password hashes in your database, which are not decryptable. Watching helper.Decrypt(password) in your code and sending the original password as a plain text in email is something painful. Normally I would just send a password reset link which can be used only once.
I checked the SqlParemater docs, it is added as a String value the way you use it, so it is not SQL injectable. Without the exact SQL I cannot tell much. I think they meant that it is SQL injectable, but then they should send evidence at least.

how we can return a status code for the serialized JSON object using Newtonsoft.net

I have this Action method which act as an API end point inside our ASP.NET MVC-5, where it search for a username and return the username Phone number and Department from Active Directory (we are serializing the object using Newtonsoft.net):-
public ActionResult UsersInfo2()
{
DomainContext result = new DomainContext();
try
{
// create LDAP connection object
DirectoryEntry myLdapConnection = createDirectoryEntry();
string ADServerName = System.Web.Configuration.WebConfigurationManager.AppSettings["ADServerName"];
string ADusername = System.Web.Configuration.WebConfigurationManager.AppSettings["ADUserName"];
string ADpassword = System.Web.Configuration.WebConfigurationManager.AppSettings["ADPassword"];
using (var context = new DirectoryEntry("LDAP://mydomain.com:389/DC=mydomain,DC=com", ADusername, ADpassword))
using (var search = new DirectorySearcher(context))
{
// create search object which operates on LDAP connection object
// and set search object to only find the user specified
// DirectorySearcher search = new DirectorySearcher(myLdapConnection);
// search.PropertiesToLoad.Add("telephoneNumber");
search.Filter = "(&(objectClass=user)(sAMAccountName=test.test))";
SearchResult r = search.FindOne();
ResultPropertyCollection fields = r.Properties;
foreach (String ldapField in fields.PropertyNames)
{
// cycle through objects in each field e.g. group membership
// (for many fields there will only be one object such as name)
string temp;
// foreach (Object myCollection in fields[ldapField])
// {
// temp = String.Format("{0,-20} : {1}",
// ldapField, myCollection.ToString());
if (ldapField.ToLower() == "telephonenumber")
{
foreach (Object myCollection in fields[ldapField])
{
result.Telephone = myCollection.ToString();
}
}
else if (ldapField.ToLower() == "department")
{
foreach (Object myCollection in fields[ldapField])
{
result.Department = myCollection.ToString();
}
}
// }
}
string output = JsonConvert.SerializeObject(result);
return Json(output,JsonRequestBehavior.AllowGet);
}
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return View(result);
}
now the return JSON will be as follow:-
"\"DisplayName\":null,\"Telephone\":\"123123\",\"Department\":\"IT\",\"Name\":null,\"SamAccountName\":null,\"DistinguishedName\":null,\"UserPrincipalName\":null}"
but in our case we need to return a status code beside the return json data. for example inccase there is an exception we need to return an error code,also if we are able to get the user's info we need to pass succes code 200, and so on.. so how we can achieve this?
you can try something like this
var statusCode=200;
string output = JsonConvert.SerializeObject( new { result = result, StatusCode = statusCode);
but nobody usually do this. When users call API they can check status code that HTTP Client returns, using code like this
var response = await client.GetAsync(api);
//or
var response = await client.PutAsJsonAsync(api, data);
var statusCode = response.StatusCode.ToString();
//or usually
if (response.IsSuccessStatusCode) {...}
else {...}

Modify BuildApiResponse in ASP.Net Web Api

I am new in ASP.NET MVC Web API. I am trying to modified the return JSon to this format
{
"Error": false,
"Status": 200,
"Response": []
}
Now I able to do that by follow this post https://www.devtrends.co.uk/blog/wrapping-asp.net-web-api-responses-for-consistency-and-to-provide-additional-information . But the problem is I not able to show ModelState error like 'First name is required' because the code only show the first hit error.
if (error != null)
{
content = null;
//only show the first error
errorMessage = error.Message;
}
So I did some modification, now the code is written as below:
if (error != null)
{
content = null;
foreach(var e in error)
{
//if the error's type is ModelState
if (e.Key.Equals("ModelState"))
{
var allErrors = e.Value;
foreach (var modelError in (IEnumerable<KeyValuePair<string, object>>)allErrors)
{
var msg = modelError;
errorMessage = string.Concat(errorMessage, ", ", ((String[]) modelError.Value)[0]);
}
}
else
{
errorMessage = e.Value.ToString();
}
}
}
Now it's able to show all errors but the code is messy. I am writing this questions to find out what is the proper way to write this kind of code.
You can iterate over all the errors and concatenate them using StringBuilder. String.Join is much faster than Append for less than 1000 items (it is unlikely you will have so many errors in the modelstate object):
public static ValidationResult CheckValid(ModelStateDictionary modelState, string httpName = null)
{
if (!modelState.IsValid)
{
var sb = new StringBuilder();
sb.AppendLine(httpName + " failed: Invalid Json:");
foreach (var pair in modelState)
{
var error = String.Join(";", pair.Value.Errors.Select
(
i =>
{
if (!String.IsNullOrEmpty(i.ErrorMessage))
return i.ErrorMessage;
return i.Exception.Message;
}
));
sb.AppendLine($"Property: {pair.Key} Errors: ({error})");
}
return new ValidationResult(false, sb.ToString());
}
else
return new ValidationResult(true, "");
}

parsing signed and encrypted email

I am writing an application that must be able to read signed and encrypted emails and parse through their contents. I am able to get everything working fine for emails that are only encrypted, but do not know what to do when I get an email that is also signed. Once I decrypt this email instead of having an anticipated 4 parts in a Multipart object, I have only 1 part in a MimePart object with the file name smime.p7m. I do not know how to break this file up or verify the signature. I have found the documentation on verifying a signature (http://www.mimekit.net/docs/html/Working-With-SMime.htm#Verify), but I don't see how this does anything. Obviously there is something that I am just not understanding at this point.
Below is a sample of the code that I am using. Note that this will be refactored after I get everything figured out, but this code is thus far working fine for all emails that I have tested so far that are not signed (may or may not be encrypted).
public void decryptAndSendEmails()
{
List<EmailMessage> emails = getEmails();
foreach (var email in emails)
{
var decryptedEmailMessage = new EmailMessage(service);
MimeMessage message;
using (var stream = new MemoryStream(email.MimeContent.Content, false))
{
message = MimeMessage.Load(stream);
}
var pkcs7 = message.BodyParts.OfType<ApplicationPkcs7Mime>().FirstOrDefault();
if (pkcs7 != null)
{
//If the SecureMimeType has not been set as it should, set it to EnvelopedData
if (pkcs7.SecureMimeType == SecureMimeType.Unknown)
{
var content = new MemoryStream();
pkcs7.Content.DecodeTo(content);
content.Position = 0;
pkcs7 = new ApplicationPkcs7Mime(SecureMimeType.EnvelopedData, content);
}
using (var ctx = new TemporarySecureMimeContext())
{
using (var stream = File.OpenRead(ConfigurationManager.AppSettings["certLocation"]))
{
ctx.Import(stream, ConfigurationManager.AppSettings["certPassword"]);
}
var decrypted = pkcs7.Decrypt(ctx);
var decryptedParts = new List<MimePart>();
if (decrypted is Multipart)
{
decryptedParts = breakMultiPart((Multipart)decrypted);
}
else if (decrypted is MimePart)
{
decryptedParts.Add((MimePart)decrypted);
}
else
{
throw new InvalidOperationException("Unknown Mime part found");
}
var textParts = decryptedParts.Where(r => r is TextPart);
var htmlParts = textParts.Where(x => ((TextPart)x).IsHtml);
var textBodyParts = textParts.Where(x => !((TextPart)x).IsHtml);
var attachmentParts = decryptedParts.Where(r => !(r is TextPart));
if (htmlParts.Any())
{
if (htmlParts.Count() > 1)
{
throw new InvalidOperationException("multiple html body parts.");
}
var htmlPart = (TextPart)htmlParts.First();
decryptedEmailMessage.Body = new MessageBody(BodyType.HTML, htmlPart.Text);
}
else
{
//Text body
if (textBodyParts.Count() > 1)
{
throw new InvalidOperationException("multiple text body parts.");
}
var textPart = (TextPart)textBodyParts.First();
decryptedEmailMessage.Body = new MessageBody(BodyType.Text, textPart.Text);
}
foreach (var part in attachmentParts)
{
var content = new MemoryStream();
part.Content.DecodeTo(content);
content.Position = 0;
decryptedEmailMessage.Attachments.AddFileAttachment(part.FileName, content);
if (!part.IsAttachment)
{
decryptedEmailMessage.Attachments.First(r => r.Name == part.FileName).IsInline = true;
decryptedEmailMessage.Attachments.First(r => r.Name == part.FileName).ContentId = part.ContentId;
}
}
}
////do stuff with decrypted Email
}
else
{
//The email is not encrypted
decryptedEmailMessage = email;
//do stuff with decrypted Email
}
}
}
I have finally figured this out using a combination of the comment from #jstedfast and the information I found in Unable to decrypt p7m using MimeKit. The following is the resulting code to fix this issue:
public void decryptAndSendEmails()
{
List<EmailMessage> emails = getEmails();
foreach (var email in emails)
{
var decryptedEmailMessage = new EmailMessage(service);
MimeMessage message;
using (var stream = new MemoryStream(email.MimeContent.Content, false))
{
message = MimeMessage.Load(stream);
}
var pkcs7 = message.BodyParts.OfType<ApplicationPkcs7Mime>().FirstOrDefault();
if (pkcs7 != null)
{
using (var ctx = new TemporarySecureMimeContext())
{
using (var stream = File.OpenRead(ConfigurationManager.AppSettings["certLocation"]))
{
ctx.Import(stream, ConfigurationManager.AppSettings["certPassword"]);
}
var decrypted = pkcs7.Decrypt(ctx);
if (decrypted != null && decrypted is MimePart && ((MimePart)decrypted).FileName == "smime.p7m")
{
//We need to verify the signature
var signedDecryptedEntity = decrypted as ApplicationPkcs7Mime;
signedDecryptedEntity.Verify(ctx, out decrypted); //the real decrypted data
}
var decryptedParts = new List<MimePart>();
if (decrypted is Multipart)
{
decryptedParts = breakMultiPart((Multipart)decrypted);
}
else if (decrypted is MimePart)
{
decryptedParts.Add((MimePart)decrypted);
}
else
{
throw new InvalidOperationException("Unknown Mime part found");
}
var textParts = decryptedParts.Where(r => r is TextPart);
var htmlParts = textParts.Where(x => ((TextPart)x).IsHtml);
var textBodyParts = textParts.Where(x => !((TextPart)x).IsHtml);
var attachmentParts = decryptedParts.Where(r => !(r is TextPart));
if (htmlParts.Any())
{
if (htmlParts.Count() > 1)
{
throw new InvalidOperationException("multiple html body parts.");
}
var htmlPart = (TextPart)htmlParts.First();
decryptedEmailMessage.Body = new MessageBody(BodyType.HTML, htmlPart.Text);
}
else
{
//Text body
if (textBodyParts.Count() > 1)
{
throw new InvalidOperationException("multiple text body parts.");
}
var textPart = (TextPart)textBodyParts.First();
decryptedEmailMessage.Body = new MessageBody(BodyType.Text, textPart.Text);
}
foreach (var part in attachmentParts)
{
var content = new MemoryStream();
part.Content.DecodeTo(content);
content.Position = 0;
decryptedEmailMessage.Attachments.AddFileAttachment(part.FileName, content);
if (!part.IsAttachment)
{
decryptedEmailMessage.Attachments.First(r => r.Name == part.FileName).IsInline = true;
decryptedEmailMessage.Attachments.First(r => r.Name == part.FileName).ContentId = part.ContentId;
}
}
}
//Do Something with email (decryptedEmailMessage)
}
else
{
//The email is not encrypted
decryptedEmailMessage = email;
//Do Something with email (decryptedEmailMessage)
}
}
}

Resources