There should be a bug in DotNetNativeToolChain. In project_name.UWP.csproj file, I have
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
In xaml, I have
<Image x:Name="testimage"></Image>
In code behind file, I have
testimage.Source = ImageSource.FromResource("project_name.testimage1.png");
testimage1.png is entered into project_name.csproj as
<EmbeddedResource Include="testimage1.png" />
Project can compile but crash with an error "Unhandled exception at 0x(Windows.UI.Xaml.dll) in .exe. 0xC000027B: An application-internal exception has occurred."
If I comment out the "UseDotNetNativeToolchain" in project_name.UWP.csproj file, the application runs smoothly.
public ImageSource GetImageSource(string resource)
{
ImageSource imagesource = null;
Assembly assembly = GetType().GetTypeInfo().Assembly;
MemoryStream ms = new MemoryStream();
using (Stream stream = assembly.GetManifestResourceStream(resource))
{
if (stream != null)
{
stream.CopyTo(ms);
imagesource = ImageSource.FromStream(() => new MemoryStream(ms.ToArray()));
}
}
return imagesource;
}
In the code, I use
testimage.Source = GetImageSource("project_name.testimage1.png");
Related
I am trying to deserialize a (in this case a PDF) file from a FileStreamResult on from an API Controller in the Blazor WebAssembly front end.
On the controller side I return the file;
public IActionResult GetDocumentImage(int documentId)
{
var response = _service.Get(documentId);
HttpAssert.Success(response);
HttpAssert.IsNotNull(response);
Stream stream = new MemoryStream(response.Result.Data);
if (stream == null)
return NotFound();
return File(stream, response.Result.MimeType);
}
I have the following code;
internal async Task<ServiceResponse<T>> BuildResponseAsBinaryStream<T>(HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStreamAsync();
using (MemoryStream memoryStream = new MemoryStream())
{
await responseContent.CopyToAsync(memoryStream);
memoryStream.Position = 0;
T obj = default(T);
BinaryFormatter binarySerializer = new BinaryFormatter();
obj = (T)binarySerializer.Deserialize(memoryStream);
return new ServiceResponse<T> { Result = obj, HasError = false, HttpErrorCode = -1, Error = null };
}
}
}
However, an exception is thrown at await responseContent.CopyToAsync(memoryStream);, I can debug this through Chrome using the client side debugger and Visual Studio but the ex.Message is unable to evaluate.
An ASP.NET MVC solution that was working fine in VS 2012 stopped working in 2019 and I cannot find what has changed to break it.
Originally I had the code in the first block - the async task would go to the file storage and retrieve the file, and then the file was sent to the browser using a FileResult that the controller called automatically. After a VERY painful change to VS 2019 and updating everything (.NET runtime, 3rd party libraries, etc.) I have the application working again except for this issue.
I tried creating a new FileStreamResult (which is in the 2nd block) but that does not get called either. When I click on a link that calls this:
<a href="/Cert/File?folder=&filename=#HttpUtility.UrlEncode(FilePath)" ...
It gives me a blank page instead of downloading the file as it used to.
public async Task FileAsync(string folder, string filename)
{
AsyncManager.OutstandingOperations.Increment();
var ReadObjectTask = _fileStorageProvider.ReadObjectDataAsync(folder, filename);
Stream ROResult = await ReadObjectTask;
AsyncManager.Parameters["stream"] = ROResult;
AsyncManager.Parameters["filename"] = filename;
AsyncManager.OutstandingOperations.Decrement();
}
public FileResult FileCompleted(Stream stream, string filename)
{
if (stream == null)
{
return File(Server.MapPath(Url.Content("~/Content/bad_file.png")), "image/png");
}
var file = new FileStreamResult(stream, MIMEAssistant.GetMIMEType(filename));
if (filename.Contains("/"))
{
filename = filename.Split('/').Last();
}
file.FileDownloadName = filename;
return file;
}
Here is the FileStreamResult I tried:
public System.Web.Mvc.FileStreamResult FileCompleted(Stream stream, string contentType, string filename)
{
if (stream == null)
{
string bFile = Server.MapPath(Url.Content("~/Content/bad_file.png"));
Stream blankfile = System.IO.File.OpenRead(bFile);
return File(blankfile, MIMEAssistant.GetMIMEType(bFile), System.IO.Path.GetFileName(bFile));
}
if (filename.Contains("/"))
{
filename = filename.Split('/').Last();
}
return File(stream, MIMEAssistant.GetMIMEType(filename), filename);
}
(The filename.Contains part is old code from a predecessor that I just need to replace with Path.GetFileName - sorry I did not clean it up before I posted.)
I decided to make the Async Task one of type and moved the
stream processing into that procedure to solve my problem. I do not know
why the Async Task that was working in 2012 stopped in 2019.
public async Task<FileResult> FileAsync(string folder, string filename)
{
AsyncManager.OutstandingOperations.Increment();
var ReadObjectTask = _fileStorageProvider.ReadObjectDataAsync(folder, filename);
Stream ROResult = await ReadObjectTask;
AsyncManager.Parameters["stream"] = ROResult;
AsyncManager.Parameters["filename"] = filename;
AsyncManager.OutstandingOperations.Decrement();
if (ROResult == null)
{
return File(Server.MapPath(Url.Content("~/Content/bad_file.png")), "image/png");
}
var file = new FileStreamResult(ROResult, MIMEAssistant.GetMIMEType(filename));
file.FileDownloadName = System.IO.Path.GetFileName(filename);
return file;
}
I made a feedback project. I made it on ASP.NET MVC 5 it also has crystal reports. reports were working fine, but suddenly they stopped to work. I don't what happened with them. but since last week I tried hard to find solution but unfortunately could not get the right one who solved the solution. I downloaded different run times but all went vain. this is the bottom line of error.
"Method not found: 'CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag CrystalDecisions.ReportAppServer.ReportDefModel.ISCRExportOptions.get_ExportOptionsEx()'"
this is the code:
public CrystalReportFeedback UserFeedbackDateWise(FeedbackReport be){
if (Session["CurrentUser"] != null && Convert.ToInt32(Session["User_Id"]) != 0)
{
string reportPath = Path.Combine(Server.MapPath("~/Reports"), "UserFeedbackReport.rpt");
if (ModelState.IsValid)
{
be.FromDate = Convert.ToDateTime(TempData["UserFromDate"]);
be.ToDate = Convert.ToDateTime(TempData["UserToDate"]);
be.User_Id = Convert.ToInt32(Session["User_Id"]);
}
return new CrystalReportFeedback(reportPath, be);
}
else
{
return null;
//new CrystalReportFeedback(reportPath, be);
}
}
Init of the report :
public CrystalReportFeedback(string reportPath, FeedbackReport be)//, object dataSet)
{
//int[] array;
string strConnect = Convert.ToString(System.Configuration.ConfigurationManager.ConnectionStrings["TSC"]);
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(strConnect);
string _username = builder.UserID;
string _pass = builder.Password;
string _server = builder.DataSource;
string _database = builder.InitialCatalog;
ReportDocument reportDocument = new ReportDocument();
//
reportDocument.Load(reportPath);
reportDocument.SetDatabaseLogon(_username, _pass, _server, _database);
if (be.Region_Id != 0)
{
reportDocument.SetParameterValue("#Region_Id", be.Region_Id);
}
if (be.User_Id != 0)
{
reportDocument.SetParameterValue("#User_Id", be.User_Id);
}
reportDocument.SetParameterValue("#FromDate", be.FromDate);
reportDocument.SetParameterValue("#ToDate", be.ToDate);
//reportDocument.ExportToDisk(ExportFormatType.PortableDocFormat, "C:\report.pdf");
_contentBytes = StreamToBytes(reportDocument.ExportToStream(ExportFormatType.PortableDocFormat));
}
Export method :
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.ApplicationInstance.Response;
response.Clear();
response.Buffer = false;
response.ClearContent();
response.ClearHeaders();
response.Cache.SetCacheability(HttpCacheability.Public);
response.ContentType = "application/pdf";
using (var stream = new MemoryStream(_contentBytes))
{
stream.WriteTo(response.OutputStream);
stream.Flush();
}
}
private static byte[] StreamToBytes(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Hope that I will get my solution at earliest.
this is modified code:
[HttpGet]
public FileResult UserFeedbackDateWise(FeedbackReport be)
{
if (Session["CurrentUser"] != null && Convert.ToInt32(Session["User_Id"]) != 0)
{
string reportPath = Path.Combine(Server.MapPath("~/Reports"), "UserFeedbackReport.rpt");
if (ModelState.IsValid)
{
be.FromDate = Convert.ToDateTime(TempData["UserFromDate"]);
be.ToDate = Convert.ToDateTime(TempData["UserToDate"]);
be.User_Id = Convert.ToInt32(Session["User_Id"]);
}
string strConnect = Convert.ToString(System.Configuration.ConfigurationManager.ConnectionStrings["TSC"]);
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(strConnect);
string _username = builder.UserID;
string _pass = builder.Password;
string _server = builder.DataSource;
string _database = builder.InitialCatalog;
ReportDocument reportDocument = new ReportDocument();
//
reportDocument.Load(reportPath);
reportDocument.SetDatabaseLogon(_username, _pass, _server, _database);
if (be.Region_Id != 0)
{
reportDocument.SetParameterValue("#Region_Id", be.Region_Id);
}
if (be.User_Id != 0)
{
reportDocument.SetParameterValue("#User_Id", be.User_Id);
}
reportDocument.SetParameterValue("#FromDate", be.FromDate);
reportDocument.SetParameterValue("#ToDate", be.ToDate);
Stream stream = reportDocument.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat);
//Here i have my stream with my pdf report, i just create a new FileStreamResult and return it to my client like that :
FileStreamResult myfile = new FileStreamResult(stream, "application/pdf");
return myfile;
//new CrystalReportFeedback(reportPath, be);
}
else
{
return null;
//new CrystalReportFeedback(reportPath, be);
}
}
This isn't a coding issue, it's a runtime issue. The version of the crystal runtime or the bitness of your application.
One thing to try first is to upgrade both your development version and ensure you're running the same version in production. See https://apps.support.sap.com/sap/support/knowledge/public/en/2148492 for more details
It says:
Compile your application either to 'X86 mode' or 'X64 mode'
Install the particular versions of runtimes on deployment machine.
i.e. If the application is compiled as 32 bit, then install the 32bit runtimes.
I'll try my best to help you exporting your report, but your post is not very clear. For your next post try to be very specific and provide as much information as you can.
I currently made a MVC project and export a crystalreport report from my controller to my client.
I think that your ExecuteResult method can work, but working with the httpcontext is useless, Crystalreport and .NET provide some useful methods to do the same.
So i'll show you how i create and export my report so you can copy / paste and modify your code.
Here is my controller method, called from a button :
[HttpGet]
public FileResult InitReport()
{
//I create my report here
FileImportReport rptH = new FileImportReport();
// Some configuration on the report, datasource, databaselogon .. etc
...
//
//Then I export my report to a pdf stream like that :
Stream stream = rptH.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat);
//Here i have my stream with my pdf report, i just create a new FileStreamResult and return it to my client like that :
FileStreamResult myfile = new FileStreamResult(stream, "application/pdf");
return myfile;
}
My method is called from a button but it can work like you want, or the file can be saved in any known path.
You can test to reproduce my code, in your CrystalReportFeedback method use my code with your reportDocument object, you don't need to use your StreamToBytes method.
Regards,
EDIT : Useful links with your error :
Crystal Reports exception in Visual Studio 2013
https://www.arcanadev.com/support/kb/K00000499.aspx
Long story short, I can sign documents just fine. But verifying them returns false, every time. I've looked through the first 5 or 6 pages of google and bing for a solution, but every "fix" I've found fails to help. Any help would be appreciated, as I've been trying to tackle this for a little over a week now. Also, the private keys of these certs are NOT exportable, and can't be. I'm not sure if that matters or not. Also, I opted not to include ValidateCertificate for now because it's never once made it that far. It always fails at CheckSignature(). Thank you.
HEre's what I'm using to generate my certs:
makecert -a SHA256 -n "CN=JEA2.me" -pe -r -len 2048 -sy 24 -sky signature -sv jeame2.pvk jeame2.cer
certmgr /add jeame2.cer /s /r localmachine root
makecert -sk "jea2.me" -iv jeame2.pvk -n "CN=JEA2IIS.me" -eku 1.3.6.1.4.1.311.10.3.12 -pe -sy 24 -ss my -sr localmachine -len 2048 -sky signature -ic Jeame2.cer IIS-ServerCert-Jeame2.cer
And from here I'm installing them directly into Local machine -> Trusted Root Certification Authorities
private static X509Certificate2 CheckXmldsigSignature(XmlDocument document)
{
X509Certificate2 certificate = null;
try
{
XmlNodeList nodeList = document.GetElementsByTagName("Signature", Xmldsigns);
if (nodeList.Count != 1)
{
Logger.ErrorFormat("Found {0} signature elements in file", nodeList.Count);
throw new InvalidOperationException(
"The XML document must have a single element with local name: \"Signature\" and namespace URI: " + Xmldsigns);
}
else
{
Logger.DebugFormat("Found Signature element successfully");
}
RSAPKCS1SHA256SignatureDescription.Register();
var signatureElement = (XmlElement)nodeList[0];
var signedXml = new SignedXml(document);
signedXml.LoadXml(signatureElement);
var keyInfoX509 =
(KeyInfoX509Data)
(from KeyInfoClause kic in signedXml.KeyInfo where kic is KeyInfoX509Data select kic).Single();
if (keyInfoX509.Certificates.Count != 1)
{
var msg = "The signature must contain information for one certificate.";
Logger.Error(msg);
throw new InvalidOperationException(msg);
}
else
{
Logger.DebugFormat("Extracted X509 certificate data successfully");
}
certificate = (X509Certificate2)keyInfoX509.Certificates[0];
bool validSignature = signedXml.CheckSignature(); //was null parameters. This too does not work.
if (!validSignature)
{
var msg = " SignedXml.CheckSignature returned false.";
throw new InvalidOperationException(msg);
}
else
{
Logger.DebugFormat("SignedXml.CheckSignature returned true.");
}
}
catch (Exception ex)
{
ScriptPro.Common.Logging.LogEx.LogException(Logger, ex);
throw;
}
return certificate;
}
private static Stream SignSHA256Stream(X509Certificate2 certificate, Stream stream)
{
if (certificate == null)
{
Logger.Error("certificate argument is null");
throw new ArgumentNullException("certificate");
}
if (stream == null)
{
Logger.Error("stream argument is null");
throw new ArgumentNullException("stream");
}
RSAPKCS1SHA256SignatureDescription.Register();
var document = new XmlDocument();
document.PreserveWhitespace = true; // May not be necessary.
document.Load(stream);
XmlNode root = document.DocumentElement;
XmlNodeList nodeList = document.GetElementsByTagName("Signature", Xmldsigns);
while (nodeList.Count > 0)
{
root.RemoveChild(nodeList[0]);
}
Reference reference = new Reference(string.Empty);
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
CspParameters csp = new CspParameters(24);
csp.Flags = CspProviderFlags.UseMachineKeyStore;
csp.KeyContainerName = "XML_DISG_RSA_KEY";
RSACryptoServiceProvider key = new RSACryptoServiceProvider(csp);
key.PersistKeyInCsp = false;
var keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(certificate));
SignedXml sxml = new SignedXml(document);
sxml.KeyInfo = keyInfo;
sxml.SigningKey = key;
sxml.SignedInfo.SignatureMethod = Xmldsigns256;
sxml.AddReference(reference);
sxml.ComputeSignature();
XmlElement xmlDigitalSignature = sxml.GetXml();
if (document.DocumentElement == null)
{
document.AppendChild(document.ImportNode(xmlDigitalSignature, true));
}
else
{
document.DocumentElement.AppendChild(document.ImportNode(xmlDigitalSignature, true));
}
if (document.FirstChild is XmlDeclaration)
{
document.RemoveChild(document.FirstChild);
}
MemoryStream outStream = new MemoryStream();
document.Save(outStream);
return outStream;
}
private static void SignSHA256File(X509Certificate2 certificate, FileInfo file)
{
if (certificate == null)
{
Logger.Error("certificate argument is null");
throw new ArgumentNullException("certificate");
}
if (file == null)
{
Logger.Error("file argument is null");
throw new ArgumentNullException("file");
}
if (!file.Exists)
{
Logger.ErrorFormat("File {0} does not exist.", file.Name);
throw new ArgumentException("File must exist.", "file");
}
if (file.IsReadOnly)
{
Logger.ErrorFormat("File {0} is read only.", file.Name);
throw new ArgumentException("File is read only.", "file");
}
FileStream stream = file.OpenRead();
string s = string.Empty;
using (StreamReader reader = new StreamReader(stream))
{
s = reader.ReadToEnd();
}
MemoryStream stream2 = new MemoryStream(Encoding.Default.GetBytes(s));
Stream inStream = SignSHA256Stream(certificate, stream2);
XmlDocument document = new XmlDocument();
inStream.Seek(0L, SeekOrigin.Begin);
document.Load(inStream);
Logger.InfoFormat("Saving {0}", file.FullName);
document.Save(file.FullName);
}
public class RSAPKCS1SHA256SignatureDescription : SignatureDescription
{
private const int PROV_RSA_AES = 24;
public RSAPKCS1SHA256SignatureDescription()
{
this.KeyAlgorithm = "System.Security.Cryptography.RSACryptoServiceProvider";
this.DigestAlgorithm = "System.Security.Cryptography.SHA256CryptoServiceProvider"; // use System.Security.Cryptography.SHA256Managed for .NET 4.5
this.FormatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureFormatter";
this.DeformatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureDeformatter";
}
public static void Register()
{
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
}
public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
{
var asymmetricSignatureDeformatter = (AsymmetricSignatureDeformatter)CryptoConfig.CreateFromName(DeformatterAlgorithm);
asymmetricSignatureDeformatter.SetKey(key);
asymmetricSignatureDeformatter.SetHashAlgorithm("SHA256");
return asymmetricSignatureDeformatter;
}
public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
{
var asymmetricSignatureFormatter = (AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm);
asymmetricSignatureFormatter.SetKey(key);
asymmetricSignatureFormatter.SetHashAlgorithm("SHA256");
return asymmetricSignatureFormatter;
}
}
}
Here are my two XML Files:
1.xml:
<node1>
<node2>
</node2>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>3nIr0blku+Nsu3FgibCxfQRGBtSmtZL4JGodmaU8blE= </DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>O3ihm7QwE/vh9VZ6CtdENAhB9Ve8jceATCgdJuaQkUHpPWxrG01TftUlrw9a/dQGfW48jJMPngwgcfqnbFspmEEGsBe1xoWQd6mdy2wVRBcQSjqdReNNzs0uQz3/1wPPk4Y2UO+fL+CVNzkIcMpne+t80c2eU4cHBa1WyL5qSlc=</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIICFDCCAX2gAwIBAgIQ2rStbEE1JJhHRLiuA4n/0jANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDEwtKQUxDT1JOLm1lMjAeFw0xNjAzMzAxODE1MDFaFw0zOTEyMzEyMzU5NTlaMBkxFzAVBgNVBAMTDkpBTENPUk5JSVMubWUyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLJEzyRjaHLfK6zrg1Xdx2yO34d5sbd7ajFFVmb3zPKtVGmuJlCBPsDTC84pzHBTywVVApi3U2UwtuCh96rQu5r3nYUT/E46CtexWiFATyh0M9+wD/h3hZj1CQ0YHTEZWznOWWIdbNRAcp99tGSALrwjH2rEJhGHHpVn7otCNmZQIDAQABo2AwXjATBgNVHSUEDDAKBggrBgEFBQcDATBHBgNVHQEEQDA+gBAgVyu7w3c59jEjiSh/vma+oRgwFjEUMBIGA1UEAxMLSkFMQ09STi5tZTKCEFvqkxy0Sd+mSgbqvsCEqKcwDQYJKoZIhvcNAQELBQADgYEAAcM6GlR3UpjIY4TWWuMiSyqiUiAGgg3JetiUXj1EVZ7TZVvyoVA1L/wd8ZHt+nZu1UtJmJ8sU7eu55TMVcX/xu7QoYsp6JtbPp5abLI6rnOCwDfyorrjM4S8Rm2RCO3PhL0NC9i9QBPfNV15FEbFpeqHZGw/xmyGzEv3EWxEESE=</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</node1>
2.xml:
<metadata>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>wc+6kgUoF9TE7KL1OQXm0EzAIYZuVVc6w3zOKsIY8yU= </DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>MDJn2QLG65LChsJOAN9zKmq4Br5JFSncaTMOmmsmL+DY4xcZt7e4VfI6/IehBkBUzDLeUJHWoE9sp7tVmArBiq/ZFm/ScB2/SRAAD+/NS0XxnxTPjvwu0JsmupNFJ364r/k31TYhI6TBmiCBIdZ6/3qV8LNPtS0iVrMkyhFw6L8=</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIICFDCCAX2gAwIBAgIQ2rStbEE1JJhHRLiuA4n/0jANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDEwtKQUxDT1JOLm1lMjAeFw0xNjAzMzAxODE1MDFaFw0zOTEyMzEyMzU5NTlaMBkxFzAVBgNVBAMTDkpBTENPUk5JSVMubWUyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLJEzyRjaHLfK6zrg1Xdx2yO34d5sbd7ajFFVmb3zPKtVGmuJlCBPsDTC84pzHBTywVVApi3U2UwtuCh96rQu5r3nYUT/E46CtexWiFATyh0M9+wD/h3hZj1CQ0YHTEZWznOWWIdbNRAcp99tGSALrwjH2rEJhGHHpVn7otCNmZQIDAQABo2AwXjATBgNVHSUEDDAKBggrBgEFBQcDATBHBgNVHQEEQDA+gBAgVyu7w3c59jEjiSh/vma+oRgwFjEUMBIGA1UEAxMLSkFMQ09STi5tZTKCEFvqkxy0Sd+mSgbqvsCEqKcwDQYJKoZIhvcNAQELBQADgYEAAcM6GlR3UpjIY4TWWuMiSyqiUiAGgg3JetiUXj1EVZ7TZVvyoVA1L/wd8ZHt+nZu1UtJmJ8sU7eu55TMVcX/xu7QoYsp6JtbPp5abLI6rnOCwDfyorrjM4S8Rm2RCO3PhL0NC9i9QBPfNV15FEbFpeqHZGw/xmyGzEv3EWxEESE=</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</metadata>
public static bool VerifyXmldsigSignature(FileInfo file, bool useSHA256 = false)
{
Logger.InfoFormat("Checking Digital Signature and Certificate on {0}", file.FullName);
bool validCertificate = false;
if (file == null)
{
Logger.Error("file argument is null");
throw new ArgumentNullException("file");
}
if (!file.Exists)
{
Logger.ErrorFormat("File {0} does not exist.", file.Name);
throw new ArgumentException("File must exist.", "file");
}
try
{
var document = new XmlDocument();
document.PreserveWhitespace = true; document.Load(file.FullName);
DateTime timestamp = DateTime.UtcNow;
bool respectCertExpiration = HasTimestamp(document);
if (respectCertExpiration)
{
timestamp = CheckXadesTimestamp(document);
}
var certificate = CheckXmldsigSignature(document);
validCertificate = ValidateCertificate(certificate, timestamp, respectCertExpiration);
Logger.InfoFormat("Digital Signature and Certificate passed verification on {0}", file.FullName);
}
catch (Exception ex)
{
string message = string.Format("{0} failed signature verification.", file.FullName);
throw;
}
Looking at the code, there are two places that I can find that might be an issue:
Certificate Validity.
Using CheckSignature() without any parameters requires the signing certificate to be signed by a trusted root authority. As you're already extracting the certificate that is part of the signature I suggest that for testing you change the call to
bool validSignature = signedXml.CheckSignature(certificate);
Note that you know only validates that the Xml is signed by the certificate info in the file. You have no validation that the signature actually is done by any specific party. I assume you are doing that in the calling function as it returns the certificate.
Whitespace
In the signing routine you set PreserveWhitespace=true. That means that the whitespace will be included in the hash calculation of the signature. Make sure you set PreserveWhitespace=true when you load the document for validation too (that part is not included in the posted code, so I don't know).
References
Finally, you're code is vulnerable to Xml Signature Wrapping attacks, because you are not properly checking the references of the signature. Please see this blog post of mine for examples.
Anders, thanks for your suggestions. I finally got my code to verify after several weeks of playing around with it, and I finally got something to work so I wanted to share it with you guys. The verify method is unchanged, and the Xades stuff is custom and not necessary to verify files signed with my code. Lastly, I used the following 2 urls as my starting point, but dozens of pages from google also helped:
https://blogs.msdn.microsoft.com/winsdk/2015/11/14/using-sha256-with-the-signedxml-class/
https://gist.github.com/sneal/f35de432115b840c4c1f#file-rsapkcs1sha256signaturedescription
private static Stream SignSHA256Stream(X509Certificate2 certificate, Stream stream)
{
if (certificate == null)
{
Logger.Error("certificate argument is null");
throw new ArgumentNullException("certificate");
}
if (stream == null)
{
Logger.Error("stream argument is null");
throw new ArgumentNullException("stream");
}
RSAPKCS1SHA256SignatureDescription.Register();
var document = new XmlDocument();
document.Load(stream);
XmlNode root = document.DocumentElement;
XmlNodeList nodeList = document.GetElementsByTagName("Signature", Xmldsigns);
// nodeList is actively updated so we delete element [0] until there are none left.
while (nodeList.Count > 0)
{
root.RemoveChild(nodeList[0]);
}
Reference reference = new Reference(string.Empty);
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
var keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(certificate));
SignedXml sxml = new SignedXml(document);
sxml.KeyInfo = keyInfo;
sxml.SigningKey = certificate.PrivateKey;
sxml.SignedInfo.SignatureMethod = Xmldsigns256;
sxml.AddReference(reference);
sxml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
sxml.ComputeSignature();
XmlElement xmlDigitalSignature = sxml.GetXml();
if (document.DocumentElement == null)
{
document.AppendChild(document.ImportNode(xmlDigitalSignature, true));
}
else
{
document.DocumentElement.AppendChild(document.ImportNode(xmlDigitalSignature, true));
}
if (document.FirstChild is XmlDeclaration)
{
document.RemoveChild(document.FirstChild);
}
MemoryStream outStream = new MemoryStream();
document.Save(outStream);
return outStream;
}
I got the camera function to work and it displays the image on the page like i asked it too. But is there a way to permanently save the image on your phone or somewhere else and then call it?
Thank you so much
Here's some code that works for me.
IFileAccess is my wrapper around System.IO.File functions such as file open, write, check if exsists. If you're making your own file service look up Xamarin.Forms.Labs.Resolver and how to use it; if you're using shared Forms project type you can access System.IO.File directly from the Forms project. Assuming that's clear, the following
var fileAccess = Resolver.Resolve<IFileAccess> ();
mediaPicker.SelectPhotoAsync (new CameraMediaStorageOptions{ MaxPixelDimension = 1024 })
.ContinueWith(t=>{
if (!t.IsFaulted && !t.IsCanceled) {
var mediaFile = t.Result;
var fileAccess = Resolver.Resolve<IFileAccess> ();
string imageName = "IMG_" + DateTime.Now.ToString ("yy-MM-dd_HH-mm-ss") + ".jpg";
// save the media stream to a file
fileAccess.WriteStream (imageName, mediaFile.Source);
// use the stored file for ImageSource
ImageSource imgSource = ImageSource.FromFile (fileAccess.FullPath (imageName));
imgInXAML.Source = imgSource;
}
});
Further detail on IFileAccess.
In your Forms project create an interface like this:
public interface IFileAccess
{
bool Exists (string filename);
string FullPath(string filename);
void WriteStream (string filename, Stream streamIn);
}
In your iOS or Android or Shared project add a class FileAccess that implements IFileAccess:
public class FileAccess : IFileAccess
{
public bool Exists (string filename)
{
var filePath = GetFilePath (filename);
if (File.Exists (filePath)) {
FileInfo finf = new FileInfo (filePath);
return finf.Length > 0;
} else
return false;
}
public string FullPath (string filename)
{
var filePath = GetFilePath (filename);
return filePath;
}
static string GetFilePath (string filename)
{
var documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
var filePath = Path.Combine (documentsPath, filename);
return filePath;
}
public void WriteStream (string filename, Stream streamIn)
{
var filePath = GetFilePath (filename);
using (var fs = File.Create (filePath)) {
streamIn.CopyTo (fs);
}
}
}
If you're already using Xamarin.Forms.Labs.Resolver then add only the line to register the service, otherwise in your iOS or Android project find a call to Forms.Init() and right before it add
var resolverContainer = new SimpleContainer ();
resolverContainer.Register<IFileAccess> (t => new FileAccess ()); // maybe just this line
Resolver.SetResolver (resolverContainer.GetResolver ());