public static void TryDecode_Invalid()
        {
            ReadOnlyMemory <byte> inputData = TimestampTokenTestData.Symantec1.TokenInfoBytes;

            Assert.False(
                Rfc3161TimestampTokenInfo.TryDecode(
                    inputData.Slice(0, inputData.Length - 1),
                    out Rfc3161TimestampTokenInfo tokenInfo,
                    out int bytesRead));

            Assert.Equal(0, bytesRead);
            Assert.Null(tokenInfo);
        }
        private static AsnEncodedData CreateTimestampToken(byte serial)
        {
            Oid tokenOid = new Oid(TokenAttributeOid, TokenAttributeOid);

            Oid policyId        = new Oid("0.0", "0.0");
            Oid hashAlgorithmId = new Oid(Oids.Sha256);

            var tokenInfo = new Rfc3161TimestampTokenInfo(
                policyId,
                hashAlgorithmId,
                new byte[256 / 8],
                new byte[] { (byte)serial },
                DateTimeOffset.UtcNow);

            return(new AsnEncodedData(tokenOid, tokenInfo.Encode()));
        }
        private static void VerifyAttributesAreEqual(AsnEncodedData actual, AsnEncodedData expected)
        {
            Assert.NotSame(expected.Oid, actual.Oid);
            Assert.Equal(expected.Oid.Value, actual.Oid.Value);

            // We need to decode bytes because DER and BER may encode the same information slightly differently
            Rfc3161TimestampTokenInfo expectedToken;

            Assert.True(Rfc3161TimestampTokenInfo.TryDecode(expected.RawData, out expectedToken, out _));

            Rfc3161TimestampTokenInfo actualToken;

            Assert.True(Rfc3161TimestampTokenInfo.TryDecode(actual.RawData, out actualToken, out _));

            Assert.Equal(expectedToken.GetSerialNumber().ByteArrayToHex(), actualToken.GetSerialNumber().ByteArrayToHex());
            Assert.Equal(expectedToken.Timestamp, actualToken.Timestamp);
            Assert.Equal(expectedToken.HashAlgorithmId.Value, Oids.Sha256);
            Assert.Equal(expectedToken.HashAlgorithmId.Value, actualToken.HashAlgorithmId.Value);
        }
        private static void ValidateTokenInfo(
            ReadOnlyMemory <byte> tokenInfoBytes,
            TimestampTokenTestData testData,
            int?lengthFromTry)
        {
            Rfc3161TimestampTokenInfo tokenInfo;

            Assert.True(
                Rfc3161TimestampTokenInfo.TryDecode(tokenInfoBytes, out tokenInfo, out int bytesRead),
                "Rfc3161TimestampTokenInfo.TryDecode");

            Assert.NotNull(tokenInfo);

            if (lengthFromTry != null)
            {
                Assert.Equal(lengthFromTry.Value, bytesRead);
            }

            AssertEqual(testData, tokenInfo);
        }
        public static void CreateFromParameters(string testDataName)
        {
            TimestampTokenTestData testData = TimestampTokenTestData.GetTestData(testDataName);

            Oid policyId         = new Oid(testData.PolicyId, testData.PolicyId);
            Oid hashAlgorithmOid = new Oid(testData.HashAlgorithmId);

            byte[]         messageHash      = testData.HashBytes.ToArray();
            byte[]         serial           = testData.SerialNumberBytes.ToArray();
            DateTimeOffset nonUtcTimestamp  = testData.Timestamp.ToOffset(TimeSpan.FromHours(-8));
            long?          accuracyMicrosec = testData.AccuracyInMicroseconds;

            byte[] nonce        = testData.NonceBytes?.ToArray();
            byte[] tsaNameBytes = testData.TsaNameBytes?.ToArray();

            ReadOnlyMemory <byte>?nonceMemory = null;
            ReadOnlyMemory <byte>?tsaMemory   = null;

            if (nonce != null)
            {
                nonceMemory = nonce;
            }

            if (tsaNameBytes != null)
            {
                tsaMemory = tsaNameBytes;
            }

            var tokenInfo = new Rfc3161TimestampTokenInfo(
                policyId,
                hashAlgorithmOid,
                messageHash,
                serial,
                nonUtcTimestamp,
                accuracyMicrosec,
                testData.IsOrdering,
                nonceMemory,
                tsaMemory);

            // Since AssertEqual will check all the fields the remaining checks in this method are about
            // input/output value/reference associations.
            AssertEqual(testData, tokenInfo);

            Assert.NotSame(policyId, tokenInfo.PolicyId);
            Assert.NotSame(hashAlgorithmOid, tokenInfo.HashAlgorithmId);

            Assert.Equal(nonUtcTimestamp, tokenInfo.Timestamp);
            Assert.Equal(TimeSpan.Zero, tokenInfo.Timestamp.Offset);

            Assert.Equal(messageHash.ByteArrayToHex(), tokenInfo.GetMessageHash().ByteArrayToHex());
            // Detached from the original data
            messageHash[0] ^= 0xFF;
            Assert.NotEqual(messageHash.ByteArrayToHex(), tokenInfo.GetMessageHash().ByteArrayToHex());

            Assert.Equal(serial.ByteArrayToHex(), tokenInfo.GetSerialNumber().ByteArrayToHex());
            // Detached from the original data
            serial[1] ^= 0xFF;
            Assert.NotEqual(serial.ByteArrayToHex(), tokenInfo.GetSerialNumber().ByteArrayToHex());


            if (nonce != null)
            {
                ReadOnlyMemory <byte>?tokenNonce = tokenInfo.GetNonce();
                Assert.True(tokenNonce.HasValue, "tokenInfo.GetNonce().HasValue");

                Assert.Equal(nonce.ByteArrayToHex(), tokenNonce.Value.ByteArrayToHex());
                // Detached from the original data
                nonce[0] ^= 0xFF;
                Assert.NotEqual(nonce.ByteArrayToHex(), tokenNonce.Value.ByteArrayToHex());
            }

            ReadOnlyMemory <byte>?nameFromToken = tokenInfo.GetTimestampAuthorityName();

            if (tsaNameBytes != null)
            {
                Assert.True(nameFromToken.HasValue, "nameFromToken.HasValue");
                Assert.Equal(tsaNameBytes.ByteArrayToHex(), nameFromToken.Value.ByteArrayToHex());
                // Detached from the original data
                tsaNameBytes[5] ^= 0xFF;
                Assert.NotEqual(tsaNameBytes.ByteArrayToHex(), nameFromToken.Value.ByteArrayToHex());
            }

            if (testData.ExtensionsBytes == null)
            {
                Assert.False(tokenInfo.HasExtensions, "tokenInfo.HasExtensions");
                Assert.NotNull(tokenInfo.GetExtensions());
                Assert.Equal(0, tokenInfo.GetExtensions().Count);

                // GetExtensions always returns a new collection.
                Assert.NotSame(tokenInfo.GetExtensions(), tokenInfo.GetExtensions());
            }
            else
            {
                Assert.True(tokenInfo.HasExtensions, "tokenInfo.HasExtensions");
                Assert.NotNull(tokenInfo.GetExtensions());

                Assert.True(false, "A test handler has been written for extensions...");

                // GetExtensions always returns a new collection.
                Assert.NotSame(tokenInfo.GetExtensions(), tokenInfo.GetExtensions());
            }

            // Because the token is DER encoded, we should produce byte-for-byte the same value.
            Assert.Equal(testData.TokenInfoBytes.ByteArrayToHex(), tokenInfo.Encode().ByteArrayToHex());
        }
