Mandatory Trust Chains are missing in PKCS#12 certificate - pkcs#12

How to include all CAs Trust Chains (Chain of Trust) in PKCS#12 certificate in C#.NET? I need the solution right from the scratch. I can create a X509 certificate using DOT NET libraries. But I don't know how to include all CAs Trust Chains in PKCS#12 cert format. The trust chains are : Entrust->My CA->My Issuing CA->My Certificate.
Please help me experts.

At first I want to say, I have not worked in C# for some time so at first I want to explain in Java. If you use bouncy castle and the certificates then you can easily build a certificate chain and simply insert the chain. This is a sample java code.
KeyStore store = KeyStore.getInstance("PKCS12", "BC");
store.load(null, null);
store.setKeyEntry(keyAlias, privKey, null, chain);
FileOutputStream fOut = new FileOutputStream(fileLocation);
store.store(fOut, password.toCharArray());
Now, the certificate chain object chain needs to have all the chain certificates. Like:
Certificate[] chain = new Certificate[]{(Certificate)childCertificate, (Certificate)subCaCertificate, (Certificate)caCertificate};
So, as you can see, the chain should be start from child to mother. Many only insert the child certificate, so full chain does not include during export.
Now, for C#, I want to write some code using bouncycastle. Forgive me if some mistakes happen as I said that, I am not working in C#.
Sample C# Code:
Pkcs12Store pkcs12Store = new Pkcs12Store();
AsymmetricKeyParameter privateKey = ......
X509CertificateEntry[] certEntry = new X509CertificateEntry[certChain.Count];
for ( int k = 0; k < certChain.Count; k++ )
{
certEntry[k] = new X509CertificateEntry(certChain[k]);
}
pkcs12Store.SetKeyEntry (alias, new AsymmetricKeyEntry(privateKey), certEntry);
MemoryStream memoryStream = new MemoryStream ();
pkcs12Store.Save ( memoryStream, password, GetRandom ( 16 ) );
byte[] data = memoryStream.GetBuffer ();
data = Pkcs12Utilities.ConvertToDefiniteLength (data, password);
Here, the certEntry object will contain all the certificate chain.

Related

Flutter add self signed certificate from asset folder

