예제 #1
0
 public static extern uint NCryptVerifySignature(IntPtr hKey,
                                                 [In] ref BCRYPT_PSS_PADDING_INFO pPaddingInfo,
                                                 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
                                                 int cbHashValue,
                                                 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
                                                 int cbSignature,
                                                 uint dwFlags);
예제 #2
0
 public static extern uint NCryptSignHash(IntPtr hKey,
                                          [In] ref BCRYPT_PSS_PADDING_INFO pPaddingInfo,
                                          [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
                                          int cbHashValue,
                                          IntPtr pbSignature,
                                          int cbSignature,
                                          [Out] out uint pcbResult,
                                          uint dwFlags);
        public static bool ValidateData(byte[] nonce, byte[] token, byte[] signature, byte[] certificate)
        {
            // Convert the Certificate Chain which is in a serialized format to SignedCms object.
            SignedCms cms = new SignedCms();
            cms.Decode(certificate);

            // Looping through all certificates to find the leaf certificate. 
            X509Certificate2 leafCertificate = null;
            foreach (X509Certificate2 x509 in cms.Certificates)
            {
                bool basicConstraintExtensionExists = false;

                foreach (X509Extension extension in x509.Extensions)
                {
                    if (extension.Oid.FriendlyName == "Basic Constraints")
                    {
                        basicConstraintExtensionExists = true;
                        X509BasicConstraintsExtension ext = (X509BasicConstraintsExtension)extension;
                        if (!ext.CertificateAuthority)
                        {
                            leafCertificate = x509;
                            break;
                        }
                    }
                }

                if (leafCertificate != null)
                {
                    break;
                }

                if (!basicConstraintExtensionExists)
                {
                    if (x509.Issuer != x509.Subject)
                    {
                        leafCertificate = x509;
                        break;
                    }
                }
            }

            if (leafCertificate == null)
            {
                throw new ArgumentException("Leaf certificate could not be found");
            }

            // Validating the certificate chain. Ignore the errors due to online revocation check not 
            // being available. Also we are not failing validation due to expired certificates. Microsoft
            // will be revoking the certificates that were exploided. 
            X509Chain chain = new X509Chain();
            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid |
                X509VerificationFlags.IgnoreCtlNotTimeValid |
                X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown |
                X509VerificationFlags.IgnoreEndRevocationUnknown |
                X509VerificationFlags.IgnoreCtlSignerRevocationUnknown;

            chain.ChainPolicy.ApplicationPolicy.Add(new Oid("1.3.6.1.4.1.311.10.5.40"));
            chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

            bool result = chain.Build(leafCertificate);
            if (!result)
            {
                foreach (X509ChainStatus status in chain.ChainStatus)
                {
                    switch (status.Status)
                    {
                        case X509ChainStatusFlags.NoError:
                        case X509ChainStatusFlags.NotTimeValid:
                        case X509ChainStatusFlags.NotTimeNested:
                        case X509ChainStatusFlags.CtlNotTimeValid:
                        case X509ChainStatusFlags.RevocationStatusUnknown:
                        case X509ChainStatusFlags.OfflineRevocation:
                            break;
                        #if DEBUG
                            case X509ChainStatusFlags.UntrustedRoot:
                            break;
                        #endif

                        default:
                            throw new ArgumentException("Chain verification failed with status " + status.Status);
                    }
                }
            }

            // gRootPublicKey is the hard coded public key for the root certificate. 
            // Compare the public key on the root certificate with the hard coded one. 
            // They must match.
            X509Certificate2 rootCertificate = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
            if (!rootCertificate.PublicKey.EncodedKeyValue.RawData.SequenceEqual(gRootPublicKey))
            {
                throw new ArgumentException("Public key of the root certificate is not as expected.");
            }

            // Signature contains both nonce and hardwareId. So creating the combined data;
            byte[] blob;
            if (nonce == null)
            {
                blob = token;
            }
            else
            {
                blob = nonce.Concat(token).ToArray();
            }

            // Using the leaf Certificate we verify the signature of blob. The RSACryptoServiceProvider does not
            // provide a way to pass in different padding mode. So we use Win32 NCryptVerifySignature API instead.
            RSACryptoServiceProvider rsaCsp = leafCertificate.PublicKey.Key as RSACryptoServiceProvider;
            RSAParameters parameters = rsaCsp.ExportParameters(false);
            SHA1Managed sha1 = new SHA1Managed();
            byte[] blobHash = sha1.ComputeHash(blob);

            CngKey cngKey = CngKey.Import(GetPublicKey(parameters), CngKeyBlobFormat.GenericPublicBlob);
            BCRYPT_PSS_PADDING_INFO paddingInfo = new BCRYPT_PSS_PADDING_INFO
            {
                pszAlgId = CngAlgorithm.Sha1.Algorithm,
                cbSalt = 0
            };

            string[] lines = { "sha1: " + BitConverter.ToInt64(sha1.Hash, 0), " \n blobHash: " + BitConverter.ToInt64(blobHash, 0), "\n blob: " + BitConverter.ToInt64(blob, 0), "\n MachineId:" + BitConverter.ToInt64(token, 0) };
            System.IO.File.WriteAllLines(@"C:\Users\YanBorowski\Desktop\Windows8.HardwareToken-master\W8\HardwareTokenSample\HardwareTokenValidationService\log.txt", lines);

            int result2 = UnsafeNativeMethods.NCryptVerifySignature(
                cngKey.Handle,
                ref paddingInfo,
                blobHash,
                blobHash.Length,
                signature,
                signature.Length,
                8); // NCRYPT_PAD_PSS_FLAG

            if (result2 != 0) // 0 means ERROR_SUCCESS
            {
                return false; //throw new ArgumentException("Verification failed with " + result2);
            }

            return true;
        }