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