Beispiel #1
0
        public void CrlInternalBuilderTest()
        {
            var dname      = new X500DistinguishedName("CN=Test");
            var hash       = HashAlgorithmName.SHA256;
            var crlBuilder = CrlBuilder.Create(dname, hash)
                             .SetNextUpdate(DateTime.Today.AddDays(30));

            byte[] serial       = new byte[] { 4, 5, 6, 7 };
            var    revokedarray = new RevokedCertificate(serial);

            crlBuilder.RevokedCertificates.Add(revokedarray);
            string serstring     = "45678910";
            var    revokedstring = new RevokedCertificate(serstring);

            crlBuilder.RevokedCertificates.Add(revokedstring);
            crlBuilder.CrlExtensions.Add(X509Extensions.BuildCRLNumber(123));
            var crlEncoded = crlBuilder.Encode();

            Assert.NotNull(crlEncoded);
            var x509Crl = new X509CRL();

            x509Crl.DecodeCrl(crlEncoded);
            Assert.NotNull(x509Crl);
            Assert.NotNull(x509Crl.CrlExtensions);
            Assert.NotNull(x509Crl.RevokedCertificates);
            Assert.AreEqual(dname.RawData, x509Crl.IssuerName.RawData);
            //Assert.AreEqual(crlBuilder.ThisUpdate, x509Crl.ThisUpdate);
            //Assert.AreEqual(crlBuilder.NextUpdate, x509Crl.NextUpdate);
            Assert.AreEqual(2, x509Crl.RevokedCertificates.Count);
            Assert.AreEqual(serial, x509Crl.RevokedCertificates[0].UserCertificate);
            Assert.AreEqual(serstring, x509Crl.RevokedCertificates[1].SerialNumber);
            Assert.AreEqual(1, x509Crl.CrlExtensions.Count);
            Assert.AreEqual(hash, x509Crl.HashAlgorithmName);
        }
