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); } }
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); } } }