private static unsafe TstInfo Decode(byte[] rawData)
        {
            var really = new byte[rawData.Length];

            fixed(byte *pbData = rawData)
            {
                var decodedPtr = IntPtr.Zero;
                var cbStruct   = 0;

                try
                {
                    if (!Rfc3161TimestampWin32.CryptDecodeObjectEx(
                            Rfc3161TimestampWin32.CryptEncodingTypes.X509_ASN_ENCODING,
                            Rfc3161TimestampWin32.TIMESTAMP_INFO,
                            (IntPtr)pbData,
                            rawData.Length,
                            Rfc3161TimestampWin32.CryptDecodeObjectFlags.CRYPT_DECODE_ALLOC_FLAG |
                            Rfc3161TimestampWin32.CryptDecodeObjectFlags.CRYPT_DECODE_NOCOPY_FLAG |
                            Rfc3161TimestampWin32.CryptDecodeObjectFlags.CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG,
                            IntPtr.Zero,
                            (IntPtr)(&decodedPtr),
                            ref cbStruct))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    var tstInfo = ReadTstInfo(decodedPtr);

                    //fixed (byte* pbReally = really)
                    {
                        uint cbReally        = 0;
                        var  letThemEncodeIt = IntPtr.Zero;

                        if (!Rfc3161TimestampWin32.CryptEncodeObjectEx(
                                Rfc3161TimestampWin32.CryptEncodingTypes.X509_ASN_ENCODING,
                                Rfc3161TimestampWin32.TIMESTAMP_INFO,
                                decodedPtr,
                                Rfc3161TimestampWin32.CryptEncodeObjectFlags.CRYPT_ENCODE_ALLOC_FLAG,
                                IntPtr.Zero,
                                (IntPtr)(&letThemEncodeIt),
                                ref cbReally))
                        {
                            throw new CryptographicException(Marshal.GetLastWin32Error());
                        }

                        really = new byte[cbReally];
                        Marshal.Copy(letThemEncodeIt, really, 0, (int)cbReally);
                    }

                    return(tstInfo);
                }
                finally
                {
                    if (decodedPtr != IntPtr.Zero)
                    {
                        Rfc3161TimestampWin32.LocalFree(decodedPtr);
                    }
                }
            }
        }
        private static unsafe byte[] Encode(TstInfo tstInfo)
        {
            var algOid = tstInfo.HashAlgorithmId.Value;

            var policyOidBytes           = new byte[tstInfo.PolicyId.Length + 1];
            var algOidBytes              = new byte[algOid.Length + 1];
            var serialNumberBigEndian    = tstInfo.SerialNumber;
            var serialNumberLittleEndian = new byte[serialNumberBigEndian.Length];

            for (var i = 0; i < serialNumberLittleEndian.Length; i++)
            {
                serialNumberLittleEndian[i] = serialNumberBigEndian[serialNumberBigEndian.Length - i - 1];
            }

            var filetime = tstInfo.Timestamp.ToFileTime();

            fixed(byte *pbPolicyOid = policyOidBytes)
            fixed(char *pszPolicyOid    = tstInfo.PolicyId)
            fixed(byte *pbHashedMessage = tstInfo.HashedMessage)
            fixed(byte *pbSerialNumber  = serialNumberLittleEndian)
            fixed(char *pszAlgOid       = algOid)
            fixed(byte *pbAlgOid        = algOidBytes)
            fixed(byte *pbNonce         = tstInfo.Nonce)
            fixed(byte *pbTsaName       = tstInfo.TsaName)
            {
                Encoding.ASCII.GetBytes(pszPolicyOid, tstInfo.PolicyId.Length, pbPolicyOid, policyOidBytes.Length);
                Encoding.ASCII.GetBytes(pszAlgOid, algOid.Length, pbAlgOid, algOidBytes.Length);

                var info = new Rfc3161TimestampWin32.CRYPT_TIMESTAMP_INFO
                {
                    dwVersion      = tstInfo.Version,
                    pszTSAPolicyId = (IntPtr)pbPolicyOid,
                    fOrdering      = tstInfo.IsOrdering,
                };

                var accuracy = default(Rfc3161TimestampWin32.CRYPT_TIMESTAMP_ACCURACY);

                info.HashAlgorithm.pszOid = (IntPtr)pbAlgOid;
                info.HashedMessage.cbData = (uint)tstInfo.HashedMessage.Length;
                info.HashedMessage.pbData = (IntPtr)pbHashedMessage;
                info.SerialNumber.cbData  = (uint)serialNumberLittleEndian.Length;
                info.SerialNumber.pbData  = (IntPtr)pbSerialNumber;

                info.ftTime.dwLowDateTime  = (int)(filetime & 0xFFFFFFFF);
                info.ftTime.dwHighDateTime = (int)(filetime >> 32);

                if (tstInfo.AccuracyInMicroseconds.HasValue)
                {
                    var val = tstInfo.AccuracyInMicroseconds.Value;
                    val = Math.DivRem(val, 1000, out var rem);
                    accuracy.dwMicros = (int)rem;
                    val = Math.DivRem(val, 1000, out rem);
                    accuracy.dwMillis = (int)rem;

                    if (val > int.MaxValue)
                    {
                        Debug.Fail($"accuracy value {tstInfo.AccuracyInMicroseconds.Value} had seconds component {val}, which should have been stopped");
                        throw new CryptographicException();
                    }

                    accuracy.dwSeconds = (int)val;
                    info.pvAccuracy    = (IntPtr)(&accuracy);
                }

                if (tstInfo.Nonce != null)
                {
                    info.Nonce.cbData = (uint)tstInfo.Nonce.Length;
                    info.Nonce.pbData = (IntPtr)pbNonce;
                }

                if (tstInfo.TsaName != null)
                {
                    info.Tsa.cbData = (uint)tstInfo.TsaName.Length;
                    info.Tsa.pbData = (IntPtr)pbTsaName;
                }

                if (tstInfo.Extensions != null)
                {
                    throw new NotImplementedException();
                }

                var  encodedDataPtr = IntPtr.Zero;
                uint cbEncoded      = 0;

                try
                {
                    if (!Rfc3161TimestampWin32.CryptEncodeObjectEx(
                            Rfc3161TimestampWin32.CryptEncodingTypes.X509_ASN_ENCODING,
                            Rfc3161TimestampWin32.TIMESTAMP_INFO,
                            (IntPtr)(&info),
                            Rfc3161TimestampWin32.CryptEncodeObjectFlags.CRYPT_ENCODE_ALLOC_FLAG,
                            IntPtr.Zero,
                            (IntPtr)(&encodedDataPtr),
                            ref cbEncoded))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    var encoded = new byte[cbEncoded];
                    Marshal.Copy(encodedDataPtr, encoded, 0, (int)cbEncoded);
                    return(encoded);
                }
                finally
                {
                    if (encodedDataPtr != IntPtr.Zero)
                    {
                        Rfc3161TimestampWin32.LocalFree(encodedDataPtr);
                    }
                }
            }
        }
        public unsafe IRfc3161TimestampToken SubmitRequest(Uri timestampUri, TimeSpan timeout)
        {
            if (timestampUri == null)
            {
                throw new ArgumentNullException(nameof(timestampUri));
            }
            if (!timestampUri.IsAbsoluteUri)
            {
                throw new ArgumentException("Absolute URI required", nameof(timestampUri));
            }
            if (timestampUri.Scheme != Uri.UriSchemeHttp && timestampUri.Scheme != Uri.UriSchemeHttps)
            {
                throw new ArgumentException("HTTP/HTTPS required", nameof(timestampUri));
            }

            IntPtr requestedPolicyPtr = IntPtr.Zero;
            IntPtr pTsContext         = IntPtr.Zero;
            IntPtr pTsSigner          = IntPtr.Zero;
            IntPtr hStore             = IntPtr.Zero;

            const Rfc3161TimestampWin32.CryptRetrieveTimeStampFlags flags =
                Rfc3161TimestampWin32.CryptRetrieveTimeStampFlags.TIMESTAMP_VERIFY_CONTEXT_SIGNATURE |
                Rfc3161TimestampWin32.CryptRetrieveTimeStampFlags.TIMESTAMP_DONT_HASH_DATA;

            try
            {
                requestedPolicyPtr = Marshal.StringToHGlobalAnsi(Data._requestedPolicyId?.Value);

                Rfc3161TimestampWin32.CRYPT_TIMESTAMP_PARA para = new Rfc3161TimestampWin32.CRYPT_TIMESTAMP_PARA()
                {
                    fRequestCerts  = Data._requestSignerCertificate,
                    pszTSAPolicyId = requestedPolicyPtr,
                };

                if (Data._extensions?.Count > 0)
                {
                    throw new NotImplementedException();

                    fixed(byte *pbNonce = Data._nonce)
                    {
                        if (Data._nonce != null)
                        {
                            para.Nonce.cbData = (uint)Data._nonce.Length;
                            para.Nonce.pbData = (IntPtr)pbNonce;
                        }

                        if (!Rfc3161TimestampWin32.CryptRetrieveTimeStamp(
                                timestampUri.AbsoluteUri,
                                flags,
                                (int)timeout.TotalMilliseconds,
                                Data._hashAlgorithm.Value,
                                ref para,
                                Data._hash,
                                Data._hash.Length,
                                ref pTsContext,
                                ref pTsSigner,
                                ref hStore))
                        {
                            throw new CryptographicException(Marshal.GetLastWin32Error());
                        }
                    }

                    var content    = (Rfc3161TimestampWin32.CRYPT_TIMESTAMP_CONTEXT)Marshal.PtrToStructure(pTsContext, typeof(Rfc3161TimestampWin32.CRYPT_TIMESTAMP_CONTEXT));
                    byte[] encoded = new byte[content.cbEncoded];
                    Marshal.Copy(content.pbEncoded, encoded, 0, content.cbEncoded);

                    var tstInfo = new Rfc3161TimestampTokenInfoNet472Wrapper(new Rfc3161TimestampTokenInfo(pTsContext));
                    X509Certificate2 signerCert = new X509Certificate2(pTsSigner);

                    using (X509Store extraCerts = new X509Store(hStore))
                    {
                        X509Certificate2Collection additionalCertsColl = new X509Certificate2Collection();

                        foreach (var cert in extraCerts.Certificates)
                        {
                            if (!signerCert.Equals(cert))
                            {
                                additionalCertsColl.Add(cert);
                            }
                        }

                        return(Rfc3161TimestampTokenFactory.Create(
                                   tstInfo,
                                   signerCert,
                                   additionalCertsColl,
                                   encoded));
                    }
            }
            finally
            {
                if (hStore != IntPtr.Zero)
                {
                    Rfc3161TimestampWin32.CertCloseStore(hStore, 0);
                }

                if (pTsSigner != IntPtr.Zero)
                {
                    Rfc3161TimestampWin32.CertFreeCertificateContext(pTsSigner);
                }

                if (pTsContext != IntPtr.Zero)
                {
                    Rfc3161TimestampWin32.CryptMemFree(pTsContext);
                }

                if (requestedPolicyPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(requestedPolicyPtr);
                }
            }
        }
        private static unsafe byte[] Encode(DataType data)
        {
            IntPtr algorithmOidPtr = IntPtr.Zero;
            IntPtr policyOidPtr    = IntPtr.Zero;
            IntPtr encodedDataPtr  = IntPtr.Zero;

            try
            {
                algorithmOidPtr = Marshal.StringToHGlobalAnsi(data._hashAlgorithm.Value);
                policyOidPtr    = Marshal.StringToHGlobalAnsi(data._requestedPolicyId?.Value);

                Rfc3161TimestampWin32.CRYPT_TIMESTAMP_REQUEST request = new Rfc3161TimestampWin32.CRYPT_TIMESTAMP_REQUEST
                {
                    dwVersion      = data._version,
                    fCertReq       = data._requestSignerCertificate,
                    pszTSAPolicyId = policyOidPtr,
                };

                request.HashAlgorithm.pszOid = algorithmOidPtr;
                request.HashedMessage.cbData = (uint)data._hash.Length;
                request.Nonce.cbData         = (uint)(data._nonce?.Length ?? 0);

                fixed(byte *hashPtr = data._hash)
                fixed(byte *noncePtr = data._nonce)
                {
                    request.HashedMessage.pbData = (IntPtr)hashPtr;
                    request.Nonce.pbData         = (IntPtr)noncePtr;

                    uint cbEncoded = 0;

                    if (!Rfc3161TimestampWin32.CryptEncodeObjectEx(
                            Rfc3161TimestampWin32.CryptEncodingTypes.X509_ASN_ENCODING,
                            Rfc3161TimestampWin32.TIMESTAMP_REQUEST,
                            (IntPtr)(&request),
                            Rfc3161TimestampWin32.CryptEncodeObjectFlags.CRYPT_ENCODE_ALLOC_FLAG,
                            IntPtr.Zero,
                            (IntPtr)(&encodedDataPtr),
                            ref cbEncoded))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    byte[] encoded = new byte[cbEncoded];
                    Marshal.Copy(encodedDataPtr, encoded, 0, (int)cbEncoded);
                    return(encoded);
                }
            }
            finally
            {
                if (algorithmOidPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(algorithmOidPtr);
                }

                if (policyOidPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(policyOidPtr);
                }

                if (encodedDataPtr != IntPtr.Zero)
                    Rfc3161TimestampWin32.LocalFree(encodedDataPtr); }
            }
Example #5
0
        private static Rfc3161TimestampToken CryptVerifyTimeStampSignature(byte[] encodedToken, byte[] data)
        {
            IntPtr pTsContext = IntPtr.Zero;
            IntPtr pTsSigner  = IntPtr.Zero;
            IntPtr hStore     = IntPtr.Zero;

            try
            {
                if (!Rfc3161TimestampWin32.CryptVerifyTimeStampSignature(
                        encodedToken,
                        encodedToken.Length,
                        data,
                        data?.Length ?? 0,
                        IntPtr.Zero,
                        ref pTsContext,
                        ref pTsSigner,
                        ref hStore))
                {
                    throw new CryptographicException(Marshal.GetLastWin32Error());
                }

                IRfc3161TimestampTokenInfo tstInfo    = new Rfc3161TimestampTokenInfoNet472Wrapper(new Rfc3161TimestampTokenInfo(pTsContext));
                X509Certificate2           signerCert = new X509Certificate2(pTsSigner);

                using (X509Store extraCerts = new X509Store(hStore))
                {
                    X509Certificate2Collection additionalCertsColl = new X509Certificate2Collection();

                    foreach (var cert in extraCerts.Certificates)
                    {
                        if (!signerCert.Equals(cert))
                        {
                            additionalCertsColl.Add(cert);
                        }
                    }

                    return(new Rfc3161TimestampToken(
                               tstInfo,
                               signerCert,
                               additionalCertsColl,
                               (byte[])encodedToken.Clone()));
                }
            }
            finally
            {
                if (pTsContext != IntPtr.Zero)
                {
                    Rfc3161TimestampWin32.CryptMemFree(pTsContext);
                }

                if (pTsSigner != IntPtr.Zero)
                {
                    Rfc3161TimestampWin32.CertFreeCertificateContext(pTsSigner);
                }

                if (hStore != IntPtr.Zero)
                {
                    Rfc3161TimestampWin32.CertCloseStore(hStore, 0);
                }
            }
        }