My server provides a Self Signed certificate when calling its HTTPS API. I have the certificate file in the asset folder and referenced its path in pubspec.yaml
I have tried passing the certificate to SecurityContext and then using that context to create an HttpClient. But the way I'm passing the certificate to SecurityContext is not working. Here is the code:
Future<ByteData> getFileData(String path) async {
return await rootBundle.load(path);
}
void initializeHttpClient() async {
try {
Future<ByteData> data = getFileData('assets/raw/certificate.crt');
await data.then((value) {
var context = SecurityContext.defaultContext;
context.useCertificateChainBytes(value.buffer.asInt8List());
client = HttpClient(context: context);
});
} on Exception catch (exception) {
print(exception.toString());
}
}
The SecurityContext has two methods:
1) useCertificateChain() this accepts a file path. But when I give the path of the file in my asset folder ('assets/raw/certificate.crt'). It says file not found.
2) useCertificateChainBytes() the above code is using this method. But this also gives me error like (unexpected end of file).
Solution as of now
I am bypassing it using client.badCertificateCallback = (X509Certificate cert, String host, int port)=> true;.
but I'd like to make it work with certificate
It's not clear from your question what the role of the self-signed certificate is. Based on your work around, I assume that it's a server side certificate that you have installed in the HTTPS server. (It's not a client side certificate that you would like to pass to the server.)
So, what you need to do is to get the Dart HttpClient to trust that certificate, which will be passed to it by the server as part of the TLS handshake. (By setting the callback you have made the client trust any certificate, not just your server's.)
To set the trusted certificate use setTrustedCertificatesBytes in place of useCertificateChainBytes (which you would use if your certificate was a client side one).
You cannot access assets directly as Files as they are bundled by the build. You are doing the right thing by loading them and using the ...Bytes methods. You could improve the readability of your code like this (removing the then). Also, note the subtle change to Uint8List
ByteData data = await rootBundle.load('assets/raw/certificate.crt');
SecurityContext context = SecurityContext.defaultContext;
context.setTrustedCertificatesBytes(data.buffer.asUint8List());
client = HttpClient(context: context);

Add password protection to PDF using Rotativa.MVC

Does Rotativa.MVC support pdf encryption with password? I wasn't able to find any reference about it.
There is no option to add a password in Rotativa.MVC.
You need to generate your pdf via html and add owner password, user password after that.
Basically you will need another piece of software to encrypt that pdf file or to develop that piece of software by yourself.
Using something like: https://github.com/itextsharper/iTextSharp-4.1.6/blob/master/iTextSharp/text/pdf/PdfEncryptor.cs you'll be able to do the following:
Encrypt(PdfReader reader, Stream os, byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits, Hashtable newInfo)
using (var input = new FileStream("rotativa_generated.pdf", FileMode.Open, FileAccess.Read, FileShare.Read))
using (var output = new FileStream("rotativa_generated_encrypted.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
var reader = new PdfReader(input);
PdfEncryptor.Encrypt(reader, output, true, "userPassword", "ownerPassword", PdfWriter.ALLOW_PRINTING);
}
Users need only userPassword to get access.
Or you can migrate to something like https://github.com/mstamy2/PyPDF2 just for encryption. (free for commercial use as far as i know)

WIF: ID1014: The signature is not valid. The data may have been tampered with

We've built a Relying Party application based on the Windows Identity Foundation. We followed the advice in Vittorio's book and created a custom set of cookie transforms to use RSA to encrypt/sign the token.
private void OnServiceConfigurationCreated( object sender, ServiceConfigurationCreatedEventArgs e )
{
List<CookieTransform> sessionTransforms = new List<CookieTransform>( new CookieTransform[]
{
new DeflateCookieTransform(),
new RsaEncryptionCookieTransform( e.ServiceConfiguration.ServiceCertificate ),
new RsaSignatureCookieTransform( e.ServiceConfiguration.ServiceCertificate )
} );
SessionSecurityTokenHandler sessionHandler =
new SessionSecurityTokenHandler( sessionTransforms.AsReadOnly() );
e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace( sessionHandler );
}
We configured a in the web.config.
<microsoft.identityModel>
<service>
<serviceCertificate>
<certificateReference x509FindType="FindByThumbprint" findValue="C7FD338059CCB374798923A915BC91B718814A8E" storeLocation="LocalMachine" storeName="TrustedPeople" />
</serviceCertificate>
</service>
</microsoft.identityModel>
I know the code in the OnServiceConfigurationCreated is executing because if I put a garbage thumbprint value into the config file the OnServiceConfigurationCreated throws an exception.
Unfortunately we are frequently getting the following exception showing up in our logs.
System.Security.Cryptography.CryptographicException: ID1014: The signature is not valid. The data may have been tampered with.
at Microsoft.IdentityModel.Web.RsaSignatureCookieTransform.Decode(Byte[] encoded)
at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound)
at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver)
at Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie)
at Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken)
at Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
We believe this exception is causing other problems in the system but can't figure out why it's occurring. We have three web servers and we've triple-checked that they are all configured to use the same certificate thumbprint and that the certificate is installed in the same place on all three servers.
We are also using a custom SessionAuthenticationModule to handle sliding session expiration. I thought that maybe when that code (below) was reissuing the cookie it might be using a different encryption/signing approach but I'm pretty sure I've tested it and that doesn't seem to be the case. I'm including it only in the interest of full disclosure.
void CustomSessionAuthenticationModule_SessionSecurityTokenReceived( object sender, SessionSecurityTokenReceivedEventArgs e )
{
DateTime now = DateTime.UtcNow;
DateTime validFrom = e.SessionToken.ValidFrom;
DateTime validTo = e.SessionToken.ValidTo;
double tokenLifetime = (validTo - validFrom).TotalMinutes;
SessionAuthenticationModule sam = sender as SessionAuthenticationModule;
if( now < validTo && now > validFrom.AddMinutes( tokenLifetime / 2 ) )
{
e.SessionToken = sam.CreateSessionSecurityToken(
e.SessionToken.ClaimsPrincipal, e.SessionToken.Context,
now, now.AddMinutes( tokenLifetime ), e.SessionToken.IsPersistent );
e.ReissueCookie = true;
}
}
From what we can tell we've done everything the docs/blogs/etc have said but we're still getting this exception. Any tips/pointers/educated guesses would be helpful at this point.
You might want to check the total size of cookie data your application sets. If you include lots of claims, the cookies grow accordingly unless you use session mode. E.g. Safari has a 4K limit on total cookie data size. If you break this limit you'd start losing cookies, which could mean you'd lose a cookie with part of the signature.
As a side note, if you can move to WIF 4.5 you have the option of using the MachineKeySessionSecurityTokenHandler instead of doing the certficate based cookie encryption.