Beispiel #2
0
        public void CrlBuilderTest(KeyHashPair keyHashPair)
        {
            var crlBuilder = CrlBuilder.Create(m_issuerCert.SubjectName, keyHashPair.HashAlgorithmName)
                             .SetThisUpdate(DateTime.UtcNow.Date)
                             .SetNextUpdate(DateTime.UtcNow.Date.AddDays(30));

            // little endian byte array as serial number?
            byte[] serial       = new byte[] { 4, 5, 6, 7 };
            var    revokedarray = new RevokedCertificate(serial);

            crlBuilder.RevokedCertificates.Add(revokedarray);
            string serstring     = "123456789101";
            var    revokedstring = new RevokedCertificate(serstring);

            crlBuilder.RevokedCertificates.Add(revokedstring);

            crlBuilder.CrlExtensions.Add(X509Extensions.BuildCRLNumber(1111));
            crlBuilder.CrlExtensions.Add(X509Extensions.BuildAuthorityKeyIdentifier(m_issuerCert));

            var     i509Crl = crlBuilder.CreateForRSA(m_issuerCert);
            X509CRL x509Crl = new X509CRL(i509Crl.RawData);

            Assert.NotNull(x509Crl);
            Assert.NotNull(x509Crl.CrlExtensions);
            Assert.NotNull(x509Crl.RevokedCertificates);
            Assert.AreEqual(m_issuerCert.SubjectName.RawData, x509Crl.IssuerName.RawData);
            Assert.AreEqual(crlBuilder.ThisUpdate, x509Crl.ThisUpdate);
            Assert.AreEqual(crlBuilder.NextUpdate, x509Crl.NextUpdate);
            Assert.AreEqual(2, x509Crl.RevokedCertificates.Count);
            Assert.AreEqual(serial, x509Crl.RevokedCertificates[0].UserCertificate);
            Assert.AreEqual(serstring, x509Crl.RevokedCertificates[1].SerialNumber);
            Assert.AreEqual(2, x509Crl.CrlExtensions.Count);
            Assert.True(x509Crl.VerifySignature(new X509Certificate2(m_issuerCert.RawData), true));
        }
        /// <summary>
        /// Revoke the certificates.
        /// </summary>
        /// <remarks>
        /// Merge all existing revoked certificates from CRL list.
        /// Add serialnumbers of new revoked certificates.
        /// The CRL number is increased by one and the new CRL is returned.
        /// </remarks>
        public static X509CRL RevokeCertificate(
            X509Certificate2 issuerCertificate,
            X509CRLCollection issuerCrls,
            X509Certificate2Collection revokedCertificates,
            DateTime thisUpdate,
            DateTime nextUpdate
            )
        {
            if (!issuerCertificate.HasPrivateKey)
            {
                throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer certificate has no private key, cannot revoke certificate.");
            }

            BigInteger crlSerialNumber = 0;
            var        crlRevokedList  = new Dictionary <string, RevokedCertificate>();

            // merge all existing revocation list
            if (issuerCrls != null)
            {
                foreach (X509CRL issuerCrl in issuerCrls)
                {
                    var extension = X509Extensions.FindExtension <X509CrlNumberExtension>(issuerCrl.CrlExtensions);
                    if (extension != null &&
                        extension.CrlNumber > crlSerialNumber)
                    {
                        crlSerialNumber = extension.CrlNumber;
                    }
                    foreach (var revokedCertificate in issuerCrl.RevokedCertificates)
                    {
                        if (!crlRevokedList.ContainsKey(revokedCertificate.SerialNumber))
                        {
                            crlRevokedList[revokedCertificate.SerialNumber] = revokedCertificate;
                        }
                    }
                }
            }

            // add existing serial numbers
            if (revokedCertificates != null)
            {
                foreach (var cert in revokedCertificates)
                {
                    if (!crlRevokedList.ContainsKey(cert.SerialNumber))
                    {
                        var entry = new RevokedCertificate(cert.SerialNumber, CRLReason.PrivilegeWithdrawn);
                        crlRevokedList[cert.SerialNumber] = entry;
                    }
                }
            }

            CrlBuilder crlBuilder = CrlBuilder.Create(issuerCertificate.SubjectName)
                                    .AddRevokedCertificates(crlRevokedList.Values.ToList())
                                    .SetThisUpdate(thisUpdate)
                                    .SetNextUpdate(nextUpdate)
                                    .AddCRLExtension(X509Extensions.BuildAuthorityKeyIdentifier(issuerCertificate))
                                    .AddCRLExtension(X509Extensions.BuildCRLNumber(crlSerialNumber + 1));

            return(new X509CRL(crlBuilder.CreateForRSA(issuerCertificate)));
        }
Beispiel #4
0
        public void CreateCRL()
        {
            // little endian byte array as serial number?
            byte[] serial       = new byte[] { 1, 2, 3 };
            var    revokedarray = new RevokedCertificate(serial);

            var crlBuilder = CrlBuilder.Create(m_issuerCert.SubjectName, HashAlgorithmName.SHA256)
                             .SetThisUpdate(DateTime.UtcNow.Date)
                             .SetNextUpdate(DateTime.UtcNow.Date.AddDays(30));

            crlBuilder.RevokedCertificates.Add(revokedarray);
            crlBuilder.CrlExtensions.Add(X509Extensions.BuildCRLNumber(1));
            crlBuilder.CrlExtensions.Add(X509Extensions.BuildAuthorityKeyIdentifier(m_issuerCert));
            _ = crlBuilder.CreateForRSA(m_issuerCert);
        }