Пример #6
0
        private static byte[] BuildCustomToken(
            CertLoader cert,
            DateTimeOffset timestamp,
            SigningCertificateOption v1Option,
            SigningCertificateOption v2Option,
            HashAlgorithmName v2DigestAlg        = default,
            X509IncludeOption includeOption      = X509IncludeOption.ExcludeRoot,
            SubjectIdentifierType identifierType = SubjectIdentifierType.IssuerAndSerialNumber)
        {
            long accuracyMicroSeconds = (long)(TimeSpan.FromMinutes(1).TotalMilliseconds * 1000);

            byte[] serialNumber = BitConverter.GetBytes(DateTimeOffset.UtcNow.Ticks);
            Array.Reverse(serialNumber);

            Rfc3161TimestampTokenInfo info = new Rfc3161TimestampTokenInfo(
                new Oid("0.0", "0.0"),
                new Oid(Oids.Sha384),
                new byte[384 / 8],
                serialNumber,
                timestamp,
                accuracyMicroSeconds,
                isOrdering: true);

            ContentInfo contentInfo = new ContentInfo(new Oid(Oids.TstInfo, Oids.TstInfo), info.Encode());
            SignedCms   cms         = new SignedCms(contentInfo);

            using (X509Certificate2 tsaCert = cert.TryGetCertificateWithPrivateKey())
            {
                CmsSigner signer = new CmsSigner(identifierType, tsaCert)
                {
                    IncludeOption = includeOption
                };

                if (v1Option != SigningCertificateOption.Omit)
                {
                    ExpandOption(v1Option, out bool validHash, out bool skipIssuerSerial, out bool validName, out bool validSerial);

                    // simple SigningCertificate
                    byte[] signingCertificateV1Bytes =
                        "301A3018301604140000000000000000000000000000000000000000".HexToByteArray();

                    if (validHash)
                    {
                        byte[] hash = SHA1.HashData(tsaCert.RawData);

                        Buffer.BlockCopy(
                            hash,
                            0,
                            signingCertificateV1Bytes,
                            signingCertificateV1Bytes.Length - hash.Length,
                            hash.Length);
                    }

                    if (!skipIssuerSerial)
                    {
                        byte[] footer = BuildIssuerAndSerialNumber(tsaCert, validName, validSerial);

                        signingCertificateV1Bytes[1] += (byte)footer.Length;
                        signingCertificateV1Bytes[3] += (byte)footer.Length;
                        signingCertificateV1Bytes[5] += (byte)footer.Length;

                        Assert.InRange(signingCertificateV1Bytes[1], 0, 127);

                        signingCertificateV1Bytes = signingCertificateV1Bytes.Concat(footer).ToArray();
                    }

                    signer.SignedAttributes.Add(
                        new AsnEncodedData("1.2.840.113549.1.9.16.2.12", signingCertificateV1Bytes));
                }

                if (v2Option != SigningCertificateOption.Omit)
                {
                    byte[] attrBytes;
                    byte[] algBytes = Array.Empty <byte>();
                    byte[] hashBytes;
                    byte[] issuerNameBytes = Array.Empty <byte>();

                    if (v2DigestAlg != default)
                    {
                        switch (v2DigestAlg.Name)
                        {
                        case "MD5":
                            algBytes = "300C06082A864886F70D02050500".HexToByteArray();
                            break;

                        case "SHA1":
                            algBytes = "300906052B0E03021A0500".HexToByteArray();
                            break;

                        case "SHA256":
                            // Invalid under DER, because it's the default.
                            algBytes = "300D06096086480165030402010500".HexToByteArray();
                            break;

                        case "SHA384":
                            algBytes = "300D06096086480165030402020500".HexToByteArray();
                            break;

                        case "SHA512":
                            algBytes = "300D06096086480165030402030500".HexToByteArray();
                            break;

                        default:
                            throw new NotSupportedException(v2DigestAlg.Name);
                        }
                    }
                    else
                    {
                        v2DigestAlg = HashAlgorithmName.SHA256;
                    }

                    hashBytes = tsaCert.GetCertHash(v2DigestAlg);

                    ExpandOption(v2Option, out bool validHash, out bool skipIssuerSerial, out bool validName, out bool validSerial);

                    if (!validHash)
                    {
                        hashBytes[0] ^= 0xFF;
                    }

                    if (!skipIssuerSerial)
                    {
                        issuerNameBytes = BuildIssuerAndSerialNumber(tsaCert, validName, validSerial);
                    }

                    // hashBytes hasn't been wrapped in an OCTET STRING yet, so add 2 more.
                    int payloadSize = algBytes.Length + hashBytes.Length + issuerNameBytes.Length + 2;
                    Assert.InRange(payloadSize, 0, 123);

                    attrBytes = new byte[payloadSize + 6];

                    int index = 0;

                    // SEQUENCE (SigningCertificateV2)
                    attrBytes[index++] = 0x30;
                    attrBytes[index++] = (byte)(payloadSize + 4);

                    // SEQUENCE OF => certs
                    attrBytes[index++] = 0x30;
                    attrBytes[index++] = (byte)(payloadSize + 2);

                    // SEQUENCE (ESSCertIdV2)
                    attrBytes[index++] = 0x30;
                    attrBytes[index++] = (byte)payloadSize;

                    Buffer.BlockCopy(algBytes, 0, attrBytes, index, algBytes.Length);
                    index += algBytes.Length;

                    // OCTET STRING (Hash)
                    attrBytes[index++] = 0x04;
                    attrBytes[index++] = (byte)hashBytes.Length;
                    Buffer.BlockCopy(hashBytes, 0, attrBytes, index, hashBytes.Length);
                    index += hashBytes.Length;

                    Buffer.BlockCopy(issuerNameBytes, 0, attrBytes, index, issuerNameBytes.Length);

                    signer.SignedAttributes.Add(
                        new AsnEncodedData("1.2.840.113549.1.9.16.2.47", attrBytes));
                }

                cms.ComputeSignature(signer);
            }

            return(cms.Encode());
        }