ASP.Net MVC & WebAPI encryption

I want to utilise some form of "simple" encryption that is reasonably secure but very low friction in terms of impact on development process.
Supposing I own both sides of the conversation in a client <> web service situation. My application is a windows phone/win8/silverlight/desktop app and the server is ASP.Net MVC or WebAPI.
In my mind, I want something as simple as:-
<security encryption="off|sometype|someothertype">
<privatekey>12345MyKey54321</privatekey>
</security>
as some form of configuration parameter on both the client and server. Additionally an authentication routine will return and store some form of public key.
Doing so will enable the 'encryption mode' and result in any http requests being encrypted & hashed in the selected manner using the provided keys. The end result being anything sniffed on the local, proxy or remote machines would not be able to view the data without the key and decryption method. On the server, data is decrypted using the same key before hitting controller actions.
Other than swapping out HttpRequest/WebClient calls for something like EncryptedHttpRequest and adding the appropriate hook on the MVC/WebAPI side of things, all other client code and controller actions would be ignorant to the fact the data was encrypted.
Am I missing something or could setup not be this simple? As far as I have searched there is nothing that offers this level of simplicity so I figure I'm missing some gaping flaw in my logic?
All you are looking for can be achieved by simply using HTTPS. Just buy a certificate (or use a self-signed certificate) and there is your encryption.
Do not re-invent the wheel.
I've done this successfully. It isn't too difficult and works well. I use it for activating a license for a product. The most important thing is that your truly control the client and server - no one can extract your private key from your code on the client.
Step 1: Create an MVC controller action method that takes no arguments:
[HttpPost] public ActionResult Activate() { ... }
Step 2: In the controller just use the HttpRequest.InputStream to get ahold of the bytes sent from the client.
var stream = this.HttpContext.Request.InputStream;
Step 3: Create a CryptoStream to deserialize.
I've included creating both encryption and decryption examples here. The sharedSecret is a byte[] of sufficient length (512 bytes) of random bytes - this is what you protect!
public CryptoStream CreateEncryptionStream(Stream writeStream)
{
TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();
PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null);
CryptoStream cryptoStream = new CryptoStream(writeStream, cryptoProvider.CreateEncryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Write);
return cryptoStream;
}
public CryptoStream CreateDecryptionStream(Stream readStream)
{
TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();
PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null);
CryptoStream cryptoStream = new CryptoStream(readStream, cryptoProvider.CreateDecryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Read);
return cryptoStream;
}
Step 4: Use your CryptoStream another stream reader to decrypt.
I use an XmlReader so that all my existing serialization code can work either in the clear (when reading/writing to disk or database on the server) or encrypted (when transmitting).
using (var reader = XmlReader.Create(decryptionStream, settings)) { ... }
Step 5: Formulate a secure response in your controller.
This is doing the reverse of Steps 1-4 to encrypt your response object. Then you just write your encrypted response to a memory stream and return it as a File result. Below, I've shown how I do this for my license response object.
var responseBytes = GetLicenseResponseBytes(licenseResponse);
return File(responseBytes, "application/octet-stream");
private byte[] GetLicenseResponseBytes(LicenseResponse licenseResponse)
{
if (licenseResponse != null)
{
using (MemoryStream memoryStream = new MemoryStream())
{
this._licenseResponseSerializer.Write(memoryStream, licenseResponse);
return memoryStream.ToArray();
}
}
return null;
}
Step 6: Implement your client request response.
You can use HttpWebRequest or the WebClient classes to formulate the request. Here's a couple of examples from the code I use.
byte[] postBytes = GetLicenseRequestBytes(licenseRequest);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(licenseServerUrl);
request.Method = "POST";
request.ContentType = "application/octet-stream";
request.Proxy = WebRequest.DefaultWebProxy;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(postBytes, 0, postBytes.Length);
}
return request;
private LicenseResponse ProcessHttpResponse(HttpWebResponse response)
{
if ((response.StatusCode == HttpStatusCode.OK) && response.ContentType.Contains("application/octet-stream"))
{
var stream = response.GetResponseStream();
if (stream != null)
{
var licenseResponse = this._licenseResponseSerializer.Read(stream);
return licenseResponse;
}
}
return new LicenseResponse(LicensingResult.Error);
}
Summary and Tips
Use the streams in the request/responses on the client and server to communicate binary octet-stream data
Use CryptoStream along with an encryption algorithm (consider using the strongest encryption possilbe) and a good private key to encrypt data when you serialize/deserialize it.
Make sure to check the size and format all incoming data to the client and server (avoid buffer overruns and throw exceptions early)
Protect your private key on your client using obfuscation if possible (take a look at the DeepSea obfustactor)