Beispiel #5
0
        public void CrlBuilderTestWithSignatureGenerator(KeyHashPair keyHashPair)
        {
            var crlBuilder = CrlBuilder.Create(m_issuerCert.SubjectName, keyHashPair.HashAlgorithmName)
                             .SetThisUpdate(DateTime.UtcNow.Date)
                             .SetNextUpdate(DateTime.UtcNow.Date.AddDays(30));

            // little endian byte array as serial number?
            byte[] serial       = new byte[] { 4, 5, 6, 7 };
            var    revokedarray = new RevokedCertificate(serial);

            crlBuilder.RevokedCertificates.Add(revokedarray);
            string serstring     = "709876543210";
            var    revokedstring = new RevokedCertificate(serstring);

            crlBuilder.RevokedCertificates.Add(revokedstring);

            crlBuilder.CrlExtensions.Add(X509Extensions.BuildCRLNumber(1111));
            crlBuilder.CrlExtensions.Add(X509Extensions.BuildAuthorityKeyIdentifier(m_issuerCert));

            IX509CRL ix509Crl;

            using (RSA rsa = m_issuerCert.GetRSAPrivateKey())
            {
                X509SignatureGenerator generator = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1);
                ix509Crl = crlBuilder.CreateSignature(generator);
            }
            X509CRL x509Crl = new X509CRL(ix509Crl);

            Assert.NotNull(x509Crl);
            Assert.NotNull(x509Crl.CrlExtensions);
            Assert.NotNull(x509Crl.RevokedCertificates);
            Assert.AreEqual(m_issuerCert.SubjectName.RawData, x509Crl.IssuerName.RawData);
            Assert.AreEqual(crlBuilder.ThisUpdate, x509Crl.ThisUpdate);
            Assert.AreEqual(crlBuilder.NextUpdate, x509Crl.NextUpdate);
            Assert.AreEqual(2, x509Crl.RevokedCertificates.Count);
            Assert.AreEqual(serial, x509Crl.RevokedCertificates[0].UserCertificate);
            Assert.AreEqual(serstring, x509Crl.RevokedCertificates[1].SerialNumber);
            Assert.AreEqual(2, x509Crl.CrlExtensions.Count);
            using (var issuerPubKey = new X509Certificate2(m_issuerCert.RawData))
            {
                Assert.True(x509Crl.VerifySignature(issuerPubKey, true));
            }
        }
