- Installing all Java’s “Root CA” certificates: Inefficient, It requires user confirmation for every certificate.
- Install temporarily the root certificate referenced by the APK/JAR file and delete it after the validation process. This option also needs user confirmation and it’s usually not a good idea to modify the user’s trusted certificate list.
- Extract the entire certification chain of the file and doing the validation manually. Obviously the best option.
The first option to think of is using Microsoft’s own X509Chain to validate the certificate chain. The behavior of X509Chain is highly configurable and allows us to change the various chain verification policies and adding chain elements manually. Once we have defined “ChainPolicy” and “ChainElements” we use the X509Chain.Build() method that returns us a Boolean value either validating or not the certificate chain. And that’s it, we have a Boolean value but no graphic information.
Furthermore, if we don’t have the root certificate installed in our certificate store, we’re unable to import the intermediate certificate as a X509ChainElement which is necessary to build the chain correctly.
[DllImport("CRYPT32", EntryPoint
= "CertOpenStore", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CertOpenStore(
int storeProvider, int encodingType,
int hcryptProv, int flags, string pvPara);
When calling the function we need to indicate that our storeProvider is of type CERT_STORE_PROV_PKCS7 and “pvPara” will point to the data.
if (!WinCrypt.CryptQueryObject(
WinCrypt.CERT_QUERY_OBJECT_FILE,
Marshal.StringToHGlobalUni(@"X:RutaFichero.RSA"),
WinCrypt.CERT_QUERY_CONTENT_FLAG_ALL,
WinCrypt.CERT_QUERY_FORMAT_FLAG_ALL,
0,
out encodingType,
out contentType,
out formatType,
ref certStore, //Contiene el "Store" con los certificados.
ref cryptMsg, //Contiene la estructura PKCS7
ref context))
//en myCert tendremos el certificado principal
X509Certificate2 myCert = new X509Certificate2(@"X:RutaFichero.RSA");
//los extra stores que queramos usar deben pasarse como puntero al array que los contiene
var extraStoreArray = new[] { certStore };
var extraStoreArrayHandle = GCHandle.Alloc(extraStoreArray, GCHandleType.Pinned);
var extraStorePointer = extraStoreArrayHandle.AddrOfPinnedObject();
//rellenamos la estructura con los parámetros
CRYPTUI_VIEWCERTIFICATE_STRUCT certViewInfo = new CRYPTUI_VIEWCERTIFICATE_STRUCT();
certViewInfo.dwSize = Marshal.SizeOf(certViewInfo);
certViewInfo.pCertContext = myCert.Handle;
certViewInfo.szTitle = "Certificate Info";
certViewInfo.dwFlags = CRYPTUI_DISABLE_ADDTOSTORE;
certViewInfo.nStartPage = 0;
certViewInfo.cStores = 1;
certViewInfo.rghStores = extraStorePointer;
bool fPropertiesChanged = false;
if (!CryptUIDlgViewCertificate(ref certViewInfo, ref fPropertiesChanged))
{
int error = Marshal.GetLastWin32Error();
MessageBox.Show(error.ToString());
}