How to get mac address of the client without using activex

My main purpose is to give every machine using the website a unique id, one way would be to find the mac address of the client, but not using activex, and also cant assign ID using cookie because cookies can be deleted and not also using last modified date method, so any ideas on how I could assign a unique ID, thanks
You might be able to do this using a java applet, but HTML and web browser policies are very carefully designed to prevent you from doing something like this, as it would be considered a major security risk. A Mac address is certainly not possible to grab without either an activex control (which if discovered would probably get banned for providing such personal information to javascript, unless you had really carefully planned security) or at the very least a java applet that would require the user to grant it elevated privileges.
Most companies just assign a unique id and store it in a cookie in the browser. There are technologies such as FireBreath that make it easy to create browser plugins (activex control and npapi plugin), but again -- what you're talking about has the potential to be a very, very bad idea, so tread with care.
I know its too late to reply for this post..but to share my experience i am posting my answer.(I too faced the same problem)
I used the applet and deployed it on client's machine.
import java.applet.Applet;
import java.applet.Applet;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
public class app extends Applet{
public String macAddr="";
public void init()
{
try
{
System.out.println("Start");
InetAddress ip = InetAddress.getLocalHost();
System.out.println((new StringBuilder("Current IP address:"+ip.toString())));
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
byte mac[] = network.getHardwareAddress();
System.out.println("mac : "+mac.toString());
System.out.print("Current MAC address : ");
StringBuilder sb = new StringBuilder();
for(int i = 0; i < mac.length; i++)
sb.append(String.format("%02X%s", new Object[] {
Byte.valueOf(mac[i]), i >= mac.length - 1 ? "" : "-"
}));
System.out.println(sb.toString());
macAddr=String.valueOf(sb);
System.out.println("okay good");
}
catch(SocketException e)
{
macAddr=e.toString();
e.printStackTrace();
System.out.println("not good");
}
catch (Exception e) {
macAddr=e.toString();
e.printStackTrace();
System.out.println("bad good");
}
}
}
The problem i faced after making this applet is[That it worked fine when i run it on Machine locally (RUN AS APPLET)], buT IT DOESNT WORK ON SERVER``
for that you have to sign your jar
Keytool -genkey -alias signFiles -keystore compstore -keypass KEYPASS -dname "cn=XYZ" -storepass KEY -validity 125000
jarsigner -keystore compstore -storepass PASS -keypass KEYPASS appletname.jar signFiles
After that it worked but not smoothly..as everytime i run it.Browser asks for permission.
which is not good.
I hope my experience helps

Resources