Beispiel #6
0
        public void GlobalSetup()
        {
            m_issuerCert = CertificateBuilder.Create("CN=Root CA")
                           .SetCAConstraint()
                           .CreateForRSA();
            m_certificate = CertificateBuilder.Create("CN=TestCert")
                            .SetNotBefore(DateTime.Today.AddDays(-1))
                            .AddExtension(
                new X509SubjectAltNameExtension("urn:opcfoundation.org:mypc",
                                                new string[] { "mypc", "mypc.opcfoundation.org", "192.168.1.100" }))
                            .CreateForRSA();

            var crlBuilder = CrlBuilder.Create(m_issuerCert.SubjectName, HashAlgorithmName.SHA256)
                             .SetThisUpdate(DateTime.UtcNow.Date)
                             .SetNextUpdate(DateTime.UtcNow.Date.AddDays(30));
            var revokedarray = new RevokedCertificate(m_certificate.SerialNumber);

            crlBuilder.RevokedCertificates.Add(revokedarray);
            crlBuilder.CrlExtensions.Add(X509Extensions.BuildCRLNumber(1));
            crlBuilder.CrlExtensions.Add(X509Extensions.BuildAuthorityKeyIdentifier(m_issuerCert));
            m_issuerCrl = crlBuilder.CreateForRSA(m_issuerCert);
            m_x509Crl   = new X509CRL(m_issuerCrl.RawData);

            var random = new Random();

            m_rsaPrivateKey = m_certificate.GetRSAPrivateKey();
            m_rsaPublicKey  = m_certificate.GetRSAPublicKey();

            // blob size for RSA padding OaepSHA256
            int blobSize = m_rsaPublicKey.KeySize / 8 - 66;

            m_randomByteArray = new byte[blobSize];
            random.NextBytes(m_randomByteArray);

            m_encryptedByteArray = m_rsaPublicKey.Encrypt(m_randomByteArray, RSAEncryptionPadding.OaepSHA256);
            m_signature          = m_rsaPrivateKey.SignData(m_randomByteArray, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }
Beispiel #7
0
        /// <summary>
        ///   Decodes the specified Certificate Revocation List (CRL) and produces
        ///   a <see cref="CertificateRevocationListBuilder" /> with all of the revocation
        ///   entries from the decoded CRL.
        /// </summary>
        /// <param name="currentCrl">
        ///   The DER-encoded CRL to decode.
        /// </param>
        /// <param name="currentCrlNumber">
        ///   When this method returns, contains the CRL sequence number from the decoded CRL.
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <param name="bytesConsumed">
        ///   When this method returns, contains the number of bytes that were read from
        ///   <paramref name="currentCrl"/> while decoding.
        /// </param>
        /// <returns>
        ///   A new builder that has the same revocation entries as the decoded CRL.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   <paramref name="currentCrl" /> could not be decoded.
        /// </exception>
        public static CertificateRevocationListBuilder Load(
            ReadOnlySpan <byte> currentCrl,
            out BigInteger currentCrlNumber,
            out int bytesConsumed)
        {
            List <RevokedCertificate> list = new();
            BigInteger crlNumber           = 0;
            int        payloadLength;

            try
            {
                AsnValueReader reader = new AsnValueReader(currentCrl, AsnEncodingRules.DER);
                payloadLength = reader.PeekEncodedValue().Length;

                AsnValueReader certificateList = reader.ReadSequence();
                AsnValueReader tbsCertList     = certificateList.ReadSequence();
                AlgorithmIdentifierAsn.Decode(ref certificateList, ReadOnlyMemory <byte> .Empty, out _);

                if (!certificateList.TryReadPrimitiveBitString(out _, out _))
                {
                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                }

                certificateList.ThrowIfNotEmpty();

                int version = 0;

                if (tbsCertList.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
                {
                    // https://datatracker.ietf.org/doc/html/rfc5280#section-5.1 says the only
                    // version values are v1 (0) and v2 (1).
                    //
                    // Since v1 (0) is supposed to not write down the version value, v2 (1) is the
                    // only legal value to read.
                    if (!tbsCertList.TryReadInt32(out version) || version != 1)
                    {
                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                    }
                }

                AlgorithmIdentifierAsn.Decode(ref tbsCertList, ReadOnlyMemory <byte> .Empty, out _);
                // X500DN
                tbsCertList.ReadSequence();

                // thisUpdate
                ReadX509Time(ref tbsCertList);

                // nextUpdate
                ReadX509TimeOpt(ref tbsCertList);

                AsnValueReader revokedCertificates = default;

                if (tbsCertList.HasData && tbsCertList.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
                {
                    revokedCertificates = tbsCertList.ReadSequence();
                }

                if (version > 0 && tbsCertList.HasData)
                {
                    AsnValueReader crlExtensionsExplicit = tbsCertList.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                    AsnValueReader crlExtensions         = crlExtensionsExplicit.ReadSequence();
                    crlExtensionsExplicit.ThrowIfNotEmpty();

                    while (crlExtensions.HasData)
                    {
                        AsnValueReader extension = crlExtensions.ReadSequence();
                        Oid?           extnOid   = Oids.GetSharedOrNullOid(ref extension);

                        if (extnOid is null)
                        {
                            extension.ReadObjectIdentifier();
                        }

                        if (extension.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean))
                        {
                            extension.ReadBoolean();
                        }

                        if (!extension.TryReadPrimitiveOctetString(out ReadOnlySpan <byte> extnValue))
                        {
                            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                        }

                        // Since we're only matching against OIDs that come from GetSharedOrNullOid
                        // we can use ReferenceEquals and skip the Value string equality check in
                        // the Oid.ValueEquals extension method (as it will always be preempted by
                        // the ReferenceEquals or will evaulate to false).
                        if (ReferenceEquals(extnOid, Oids.CrlNumberOid))
                        {
                            AsnValueReader crlNumberReader = new AsnValueReader(
                                extnValue,
                                AsnEncodingRules.DER);

                            crlNumber = crlNumberReader.ReadInteger();
                            crlNumberReader.ThrowIfNotEmpty();
                        }
                    }
                }

                tbsCertList.ThrowIfNotEmpty();

                while (revokedCertificates.HasData)
                {
                    RevokedCertificate revokedCertificate = new RevokedCertificate(ref revokedCertificates, version);
                    list.Add(revokedCertificate);
                }
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }

            bytesConsumed    = payloadLength;
            currentCrlNumber = crlNumber;
            return(new CertificateRevocationListBuilder(list));
        }