After upgrading to Visual Studio 2019 I found that my existing Xamarin application wasn't able to establish TCP connections anymore.
After some research I found that Visual Studio 2019 also came with MSBuild 16 when VS2017 had MSBuild 15.
before I was using this piece of code after generating a certificate and key pair for my RSA system cryptography:
var cert = new X509Certificate2(DotNetUtilities.ToX509Certificate(bcCert))
{ PrivateKey = DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)keyPair.Private) };
With Visual Studio 2019 you can't set the private key. This can be seen in the decompiled X509Certificate2.cs in
C:\ProgramFiles(x86)\MicrosoftVisualStudio\2019\Professional\Common7\IDE\ReferenceAssemblies\Microsoft\Framework\MonoAndroid\v1.0\System.dll
Following this repo I found a ConvertBouncyCert method that would return an X509Certificate2 wrapper around my generated X509Certificate which would have the private key attached but I was still getting an unable to decode exception.
Jeremy's library contains this code for converting an X509Certificate into an X509Certificate2:
var pkcs12Store = new Pkcs12Store();
var certEntry = new X509CertificateEntry(BouncyCert);
pkcs12Store.SetCertificateEntry(BouncyCert.SerialNumber.ToString(), certEntry);
pkcs12Store.SetKeyEntry(BouncyCert.SerialNumber.ToString(),
new AsymmetricKeyEntry(KeyPair.Private), new[] { certEntry });
X509Certificate2 keyedCert;
using (MemoryStream pfxStream = new MemoryStream()) {
pkcs12Store.Save(pfxStream, null, new SecureRandom());
pfxStream.Seek(0, SeekOrigin.Begin);
keyedCert = new X509Certificate2(pfxStream.ToArray(), "", X509KeyStorageFlags.Exportable);
}
return keyedCert;
You need to create a Pkcs12StoreBuilder object and set the DER encoding to true.
var pkcs12StoreBuilder = new Pkcs12StoreBuilder();
pkcs12StoreBuilder.SetUseDerEncoding(true);
var pkcs12Store = pkcs12StoreBuilder.Build();
var certificateEntry = new X509CertificateEntry(bouncyCert);
This article does a great job at explaining DER and all the components around it within cryptography and RSA systems.
Related
I received from a client public certificate and private RSA key, as follows (only partially displayed here):
-----BEGIN CERTIFICATE-----
MIIFKDCCAxACAQEwDQYJKoZIhvcNAQELBQAwbjELMAkGA1UEBhMCVVMxETAPBgNV
BAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApDbG91ZFF1
YW50MSUwIwYJKoZIhvcNAQkBFhZjcWFpb3BzQGNsb3VkcXVhbnQuY29tMB4XDTIw
MDkyMzIwMTgyN1oXDTQwMDkxODIwMTgyN1owRjELMAkGA1UEBhMCVVMxETAPBgNV
iESEKmYvylUwce7TcOuVnLtufyXxr8egu43jPvWDHsK0QvhMbx0q2KvyxGneQJ5E
...........
U0oIrq7M0qZTAf1BXEw9wgfQlIKfLzWDbIYKIg==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAuxHk8lBZaqRTzhi/jvlj59pehTkK/u2fVHLuHWZPGOvPiAjq
HqrAgM1urPpmQPC2QuWObmhvQ1uluo/tq6V56WZNUEYALZnXhGvVNrvnYfoFooI0
F+1dJI2xQ8AC11Khinj+yAPtKymMhZFOHzQaFnGvjhKWTn/I0MaoJc+TQ8JKbDQ0
ycvopM2finujmIb62cxxhkhkEC5T+yMUJ8MbCnfmWpYux/oU2CXSHrnPympCbx7x
cReH0BeZEZPMI7+1Yi7U+XKGc7RP+zt9AoIBAQDE0BZb3WfertNqmyj9TF73VAwq
SDtSa6MTC8bOdtQewCz9/zC13MSI+jZGRDKSh7nxNL+bgM0OgmM6n/5B/61SIRjM
hswgOU9AHewIFSB/5C/ZcxWqM+PrgYXXYfOl9ZeWs1x+YRKuqk/CW/Z2rHJXykNx
.............
czG95J+2TWdGAjPuFLA596PRXT5KN2ITOWXUym3UksHmonbJ9om+k0ckPr4J
-----END RSA PRIVATE KEY-----
Initially, I scanned many postings here and realized that the easiest way to combine the puplic PEM certificate with private RSA key (PEM format) is by using .NET 5:
// Needs .NET 5, that is .NET Core and VS2019 16.8 or higher
X509Certificate2 X509Cert = X509Certificate2.CreateFromPemFile("cert.cer", "cert.key");
X509Certificate2 cert = new X509Certificate2(mX509Cert.Export(X509ContentType.Pfx, "12345678"), "12345678");
This worked great.
However, later on I realized that the type of project I am targeting (VSTO Excel Add-In) is not supporting .NET 5 yet...
Therefore, I changed the above code to the following, (which also worked) not realizing that it also requires .NET 5...
X509Certificate2 pubOnly = new X509Certificate2("cert.cer");
RSA rsa = RSA.Create();
rsa.ImportRSAPrivateKey(keyBuffer, out _);
X509Certificate2 pubPrivEphemeral = pubOnly.CopyWithPrivateKey(rsa);
X509Certificate2 cert = new X509Certificate2(pubPrivEphemeral.Export(X509ContentType.Pfx, "12345678"), "12345678");
Then when I finally switched to .NET 4.7.2 and now 4.8 I was looking for compatible way to do the same, and tired several methods offered here, but in vain, none did not work - they had complex routines that threw exceptions...
So I am trying now BouncyCastle that helped a lot in the past and came up with this code:
string cerFilePath = Path.Combine(InstallDir, "cert.cer");
X509Certificate2 dotnetCertificate2 = new X509Certificate2(cerFilePath);
string keyFilePath = Path.Combine(InstallDir, "cert.key");
var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(File.OpenText(keyFilePath));
var pemObject = pemReader.ReadObject();
var rsa = DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)pemObject);
Unfortunately, the last line throws exception - there is something incompatible here and I do not know what it is... The exception message states:
"Unable to cast object of type 'Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair' to type 'Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters'."
So if anyone can either correct me with the above BouncyCastle code or show me pure .NET 4.6 - 4.8 code - I'd really appreciate.
EDIT:
So I did find another code from here
private X509Certificate2 CreateCertWithKey()
{
using (Log.VerboseCall())
{
X509Certificate2 x509Cert = null;
try
{
string cerFilePath = Path.Combine(InstallDir, "cert.cer");
using (TextReader tr = new StreamReader(cerFilePath))
{
publicPemCert = tr.ReadToEnd();
}
string keyFilePath = Path.Combine(InstallDir, "cert.key");
using (TextReader tr = new StreamReader(keyFilePath))
{
privatePemKey = tr.ReadToEnd();
}
var keyPair = (AsymmetricCipherKeyPair)new PemReader(new StringReader(privatePemKey)).ReadObject();
var cert = (Org.BouncyCastle.X509.X509Certificate)new PemReader(new StringReader(publicPemCert)).ReadObject();
var builder = new Pkcs12StoreBuilder();
builder.SetUseDerEncoding(true);
var store = builder.Build();
var certEntry = new X509CertificateEntry(cert);
store.SetCertificateEntry("", certEntry);
store.SetKeyEntry("", new AsymmetricKeyEntry(keyPair.Private), new[] { certEntry });
byte[] data;
using (var ms = new MemoryStream())
{
//store.Save(ms, Array.Empty<char>(), new SecureRandom());
data = ms.ToArray();
x509Cert = new X509Certificate2(data);
}
}
catch(Exception ex)
{
Log.Verbose(ex);
}
return x509Cert;
}
}
It runs without problem but with the generated certificate my HttpWebRequest does not work, claiming that TSL/SSL connection cannot be created (and I tries 1.1, 1.2, and 1.3, although I recall that just Tls negotiates the version by itself...
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
The .NET 5 code ran without a problem with exactly the same code for HttpWebRequest...
Just came across this while working through similar issues and I found a way to create the X509Certificate2 object that includes the private key (which I use for XML Signing). It requires that you create a PFX record using the public/private keys, I used OpenSSL:
openssl pkcs12 -export -inkey private-key.pem -in cert.pem -out cert.pfx
You can either open just instantiate the instance directly with the file name:
var cert = new X509Certificate2(filePath);
Or if you have already opened the file somewhere and stored it in base64 format, you can use the bytes:
var bytes = Convert.FromBase64String(pfx_base64);
var cert = new X509Certificate2(bytes);
A lot of credit for this goes to reading Scott Brady's blog.
I am fetching my certificate from Azure Key Vault using GetSecretAsync() method and then I am expecting to get the byte[] of the private key and the certificate eventually.
I have my application in .netcore3.1
This is how my code looks like :
var certWithPrivateKey = Client.GetSecretAsync(ConfigurationSettings.AppSettings["AKVEndpoint"], ConfigurationSettings.AppSettings["CertName"]).GetAwaiter().GetResult();
var privateKeyBytes = Convert.FromBase64String(certWithPrivateKey.Value);
X509Certificate2 x509Certificate = new X509Certificate2(privateKeyBytes);
var privateKey = x509Certificate.GetRSAPrivateKey() as RSA;
I get a valid privateKey of type RSACng, but any operation (tried ExportRSAPrivateKey()) on that throws an error of "'privateKey.ExportRSAPrivateKey()' threw an exception of type 'Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException'" and "The requested operation is not supported."
I am not sure how to proceed next here to get the byte[] of the private key and certificate.
Since you do actually seem to need to export: Your current code doesn't load the private key as exportable, so it can't be exported. The fix is to assert exportability:
X509Certificate2 x509Certificate =
new X509Certificate2(privateKeyBytes, "", X509KeyStorageFlags.Exportable);
If that's not enough, then you're encountering the difference between CAPI exportability and CNG exportability (Windows older, and newer, crypto libraries). If the private key from a PFX/PKCS#12 gets loaded into CNG it's only "encrypted exportable", but ExportParameters is plaintext-export.
There's a workaround, though... export it encrypted, then import that somewhere else with a more flexible export policy, then export again.
This snippet uses the .NET Core 3.0+ ExportPkcs8PrivateKey() method, since that's the format you want your data in, and new .NET 5 PemEncoding class to simplify turning the DER encoded output into PEM+DER output. If your exporter is on .NET Framework, this is a more complex problem. For .NET Standard 2.0 there's not really a clean solution (reflect call the methods for .NET Core/.NET 5, otherwise use the Windows-specific version for .NET Framework?).
byte[] pkcs8PrivateKey;
using (RSA privateKey = x509Certificate.GetRSAPrivateKey())
{
pkcs8PrivateKey = ExportPrivateKey(privateKey);
}
File.WriteAllText(
"tls.cer",
new string(PemEncoding.Write("CERTIFICATE", x509Certificate.RawData));
File.WriteAllText(
"tls.key",
new string(PemEncoding.Write("PRIVATE KEY", pkcs8PrivateKey));
...
private static byte[] ExportPrivateKey(RSA privateKey)
{
try
{
// If it's plaintext exportable, just do the easy thing.
return privateKey.ExportPkcs8PrivateKey();
}
catch (CryptographicException)
{
}
using (RSA exportRewriter = RSA.Create())
{
// Only one KDF iteration is being used here since it's immediately being
// imported again. Use more if you're actually exporting encrypted keys.
exportRewriter.ImportEncryptedPkcs8PrivateKey(
"password",
privateKey.ExportEncryptedPkcs8PrivateKey(
"password",
new PbeParameters(
PbeEncryptionAlgorithm.Aes128Cbc,
HashAlgorithmName.SHA256,
1)),
out _);
return exportRewriter.ExportPkcs8PrivateKey();
}
}
I am issuing (with own Certificate Authority) a certificate in c# code (based on: .NET Core 2.0 CertificateRequest class)
In CertificateRequest, unable to add Certificate ocsp Authority Information Access (oid: 1.3.6.1.5.5.7.1.1) and certificate policies (oid: 2.5.29.32) extensions (similar results of: Authority Information Access extension)
I do not want to use external libraries, perhaps only ASN1 libraries if needed.
Anyone can help with c# code to add these extensions as I didn't find any suitable types in .Net?
certificateRequestObject.CertificateExtensions.Add(
new X509Extension("2.5.29.32", **[Authority Information Access text] to RawData?** , false));
[Authority Information Access text]
Authority Information Access 1.3.6.1.5.5.7.1.1
[1]Authority Info Access
Access Method=On-line Certificate Status Protocol (1.3.6.1.5.5.7.48.1)
Alternative Name:
URL=example.org
[2]Authority Info Access
Access Method=Certification Authority Issuer (1.3.6.1.5.5.7.48.2)
Alternative Name:
URL=example.org
Disclaimer: I do strongly believe that you should not roll own crypto/CA and use standard CA software to issue certificate since they are intended to solve this problem.
There is no built-in support for ASN encoding/decoding in .NET (including .NET Core), you have to use 3rd party libraries.
For ASN encoding you can use ASN.1 library I developed: Asn1DerParser.NET
And use for your particular case will be:
Byte[] encodedData = new Asn1Builder()
.AddSequence(x => x.AddObjectIdentifier(new Oid("1.3.6.1.5.5.7.48.1")
.AddImplicit(6, Encoding.ASCII.GetBytes("http://ocsp.example.com"), true))
.GetEncoded();
var extension = new X509Extension("1.3.6.1.5.5.7.1.1", encodedData, false);
and add extension item to your request. If you need to add more URLs, then add more SEQUENCE elements:
Byte[] encodedData = new Asn1Builder()
.AddSequence(x => x.AddObjectIdentifier(new Oid("1.3.6.1.5.5.7.48.1")
.AddImplicit(6, Encoding.ASCII.GetBytes("http://ocsp1.example.com"), true))
.AddSequence(x => x.AddObjectIdentifier(new Oid("1.3.6.1.5.5.7.48.1")
.AddImplicit(6, Encoding.ASCII.GetBytes("http://ocsp2.example.com"), true))
.GetEncoded();
var extension = new X509Extension("1.3.6.1.5.5.7.1.1", encodedData, false);
I needed to add an AIA (Authority Information Access) extension using dotnet also. It is super cool #Crypt32 shared the code from Asn1DerParser.NET. It made me curious. I started looking at other code like BouncyCastle and I didn't see any code that did the same thing. There is a AuthorityInformationAccess class, but I couldn't find any tests that created an AIA extension. Maybe the implementation isn't finished. I could dig further but I instead looked at the dotnet runtime code. While of course there isn't a dotnet AIA builder, there is a SubjectAlternativeNameBuilder]2 I could learn from. So, I did just that. Essensually it uses the AsnWriter to encapsulate the mechanics of building an ASN1 Sequence. Below is an example where I add two certificate authority issuers. Next steps would be to encapuslate this in an AIA Builder but here is an example.
The parts that I struggled with were ensuring when to call writer.Encode and writer.WriteEncodedValue. After an hour or so everything made sense.
#Guru_07, I believe this allows you to avoid third party code. Although it has been some time since you posted your question.
List<byte[]> encodedUrls = new List<byte[]>();
List<byte[]> encodedSequences = new List<byte[]>();
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.WriteObjectIdentifier("1.3.6.1.5.5.7.48.2");
encodedUrls.Add(writer.Encode());
writer = new AsnWriter(AsnEncodingRules.DER);
writer.WriteCharacterString(
UniversalTagNumber.IA5String,
"http://ocsp.example.com",
new Asn1Tag(TagClass.ContextSpecific, 6)
);
encodedUrls.Add(writer.Encode());
writer = new AsnWriter(AsnEncodingRules.DER);
using (writer.PushSequence())
{
foreach (byte[] encodedName in encodedUrls)
{
writer.WriteEncodedValue(encodedName);
}
}
encodedSequences.Add(writer.Encode());
encodedUrls = new List<byte[]>();
writer = new AsnWriter(AsnEncodingRules.DER);
writer.WriteObjectIdentifier("1.3.6.1.5.5.7.48.2");
encodedUrls.Add(writer.Encode());
writer = new AsnWriter(AsnEncodingRules.DER);
writer.WriteCharacterString(
UniversalTagNumber.IA5String,
"http://ocsp2.example.com",
new Asn1Tag(TagClass.ContextSpecific, 6)
);
encodedUrls.Add(writer.Encode());
writer = new AsnWriter(AsnEncodingRules.DER);
using (writer.PushSequence())
{
foreach (byte[] encodedName in encodedUrls)
{
writer.WriteEncodedValue(encodedName);
}
}
encodedSequences.Add(writer.Encode());
writer = new AsnWriter(AsnEncodingRules.DER);
using (writer.PushSequence())
{
foreach (byte[] encodedSequence in encodedSequences)
{
writer.WriteEncodedValue(encodedSequence);
}
}
var ext = new X509Extension(
new Oid("1.3.6.1.5.5.7.1.1"),
writer.Encode(),
false);
I am trying to sign some data using a certificate private key. The issue I'm finding is that the signature is different depending on if I'm executing it locally or on a server.
I'm using the following code as a test, running under the same user both locally and on the server:
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace TestSignature
{
class Program
{
static void Main(string[] args)
{
var key = SigningKeyFromCertificate(StoreName.My, StoreLocation.LocalMachine, X509FindType.FindByThumbprint, "thumbprint");
var alg = CryptoConfig.MapNameToOID("SHA256");
var data = Encoding.UTF8.GetBytes("test");
var sig = key.SignData(data, alg);
Console.WriteLine(Convert.ToBase64String(sig));
}
private static RSACryptoServiceProvider SigningKeyFromCertificate(StoreName storeName, StoreLocation storeLocation, X509FindType findType, string findValue)
{
X509Store store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadOnly);
var certs = store.Certificates.Find(findType, findValue, false);
if (certs?.Count > 0)
{
var cert = certs[0];
if (cert.HasPrivateKey)
{
// Force use of Enhanced RSA and AES Cryptographic Provider to allow use of SHA256.
var key = cert.PrivateKey as RSACryptoServiceProvider;
var enhanced = new RSACryptoServiceProvider().CspKeyContainerInfo;
var parameters = new CspParameters(enhanced.ProviderType, enhanced.ProviderName, key.CspKeyContainerInfo.UniqueKeyContainerName);
return new RSACryptoServiceProvider(parameters);
}
else
{
throw new Exception($"No private key access to cert '{findValue}.'");
}
}
else
{
throw new Exception($"Cert '{findValue}' not found!");
}
}
}
}
Locally, I get the following signature:
YUjspKhLl7v3u5VQkh1PfHytMTpEtbAftxOA5v4lmph3B4ssVlZp7KedO5NW9K5L222Kz9Ik9/55NirS0cNCz/cDhEFRtD4daJ9qLRuM8oD5hCj6Jt9Vc6WeS2he+Cqfoylnv4V9plfi1xw8y7EyAf4C77BGkXOdyP5wyz2Xubo=
On the server, I get this one instead:
u1RUDwbBlUpOgNNkAjXhYEWfVLGpMOa0vEfm6PUkB4y9PYBk1lDmCAp+488ta+ipbTdSDLM9btRqsQfZ7JlIn/dIBw9t5K63Y7dcDcc7gDLE1+umLJ7EincMcdwUv3YQ0zCvzc9RrP0jKJManV1ptQNnODpMktGYAq1KmJb9aTY=
Any idea of what could be different? I would think, with the same certificate, the same code, and the same data, the signature should be the same.
(The example is written in C# 4.5.2.)
You have some code to reopen the CAPI key handle under PROV_RSA_AES:
// Force use of Enhanced RSA and AES Cryptographic Provider to allow use of SHA256.
var key = cert.PrivateKey as RSACryptoServiceProvider;
var enhanced = new RSACryptoServiceProvider().CspKeyContainerInfo;
var parameters = new CspParameters(
enhanced.ProviderType,
enhanced.ProviderName,
key.CspKeyContainerInfo.UniqueKeyContainerName);
return new RSACryptoServiceProvider(parameters);
But key.CspKeyContainerInfo.UniqueKeyContainerName isn't the name of the key (it's the name of the file on disk where the key lives), so you're opening a brand new key (you're also generating a new ephemeral key just to ask what the default provider is). Since it's a named key it persists, and subsequent application executions resolve to the same key -- but a different "same" key on each computer.
A more stable way of reopening the key is
var cspParameters = new CspParameters
{
KeyContainerName = foo.CspKeyContainerInfo.KeyContainerName,
Flags = CspProviderFlags.UseExistingKey,
};
(since the provider type and name aren't specified they will use the defaults, and by saying UseExistingKey you get an exception if you reference a key that doesn't exist).
That said, the easiest fix is to stop using RSACryptoServiceProvider. .NET Framework 4.6 (and .NET Core 1.0) have a(n extension) method on X509Certificate2, GetRSAPrivateKey(), it returns an RSA (which you should avoid casting) which is usually RSACng (on Windows), but may be RSACryptoServiceProvider if only CAPI had a driver required for a HSM, and may be some other RSA in the future. Since RSACng handles SHA-2 better there's almost never a need to "reopen" the return object (even if it's RSACryptoServiceProvider, and even if the type isn't PROV_RSA_AES (24), that doesn't mean the HSM will fail to do SHA-2).
i have a project in C# where i have to sign the files making them .p7m with envelope cryptographic CAdES, i made it with BouncyCastle.
Now, the signing process it works perfectly on Windows 7 , 8 , 10 , but when i tested it on windows xp , there was an error
This is the function that sign files
SHA256Managed hashSha256 = new SHA256Managed();
byte[] certHash = hashSha256.ComputeHash(cert.RawData);
EssCertIDv2 essCert1 = new EssCertIDv2(new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier("2.16.840.1.101.3.4.2.1"), certHash);
SigningCertificateV2 scv2 = new SigningCertificateV2(new EssCertIDv2[] { essCert1 });
Org.BouncyCastle.Asn1.Cms.Attribute CertHAttribute = new Org.BouncyCastle.Asn1.Cms.Attribute(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAASigningCertificateV2, new DerSet(scv2));
Asn1EncodableVector v = new Asn1EncodableVector();
v.Add(CertHAttribute);
Org.BouncyCastle.Asn1.Cms.AttributeTable AT = new Org.BouncyCastle.Asn1.Cms.AttributeTable(v);
CmsSignedDataGenWithRsaCsp cms = new CmsSignedDataGenWithRsaCsp();
Org.BouncyCastle.Crypto.AsymmetricKeyParameter keyParameter = null;
dynamic rsa = (RSACryptoServiceProvider)cert.PrivateKey;
Org.BouncyCastle.X509.X509Certificate certCopy = DotNetUtilities.FromX509Certificate(cert);
cms.MyAddSigner(rsa, certCopy, keyParameter, "1.2.840.113549.1.1.1", "2.16.840.1.101.3.4.2.1", AT, null);
ArrayList certList = new ArrayList();
certList.Add(certCopy);
Org.BouncyCastle.X509.Store.X509CollectionStoreParameters PP = new Org.BouncyCastle.X509.Store.X509CollectionStoreParameters(certList);
Org.BouncyCastle.X509.Store.IX509Store st1 = Org.BouncyCastle.X509.Store.X509StoreFactory.Create("CERTIFICATE/COLLECTION", PP);
cms.AddCertificates(st1);
FileInfo File__1 = new FileInfo(NomeFile);
CmsProcessableFile file__2 = new CmsProcessableFile(File__1);
CmsSignedData Firmato = cms.Generate(file__2, true);
byte[] Encoded = Firmato.GetEncoded();
RisFirma = "";
return Encoded;
That is the windows xp error
Help is much appreciated. Kind Regards
It looks like the SHA-256 hash or the OID of the SHA-256. Try and update XP to the latest service pack; XP is old, so it may not support all algorithms out of the box. The idea of creating signatures on XP machines should be avoided; you should not create security on a platform without support or bug fixes.
I solved the problem, it seems that the latest CSP doesn't work with windows xp, i tryed with another CSP and the function start to work again.
bye