/// <summary> /// Decoder for the signature sequence. /// </summary> /// <param name="crl">The encoded CRL or certificate sequence.</param> private void Decode(byte[] crl) { try { AsnReader crlReader = new AsnReader(crl, AsnEncodingRules.DER); var seqReader = crlReader.ReadSequence(Asn1Tag.Sequence); if (seqReader != null) { // Tbs encoded data Tbs = seqReader.ReadEncodedValue().ToArray(); // Signature Algorithm Identifier var sigOid = seqReader.ReadSequence(); SignatureAlgorithm = sigOid.ReadObjectIdentifier(); Name = Oids.GetHashAlgorithmName(SignatureAlgorithm); // Signature int unusedBitCount; Signature = seqReader.ReadBitString(out unusedBitCount); if (unusedBitCount != 0) { throw new AsnContentException("Unexpected data in signature."); } seqReader.ThrowIfNotEmpty(); return; } throw new CryptographicException("No valid data in the X509 signature."); } catch (AsnContentException ace) { throw new CryptographicException("Failed to decode the X509 signature.", ace); } }
/// <summary> /// Encode Tbs with a signature in ASN format. /// </summary> /// <returns>X509 ASN format of EncodedData+SignatureOID+Signature bytes.</returns> public byte[] Encode() { AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); var tag = Asn1Tag.Sequence; writer.PushSequence(tag); // write Tbs encoded data writer.WriteEncodedValue(Tbs); // Signature Algorithm Identifier if (SignatureAlgorithmIdentifier != null) { writer.WriteEncodedValue(SignatureAlgorithmIdentifier); } else { writer.PushSequence(); string signatureAlgorithmIdentifier = Oids.GetRSAOid(Name); writer.WriteObjectIdentifier(signatureAlgorithmIdentifier); writer.WriteNull(); writer.PopSequence(); } // Add signature writer.WriteBitString(Signature); writer.PopSequence(tag); return(writer.Encode()); }
/// <summary> /// Initialize the X509 signature values. /// </summary> /// <param name="tbs">The data to be signed.</param> /// <param name="signature">The signature of the data.</param> /// <param name="signatureAlgorithmIdentifier">The algorithm used to create the signature.</param> public X509Signature(byte[] tbs, byte[] signature, byte[] signatureAlgorithmIdentifier) { Tbs = tbs; Signature = signature; SignatureAlgorithmIdentifier = signatureAlgorithmIdentifier; SignatureAlgorithm = DecodeAlgorithm(signatureAlgorithmIdentifier); Name = Oids.GetHashAlgorithmName(SignatureAlgorithm); }
/// <summary> /// Constructs Certificate Revocation List raw data in X509 ASN format. /// </summary> /// <remarks> /// CRL fields -- https://tools.ietf.org/html/rfc5280#section-5.1 /// /// CertificateList ::= SEQUENCE { /// tbsCertList TBSCertList, /// signatureAlgorithm AlgorithmIdentifier, /// signatureValue BIT STRING /// } /// /// TBSCertList ::= SEQUENCE { /// version Version OPTIONAL, /// -- if present, MUST be v2 /// signature AlgorithmIdentifier, /// issuer Name, /// thisUpdate Time, /// nextUpdate Time OPTIONAL, /// revokedCertificates SEQUENCE OF SEQUENCE { /// userCertificate CertificateSerialNumber, /// revocationDate Time, /// crlEntryExtensions Extensions OPTIONAL /// -- if present, version MUST be v2 /// } OPTIONAL, /// crlExtensions [0] EXPLICIT Extensions OPTIONAL /// -- if present, version MUST be v2 /// } /// </remarks> internal byte[] Encode() { AsnWriter crlWriter = new AsnWriter(AsnEncodingRules.DER); { // tbsCertList crlWriter.PushSequence(); // version crlWriter.WriteInteger(1); // Signature Algorithm Identifier crlWriter.PushSequence(); string signatureAlgorithm = Oids.GetRSAOid(HashAlgorithmName); crlWriter.WriteObjectIdentifier(signatureAlgorithm); crlWriter.WriteNull(); // pop crlWriter.PopSequence(); // Issuer crlWriter.WriteEncodedValue((ReadOnlySpan <byte>)IssuerName.RawData); // this update crlWriter.WriteUtcTime(this.ThisUpdate); if (NextUpdate != DateTime.MinValue && NextUpdate > ThisUpdate) { // next update crlWriter.WriteUtcTime(NextUpdate); } // sequence to start the revoked certificates. crlWriter.PushSequence(); foreach (var revokedCert in RevokedCertificates) { crlWriter.PushSequence(); BigInteger srlNumberValue = new BigInteger(revokedCert.UserCertificate); crlWriter.WriteInteger(srlNumberValue); crlWriter.WriteUtcTime(revokedCert.RevocationDate); if (revokedCert.CrlEntryExtensions.Count > 0) { crlWriter.PushSequence(); foreach (var crlEntryExt in revokedCert.CrlEntryExtensions) { crlWriter.WriteExtension(crlEntryExt); } crlWriter.PopSequence(); } crlWriter.PopSequence(); } crlWriter.PopSequence(); // CRL extensions if (CrlExtensions.Count > 0) { // [0] EXPLICIT Extensions OPTIONAL var tag = new Asn1Tag(TagClass.ContextSpecific, 0); crlWriter.PushSequence(tag); // CRL extensions crlWriter.PushSequence(); foreach (var extension in CrlExtensions) { crlWriter.WriteExtension(extension); } crlWriter.PopSequence(); crlWriter.PopSequence(tag); } crlWriter.PopSequence(); return(crlWriter.Encode()); } }
/// <summary> /// Decode the Tbs of the CRL. /// </summary> /// <param name="tbs">The raw TbsCertList of the CRL.</param> internal void DecodeCrl(byte[] tbs) { try { AsnReader crlReader = new AsnReader(tbs, AsnEncodingRules.DER); var tag = Asn1Tag.Sequence; var seqReader = crlReader.ReadSequence(tag); crlReader.ThrowIfNotEmpty(); if (seqReader != null) { // Version is OPTIONAL uint version = 0; var intTag = new Asn1Tag(UniversalTagNumber.Integer); var peekTag = seqReader.PeekTag(); if (peekTag == intTag) { if (seqReader.TryReadUInt32(out version)) { if (version != 1) { throw new AsnContentException($"The CRL contains an incorrect version {version}"); } } } // Signature Algorithm Identifier var sigReader = seqReader.ReadSequence(); var oid = sigReader.ReadObjectIdentifier(); m_hashAlgorithmName = Oids.GetHashAlgorithmName(oid); if (sigReader.HasData) { sigReader.ReadNull(); } sigReader.ThrowIfNotEmpty(); // Issuer m_issuerName = new X500DistinguishedName(seqReader.ReadEncodedValue().ToArray()); // thisUpdate m_thisUpdate = seqReader.ReadUtcTime().UtcDateTime; // nextUpdate is OPTIONAL var utcTag = new Asn1Tag(UniversalTagNumber.UtcTime); peekTag = seqReader.PeekTag(); if (peekTag == utcTag) { m_nextUpdate = seqReader.ReadUtcTime().UtcDateTime; } var seqTag = new Asn1Tag(UniversalTagNumber.Sequence, true); peekTag = seqReader.PeekTag(); if (peekTag == seqTag) { // revoked certificates var revReader = seqReader.ReadSequence(tag); var revokedCertificates = new List <RevokedCertificate>(); while (revReader.HasData) { var crlEntry = revReader.ReadSequence(); var serial = crlEntry.ReadInteger(); var revokedCertificate = new RevokedCertificate(serial.ToByteArray()); revokedCertificate.RevocationDate = crlEntry.ReadUtcTime().UtcDateTime; if (version == 1 && crlEntry.HasData) { // CRL entry extensions var crlEntryExtensions = crlEntry.ReadSequence(); while (crlEntryExtensions.HasData) { var extension = crlEntryExtensions.ReadExtension(); revokedCertificate.CrlEntryExtensions.Add(extension); } crlEntryExtensions.ThrowIfNotEmpty(); } crlEntry.ThrowIfNotEmpty(); revokedCertificates.Add(revokedCertificate); } revReader.ThrowIfNotEmpty(); m_revokedCertificates = revokedCertificates; } // CRL extensions OPTIONAL if (version == 1 && seqReader.HasData) { var extTag = new Asn1Tag(TagClass.ContextSpecific, 0); var optReader = seqReader.ReadSequence(extTag); var crlExtensionList = new X509ExtensionCollection(); var crlExtensions = optReader.ReadSequence(); while (crlExtensions.HasData) { var extension = crlExtensions.ReadExtension(); crlExtensionList.Add(extension); } m_crlExtensions = crlExtensionList; } seqReader.ThrowIfNotEmpty(); m_decoded = true; return; } throw new CryptographicException("The CRL contains ivalid data."); } catch (AsnContentException ace) { throw new CryptographicException("Failed to decode the CRL.", ace); } }