public virtual void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags keyUsages) { DerSequenceReader reader = DerSequenceReader.CreateForPayload(encoded); byte[] decoded = reader.ReadBitString(); // Only 9 bits are defined. if (decoded.Length > 2) { throw new CryptographicException(); } // DER encodings of BIT_STRING values number the bits as // 01234567 89 (big endian), plus a number saying how many bits of the last byte were padding. // // So digitalSignature (0) doesn't mean 2^0 (0x01), it means the most significant bit // is set in this byte stream. // // BIT_STRING values are compact. So a value of cRLSign (6) | keyEncipherment (2), which // is 0b0010001 => 0b0010 0010 (1 bit padding) => 0x22 encoded is therefore // 0x02 (length remaining) 0x01 (1 bit padding) 0x22. // // We will read that, and return 0x22. 0x22 lines up // exactly with X509KeyUsageFlags.CrlSign (0x20) | X509KeyUsageFlags.KeyEncipherment (0x02) // // Once the decipherOnly (8) bit is added to the mix, the values become: // 0b001000101 => 0b0010 0010 1000 0000 (7 bits padding) // { 0x03 0x07 0x22 0x80 } // And we read new byte[] { 0x22 0x80 } // // The value of X509KeyUsageFlags.DecipherOnly is 0x8000. 0x8000 in a little endian // representation is { 0x00 0x80 }. This means that the DER storage mechanism has effectively // ended up being little-endian for BIT_STRING values. Untwist the bytes, and now the bits all // line up with the existing X509KeyUsageFlags. int value = 0; if (decoded.Length > 0) { value = decoded[0]; } if (decoded.Length > 1) { value |= decoded[1] << 8; } keyUsages = (X509KeyUsageFlags)value; }
internal CertificateData(byte[] rawData) { #if DEBUG try { #endif DerSequenceReader reader = new DerSequenceReader(rawData); DerSequenceReader tbsCertificate = reader.ReadSequence(); if (tbsCertificate.PeekTag() == DerSequenceReader.ContextSpecificConstructedTag0) { DerSequenceReader version = tbsCertificate.ReadSequence(); Version = version.ReadInteger(); } else if (tbsCertificate.PeekTag() != (byte)DerSequenceReader.DerTag.Integer) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } else { Version = 0; } if (Version < 0 || Version > 2) { throw new CryptographicException(); } SerialNumber = tbsCertificate.ReadIntegerBytes(); DerSequenceReader tbsSignature = tbsCertificate.ReadSequence(); TbsSignature.AlgorithmId = tbsSignature.ReadOidAsString(); TbsSignature.Parameters = tbsSignature.HasData ? tbsSignature.ReadNextEncodedValue() : Array.Empty <byte>(); if (tbsSignature.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } Issuer = new X500DistinguishedName(tbsCertificate.ReadNextEncodedValue()); DerSequenceReader validity = tbsCertificate.ReadSequence(); NotBefore = validity.ReadX509Date(); NotAfter = validity.ReadX509Date(); if (validity.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } Subject = new X500DistinguishedName(tbsCertificate.ReadNextEncodedValue()); SubjectPublicKeyInfo = tbsCertificate.ReadNextEncodedValue(); DerSequenceReader subjectPublicKeyInfo = new DerSequenceReader(SubjectPublicKeyInfo); DerSequenceReader subjectKeyAlgorithm = subjectPublicKeyInfo.ReadSequence(); PublicKeyAlgorithm.AlgorithmId = subjectKeyAlgorithm.ReadOidAsString(); PublicKeyAlgorithm.Parameters = subjectKeyAlgorithm.HasData ? subjectKeyAlgorithm.ReadNextEncodedValue() : Array.Empty <byte>(); if (subjectKeyAlgorithm.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } PublicKey = subjectPublicKeyInfo.ReadBitString(); if (subjectPublicKeyInfo.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } if (Version > 0 && tbsCertificate.HasData && tbsCertificate.PeekTag() == DerSequenceReader.ContextSpecificConstructedTag1) { IssuerUniqueId = tbsCertificate.ReadBitString(); } else { IssuerUniqueId = null; } if (Version > 0 && tbsCertificate.HasData && tbsCertificate.PeekTag() == DerSequenceReader.ContextSpecificConstructedTag2) { SubjectUniqueId = tbsCertificate.ReadBitString(); } else { SubjectUniqueId = null; } Extensions = new List <X509Extension>(); if (Version > 1 && tbsCertificate.HasData && tbsCertificate.PeekTag() == DerSequenceReader.ContextSpecificConstructedTag3) { DerSequenceReader extensions = tbsCertificate.ReadSequence(); extensions = extensions.ReadSequence(); while (extensions.HasData) { DerSequenceReader extensionReader = extensions.ReadSequence(); string oid = extensionReader.ReadOidAsString(); bool critical = false; if (extensionReader.PeekTag() == (byte)DerSequenceReader.DerTag.Boolean) { critical = extensionReader.ReadBoolean(); } byte[] extensionData = extensionReader.ReadOctetString(); Extensions.Add(new X509Extension(oid, extensionData, critical)); if (extensionReader.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } } } if (tbsCertificate.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } DerSequenceReader signatureAlgorithm = reader.ReadSequence(); SignatureAlgorithm.AlgorithmId = signatureAlgorithm.ReadOidAsString(); SignatureAlgorithm.Parameters = signatureAlgorithm.HasData ? signatureAlgorithm.ReadNextEncodedValue() : Array.Empty <byte>(); if (signatureAlgorithm.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } SignatureValue = reader.ReadBitString(); if (reader.HasData) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } RawData = rawData; #if DEBUG } catch (Exception e) { throw new CryptographicException( $"Error in reading certificate:{Environment.NewLine}{PemPrintCert(rawData)}", e); } #endif }