internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out KeyTransRecipientInfoAsn decoded) { decoded = default; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); ReadOnlySpan <byte> rebindSpan = rebind.Span; int offset; ReadOnlySpan <byte> tmpSpan; if (!sequenceReader.TryReadInt32(out decoded.Version)) { sequenceReader.ThrowIfNotEmpty(); } RecipientIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Rid); AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.KeyEncryptionAlgorithm); if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan)) { decoded.EncryptedKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); } else { decoded.EncryptedKey = sequenceReader.ReadOctetString(); } sequenceReader.ThrowIfNotEmpty(); }
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out SignerInfoAsn decoded) { decoded = default; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); AsnValueReader collectionReader; ReadOnlySpan <byte> rebindSpan = rebind.Span; int offset; ReadOnlySpan <byte> tmpSpan; if (!sequenceReader.TryReadInt32(out decoded.Version)) { sequenceReader.ThrowIfNotEmpty(); } SignerIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Sid); AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.DigestAlgorithm); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) { tmpSpan = sequenceReader.ReadEncodedValue(); decoded.SignedAttributes = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); decoded.SignedAttributesSet = SignedAttributesSet.Decode(decoded.SignedAttributes.Value, AsnEncodingRules.BER); } AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.SignatureAlgorithm); if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan)) { decoded.SignatureValue = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); } else { decoded.SignatureValue = sequenceReader.ReadOctetString(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1))) { // Decode SEQUENCE OF for UnsignedAttributes { collectionReader = sequenceReader.ReadSetOf(new Asn1Tag(TagClass.ContextSpecific, 1)); var tmpList = new List <AttributeAsn>(); AttributeAsn tmpItem; while (collectionReader.HasData) { AttributeAsn.Decode(ref collectionReader, rebind, out tmpItem); tmpList.Add(tmpItem); } decoded.UnsignedAttributes = tmpList.ToArray(); } } sequenceReader.ThrowIfNotEmpty(); }
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out KeyAgreeRecipientInfoAsn decoded) { decoded = default; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); AsnValueReader explicitReader; AsnValueReader collectionReader; ReadOnlySpan <byte> rebindSpan = rebind.Span; int offset; ReadOnlySpan <byte> tmpSpan; if (!sequenceReader.TryReadInt32(out decoded.Version)) { sequenceReader.ThrowIfNotEmpty(); } explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); OriginatorIdentifierOrKeyAsn.Decode(ref explicitReader, rebind, out decoded.Originator); explicitReader.ThrowIfNotEmpty(); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); if (explicitReader.TryReadPrimitiveOctetStringBytes(out tmpSpan)) { decoded.Ukm = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); } else { decoded.Ukm = explicitReader.ReadOctetString(); } explicitReader.ThrowIfNotEmpty(); } AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.KeyEncryptionAlgorithm); // Decode SEQUENCE OF for RecipientEncryptedKeys { collectionReader = sequenceReader.ReadSequence(); var tmpList = new List <RecipientEncryptedKeyAsn>(); RecipientEncryptedKeyAsn tmpItem; while (collectionReader.HasData) { RecipientEncryptedKeyAsn.Decode(ref collectionReader, rebind, out tmpItem); tmpList.Add(tmpItem); } decoded.RecipientEncryptedKeys = tmpList.ToArray(); } sequenceReader.ThrowIfNotEmpty(); }
internal byte[] ToPkcs10Request(X509SignatureGenerator signatureGenerator, HashAlgorithmName hashAlgorithm) { // State validation should be runtime checks if/when this becomes public API Debug.Assert(signatureGenerator != null); Debug.Assert(Subject != null); Debug.Assert(PublicKey != null); byte[] signatureAlgorithm = signatureGenerator.GetSignatureAlgorithmIdentifier(hashAlgorithm); AlgorithmIdentifierAsn signatureAlgorithmAsn; // Deserialization also does validation of the value (except for Parameters, which have to be validated separately). signatureAlgorithmAsn = AlgorithmIdentifierAsn.Decode(signatureAlgorithm, AsnEncodingRules.DER); if (signatureAlgorithmAsn.Parameters.HasValue) { Helpers.ValidateDer(signatureAlgorithmAsn.Parameters.Value.Span); } SubjectPublicKeyInfoAsn spki = default; spki.Algorithm = new AlgorithmIdentifierAsn { Algorithm = PublicKey.Oid !.Value !, Parameters = PublicKey.EncodedParameters.RawData }; spki.SubjectPublicKey = PublicKey.EncodedKeyValue.RawData; var attributes = new AttributeAsn[Attributes.Count]; for (int i = 0; i < attributes.Length; i++) { attributes[i] = new AttributeAsn(Attributes[i]); } CertificationRequestInfoAsn requestInfo = new CertificationRequestInfoAsn { Version = 0, Subject = this.Subject.RawData, SubjectPublicKeyInfo = spki, Attributes = attributes }; AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); requestInfo.Encode(writer); byte[] encodedRequestInfo = writer.Encode(); writer.Reset(); CertificationRequestAsn certificationRequest = new CertificationRequestAsn { CertificationRequestInfo = requestInfo, SignatureAlgorithm = signatureAlgorithmAsn, SignatureValue = signatureGenerator.SignData(encodedRequestInfo, hashAlgorithm), }; certificationRequest.Encode(writer); return(writer.Encode()); } }
static EssCertIdV2() { EssCertIdV2 decoded = default; ReadOnlyMemory <byte> rebind = default; AsnValueReader reader; reader = new AsnValueReader(DefaultHashAlgorithm, AsnEncodingRules.DER); AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashAlgorithm); reader.ThrowIfNotEmpty(); }
internal byte[] ToPkcs10Request(X509SignatureGenerator signatureGenerator, HashAlgorithmName hashAlgorithm) { // State validation should be runtime checks if/when this becomes public API Debug.Assert(signatureGenerator != null); Debug.Assert(Subject != null); Debug.Assert(PublicKey != null); byte[] signatureAlgorithm = signatureGenerator.GetSignatureAlgorithmIdentifier(hashAlgorithm); AlgorithmIdentifierAsn signatureAlgorithmAsn; // Deserialization also does validation of the value (except for Parameters, which have to be validated separately). signatureAlgorithmAsn = AlgorithmIdentifierAsn.Decode(signatureAlgorithm, AsnEncodingRules.DER); if (signatureAlgorithmAsn.Parameters.HasValue) { Helpers.ValidateDer(signatureAlgorithmAsn.Parameters.Value); } SubjectPublicKeyInfoAsn spki = new SubjectPublicKeyInfoAsn(); spki.Algorithm = new AlgorithmIdentifierAsn { Algorithm = PublicKey.Oid, Parameters = PublicKey.EncodedParameters.RawData }; spki.SubjectPublicKey = PublicKey.EncodedKeyValue.RawData; CertificationRequestInfoAsn requestInfo = new CertificationRequestInfoAsn { Version = 0, Subject = this.Subject.RawData, SubjectPublicKeyInfo = spki, Attributes = Attributes.Select(a => new AttributeAsn(a)).ToArray(), }; using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) using (AsnWriter signedWriter = new AsnWriter(AsnEncodingRules.DER)) { requestInfo.Encode(writer); byte[] encodedRequestInfo = writer.Encode(); CertificationRequestAsn certificationRequest = new CertificationRequestAsn { CertificationRequestInfo = requestInfo, SignatureAlgorithm = signatureAlgorithmAsn, SignatureValue = signatureGenerator.SignData(encodedRequestInfo, hashAlgorithm), }; certificationRequest.Encode(signedWriter); return(signedWriter.Encode()); } }
/// <summary> /// Sign the current certificate request to create a chain-signed or self-signed certificate. /// </summary> /// <param name="issuerName">The X500DistinguishedName for the Issuer</param> /// <param name="generator"> /// An <see cref="X509SignatureGenerator"/> representing the issuing certificate authority. /// </param> /// <param name="notBefore"> /// The oldest date and time where this certificate is considered valid. /// Typically <see cref="DateTimeOffset.UtcNow"/>, plus or minus a few seconds. /// </param> /// <param name="notAfter"> /// The date and time where this certificate is no longer considered valid. /// </param> /// <param name="serialNumber"> /// The serial number to use for the new certificate. This value should be unique per issuer. /// The value is interpreted as an unsigned (big) integer in big endian byte ordering. /// </param> /// <returns> /// An <see cref="X509Certificate2"/> with the specified values. The returned object will /// not assert <see cref="X509Certificate2.HasPrivateKey" />. /// </returns> /// <exception cref="ArgumentNullException"><paramref name="issuerName"/> is null.</exception> /// <exception cref="ArgumentNullException"><paramref name="generator"/> is null.</exception> /// <exception cref="ArgumentException"> /// <paramref name="notAfter"/> represents a date and time before <paramref name="notBefore"/>. /// </exception> /// <exception cref="ArgumentException"><paramref name="serialNumber"/> has length 0.</exception> /// <exception cref="CryptographicException">Any error occurs during the signing operation.</exception> public X509Certificate2 Create( X500DistinguishedName issuerName, X509SignatureGenerator generator, DateTimeOffset notBefore, DateTimeOffset notAfter, ReadOnlySpan <byte> serialNumber) { if (issuerName == null) { throw new ArgumentNullException(nameof(issuerName)); } if (generator == null) { throw new ArgumentNullException(nameof(generator)); } if (notAfter < notBefore) { throw new ArgumentException(SR.Cryptography_CertReq_DatesReversed); } if (serialNumber == null || serialNumber.Length < 1) { throw new ArgumentException(SR.Arg_EmptyOrNullArray, nameof(serialNumber)); } byte[] signatureAlgorithm = generator.GetSignatureAlgorithmIdentifier(HashAlgorithm); AlgorithmIdentifierAsn signatureAlgorithmAsn; // Deserialization also does validation of the value (except for Parameters, which have to be validated separately). signatureAlgorithmAsn = AlgorithmIdentifierAsn.Decode(signatureAlgorithm, AsnEncodingRules.DER); if (signatureAlgorithmAsn.Parameters.HasValue) { Helpers.ValidateDer(signatureAlgorithmAsn.Parameters.Value); } ArraySegment <byte> normalizedSerial = NormalizeSerialNumber(serialNumber); TbsCertificateAsn tbsCertificate = new TbsCertificateAsn { Version = 2, SerialNumber = normalizedSerial, SignatureAlgorithm = signatureAlgorithmAsn, Issuer = issuerName.RawData, SubjectPublicKeyInfo = new SubjectPublicKeyInfoAsn { Algorithm = new AlgorithmIdentifierAsn { Algorithm = PublicKey.Oid !.Value !, Parameters = PublicKey.EncodedParameters.RawData, },
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out EssCertIdV2 decoded) { decoded = default; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); AsnValueReader defaultReader; ReadOnlySpan <byte> rebindSpan = rebind.Span; int offset; ReadOnlySpan <byte> tmpSpan; if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence)) { AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.HashAlgorithm); } else { defaultReader = new AsnValueReader(DefaultHashAlgorithm, AsnEncodingRules.DER); AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashAlgorithm); } if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan)) { decoded.Hash = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); } else { decoded.Hash = sequenceReader.ReadOctetString(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence)) { CadesIssuerSerial tmpIssuerSerial; CadesIssuerSerial.Decode(ref sequenceReader, rebind, out tmpIssuerSerial); decoded.IssuerSerial = tmpIssuerSerial; } sequenceReader.ThrowIfNotEmpty(); }
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out KEKRecipientInfoAsn decoded) { decoded = default; KEKIdentifierAsn kekIdentifier; AlgorithmIdentifierAsn algIdentifier; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); int version; if (sequenceReader.TryReadInt32(out version)) { decoded.Version = version; } KEKIdentifierAsn.Decode(ref sequenceReader, Asn1Tag.Sequence, rebind, out kekIdentifier); AlgorithmIdentifierAsn.Decode(ref sequenceReader, Asn1Tag.Sequence, rebind, out algIdentifier); var encryptedKey = sequenceReader.ReadOctetString(); decoded.KEKId = kekIdentifier; decoded.KeyEncryptionAlg = algIdentifier; decoded.EncryptedKey = encryptedKey; }
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out OriginatorPublicKeyAsn decoded) { decoded = default; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); ReadOnlySpan <byte> rebindSpan = rebind.Span; int offset; ReadOnlySpan <byte> tmpSpan; AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Algorithm); if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out tmpSpan)) { decoded.PublicKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); } else { decoded.PublicKey = sequenceReader.ReadBitString(out _); } sequenceReader.ThrowIfNotEmpty(); }
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out MessageImprint decoded) { decoded = default; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); ReadOnlySpan <byte> rebindSpan = rebind.Span; int offset; ReadOnlySpan <byte> tmpSpan; AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.HashAlgorithm); if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan)) { decoded.HashedMessage = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); } else { decoded.HashedMessage = sequenceReader.ReadOctetString(); } sequenceReader.ThrowIfNotEmpty(); }
public static void Decode(ref AsnValueReader reader, ReadOnlyMemory <byte> rebind, out CmsAlgorithmProtectAttributeAsn decoded) { var sequence = reader.ReadSequence(); decoded = default; AlgorithmIdentifierAsn digestAlgorithm; AlgorithmIdentifierAsn.Decode(ref sequence, rebind, out digestAlgorithm); decoded.DigestAlgorithm = digestAlgorithm; Asn1Tag tag = sequence.PeekTag(); if (tag.TagValue == 1 && tag.TagClass == TagClass.ContextSpecific) { AlgorithmIdentifierAsn sigAlg; AlgorithmIdentifierAsn.Decode(ref sequence, new Asn1Tag(TagClass.ContextSpecific, 1), rebind, out sigAlg); decoded.SignatureAlgorithm = sigAlg; } else { AlgorithmIdentifierAsn macAlg; AlgorithmIdentifierAsn.Decode(ref sequence, new Asn1Tag(TagClass.ContextSpecific, 2), rebind, out macAlg); decoded.MacAlgorithm = macAlg; } }
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory <byte> rebind, out SignedDataAsn decoded) { decoded = default; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); AsnValueReader collectionReader; ReadOnlySpan <byte> rebindSpan = rebind.Span; int offset; ReadOnlySpan <byte> tmpSpan; if (!sequenceReader.TryReadInt32(out decoded.Version)) { sequenceReader.ThrowIfNotEmpty(); } // Decode SEQUENCE OF for DigestAlgorithms { collectionReader = sequenceReader.ReadSetOf(); var tmpList = new List <AlgorithmIdentifierAsn>(); AlgorithmIdentifierAsn tmpItem; while (collectionReader.HasData) { AlgorithmIdentifierAsn.Decode(ref collectionReader, rebind, out tmpItem); tmpList.Add(tmpItem); } decoded.DigestAlgorithms = tmpList.ToArray(); } EncapsulatedContentInfoAsn.Decode(ref sequenceReader, rebind, out decoded.EncapContentInfo); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) { // Decode SEQUENCE OF for CertificateSet { collectionReader = sequenceReader.ReadSetOf(new Asn1Tag(TagClass.ContextSpecific, 0)); var tmpList = new List <CertificateChoiceAsn>(); CertificateChoiceAsn tmpItem; while (collectionReader.HasData) { CertificateChoiceAsn.Decode(ref collectionReader, rebind, out tmpItem); tmpList.Add(tmpItem); } decoded.CertificateSet = tmpList.ToArray(); } } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1))) { // Decode SEQUENCE OF for Crls { collectionReader = sequenceReader.ReadSetOf(new Asn1Tag(TagClass.ContextSpecific, 1)); var tmpList = new List <ReadOnlyMemory <byte> >(); ReadOnlyMemory <byte> tmpItem; while (collectionReader.HasData) { tmpSpan = collectionReader.ReadEncodedValue(); tmpItem = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); tmpList.Add(tmpItem); } decoded.Crls = tmpList.ToArray(); } } // Decode SEQUENCE OF for SignerInfos { collectionReader = sequenceReader.ReadSetOf(); var tmpList = new List <SignerInfoAsn>(); SignerInfoAsn tmpItem; while (collectionReader.HasData) { SignerInfoAsn.Decode(ref collectionReader, rebind, out tmpItem); tmpList.Add(tmpItem); } decoded.SignerInfos = tmpList.ToArray(); } sequenceReader.ThrowIfNotEmpty(); }
public static bool TryGetRsaOaepEncryptionPadding( ReadOnlyMemory <byte>?parameters, out RSAEncryptionPadding rsaEncryptionPadding, out Exception exception) { exception = null; rsaEncryptionPadding = null; if (parameters == null || parameters.Value.IsEmpty) { exception = new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); return(false); } try { OaepParamsAsn oaepParameters = OaepParamsAsn.Decode(parameters.Value, AsnEncodingRules.DER); if (oaepParameters.MaskGenFunc.Algorithm.Value != Oids.Mgf1 || oaepParameters.MaskGenFunc.Parameters == null || oaepParameters.PSourceFunc.Algorithm.Value != Oids.PSpecified ) { exception = new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); return(false); } AlgorithmIdentifierAsn mgf1AlgorithmIdentifier = AlgorithmIdentifierAsn.Decode(oaepParameters.MaskGenFunc.Parameters.Value, AsnEncodingRules.DER); if (mgf1AlgorithmIdentifier.Algorithm.Value != oaepParameters.HashFunc.Algorithm.Value) { exception = new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); return(false); } if (oaepParameters.PSourceFunc.Parameters != null && !oaepParameters.PSourceFunc.Parameters.Value.Span.SequenceEqual(s_pSpecifiedDefaultParameters)) { exception = new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); return(false); } switch (oaepParameters.HashFunc.Algorithm.Value) { case Oids.Sha1: rsaEncryptionPadding = RSAEncryptionPadding.OaepSHA1; return(true); case Oids.Sha256: rsaEncryptionPadding = RSAEncryptionPadding.OaepSHA256; return(true); case Oids.Sha384: rsaEncryptionPadding = RSAEncryptionPadding.OaepSHA384; return(true); case Oids.Sha512: rsaEncryptionPadding = RSAEncryptionPadding.OaepSHA512; return(true); default: exception = new CryptographicException( SR.Cryptography_Cms_UnknownAlgorithm, oaepParameters.HashFunc.Algorithm.Value); return(false); } } catch (CryptographicException e) { exception = e; return(false); } }
/// <summary> /// Sign the current certificate request to create a chain-signed or self-signed certificate. /// </summary> /// <param name="issuerName">The X500DistinguishedName for the Issuer</param> /// <param name="generator"> /// An <see cref="X509SignatureGenerator"/> representing the issuing certificate authority. /// </param> /// <param name="notBefore"> /// The oldest date and time where this certificate is considered valid. /// Typically <see cref="DateTimeOffset.UtcNow"/>, plus or minus a few seconds. /// </param> /// <param name="notAfter"> /// The date and time where this certificate is no longer considered valid. /// </param> /// <param name="serialNumber"> /// The serial number to use for the new certificate. This value should be unique per issuer. /// The value is interpreted as an unsigned (big) integer in big endian byte ordering. /// </param> /// <returns> /// The ASN.1 DER-encoded certificate, suitable to be passed to <see cref="X509Certificate2(byte[])"/>. /// </returns> /// <exception cref="ArgumentNullException"><paramref name="issuerName"/> is null.</exception> /// <exception cref="ArgumentNullException"><paramref name="generator"/> is null.</exception> /// <exception cref="ArgumentException"> /// <paramref name="notAfter"/> represents a date and time before <paramref name="notBefore"/>. /// </exception> /// <exception cref="ArgumentException"><paramref name="serialNumber"/> is null or has length 0.</exception> /// <exception cref="CryptographicException">Any error occurs during the signing operation.</exception> public X509Certificate2 Create( X500DistinguishedName issuerName, X509SignatureGenerator generator, DateTimeOffset notBefore, DateTimeOffset notAfter, byte[] serialNumber) { if (issuerName == null) { throw new ArgumentNullException(nameof(issuerName)); } if (generator == null) { throw new ArgumentNullException(nameof(generator)); } if (notAfter < notBefore) { throw new ArgumentException(SR.Cryptography_CertReq_DatesReversed); } if (serialNumber == null || serialNumber.Length < 1) { throw new ArgumentException(SR.Arg_EmptyOrNullArray, nameof(serialNumber)); } byte[] signatureAlgorithm = generator.GetSignatureAlgorithmIdentifier(HashAlgorithm); AlgorithmIdentifierAsn signatureAlgorithmAsn; // Deserialization also does validation of the value (except for Parameters, which have to be validated separately). signatureAlgorithmAsn = AlgorithmIdentifierAsn.Decode(signatureAlgorithm, AsnEncodingRules.DER); if (signatureAlgorithmAsn.Parameters.HasValue) { Helpers.ValidateDer(signatureAlgorithmAsn.Parameters.Value); } TbsCertificateAsn tbsCertificate = new TbsCertificateAsn { Version = 2, SerialNumber = NormalizeSerialNumber(serialNumber), SignatureAlgorithm = signatureAlgorithmAsn, Issuer = issuerName.RawData, SubjectPublicKeyInfo = new SubjectPublicKeyInfoAsn { Algorithm = new AlgorithmIdentifierAsn { Algorithm = PublicKey.Oid, Parameters = PublicKey.EncodedParameters.RawData, }, SubjectPublicKey = PublicKey.EncodedKeyValue.RawData, }, Validity = new ValidityAsn(notBefore, notAfter), Subject = SubjectName.RawData, }; if (CertificateExtensions.Count > 0) { HashSet <string> usedOids = new HashSet <string>(CertificateExtensions.Count); List <X509ExtensionAsn> extensionAsns = new List <X509ExtensionAsn>(CertificateExtensions.Count); // An interesting quirk of skipping null values here is that // Extensions.Count == 0 => no extensions // Extensions.ContainsOnly(null) => empty extensions list foreach (X509Extension extension in CertificateExtensions) { if (extension == null) { continue; } if (!usedOids.Add(extension.Oid.Value)) { throw new InvalidOperationException( SR.Format(SR.Cryptography_CertReq_DuplicateExtension, extension.Oid.Value)); } extensionAsns.Add(new X509ExtensionAsn(extension)); } tbsCertificate.Extensions = extensionAsns.ToArray(); } using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) using (AsnWriter signedWriter = new AsnWriter(AsnEncodingRules.DER)) { tbsCertificate.Encode(writer); byte[] encodedTbsCertificate = writer.Encode(); CertificateAsn certificate = new CertificateAsn { TbsCertificate = tbsCertificate, SignatureAlgorithm = signatureAlgorithmAsn, SignatureValue = generator.SignData(encodedTbsCertificate, HashAlgorithm), }; certificate.Encode(signedWriter); return(new X509Certificate2(signedWriter.Encode())); } }
private byte[] Build( X500DistinguishedName issuerName, X509SignatureGenerator generator, BigInteger crlNumber, DateTimeOffset nextUpdate, DateTimeOffset thisUpdate, HashAlgorithmName hashAlgorithm, X509AuthorityKeyIdentifierExtension authorityKeyIdentifier) { ArgumentNullException.ThrowIfNull(issuerName); ArgumentNullException.ThrowIfNull(generator); if (crlNumber < 0) { throw new ArgumentOutOfRangeException(nameof(crlNumber), SR.ArgumentOutOfRange_NeedNonNegNum); } if (nextUpdate <= thisUpdate) { throw new ArgumentException(SR.Cryptography_CRLBuilder_DatesReversed); } ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm)); ArgumentNullException.ThrowIfNull(authorityKeyIdentifier); byte[] signatureAlgId = generator.GetSignatureAlgorithmIdentifier(hashAlgorithm); { AlgorithmIdentifierAsn signatureAlgorithmAsn; // Deserialization also does validation of the value (except for Parameters, // which have to be validated separately). signatureAlgorithmAsn = AlgorithmIdentifierAsn.Decode(signatureAlgId, AsnEncodingRules.DER); if (signatureAlgorithmAsn.Parameters.HasValue) { Helpers.ValidateDer(signatureAlgorithmAsn.Parameters.GetValueOrDefault().Span); } } AsnWriter writer = (_writer ??= new AsnWriter(AsnEncodingRules.DER)); writer.Reset(); // TBSCertList using (writer.PushSequence()) { // version v2(1) writer.WriteInteger(1); // signature (AlgorithmIdentifier) writer.WriteEncodedValue(signatureAlgId); // issuer writer.WriteEncodedValue(issuerName.RawData); // thisUpdate WriteX509Time(writer, thisUpdate); // nextUpdate WriteX509Time(writer, nextUpdate); // revokedCertificates (don't write down if empty) if (_revoked.Count > 0) { // SEQUENCE OF using (writer.PushSequence()) { foreach (RevokedCertificate revoked in _revoked) { // Anonymous CRL Entry type using (writer.PushSequence()) { writer.WriteInteger(revoked.Serial); WriteX509Time(writer, revoked.RevocationTime); if (revoked.Extensions is not null) { writer.WriteEncodedValue(revoked.Extensions); } } } } } // extensions [0] EXPLICIT Extensions using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0))) { // Extensions (SEQUENCE OF) using (writer.PushSequence()) { // Authority Key Identifier Extension using (writer.PushSequence()) { writer.WriteObjectIdentifier(authorityKeyIdentifier.Oid !.Value !); if (authorityKeyIdentifier.Critical) { writer.WriteBoolean(true); } byte[] encodedAkid = authorityKeyIdentifier.RawData; Helpers.ValidateDer(encodedAkid); writer.WriteOctetString(encodedAkid); } // CRL Number Extension using (writer.PushSequence()) { writer.WriteObjectIdentifier(Oids.CrlNumber); using (writer.PushOctetString()) { writer.WriteInteger(crlNumber); } } } } } byte[] tbsCertList = writer.Encode(); writer.Reset(); byte[] signature = generator.SignData(tbsCertList, hashAlgorithm); // CertificateList using (writer.PushSequence()) { writer.WriteEncodedValue(tbsCertList); writer.WriteEncodedValue(signatureAlgId); writer.WriteBitString(signature); } byte[] crl = writer.Encode(); return(crl); }
private static unsafe CertificateRequest LoadSigningRequest( ReadOnlySpan <byte> pkcs10, bool permitTrailingData, HashAlgorithmName signerHashAlgorithm, out int bytesConsumed, CertificateRequestLoadOptions options, RSASignaturePadding?signerSignaturePadding) { ArgumentException.ThrowIfNullOrEmpty(signerHashAlgorithm.Name, nameof(signerHashAlgorithm)); if ((options & ~AllOptions) != 0) { throw new ArgumentOutOfRangeException(nameof(options), options, SR.Argument_InvalidFlag); } bool skipSignatureValidation = (options & CertificateRequestLoadOptions.SkipSignatureValidation) != 0; bool unsafeLoadCertificateExtensions = (options & CertificateRequestLoadOptions.UnsafeLoadCertificateExtensions) != 0; try { AsnValueReader outer = new AsnValueReader(pkcs10, AsnEncodingRules.DER); int encodedLength = outer.PeekEncodedValue().Length; AsnValueReader pkcs10Asn = outer.ReadSequence(); CertificateRequest req; if (!permitTrailingData) { outer.ThrowIfNotEmpty(); } fixed(byte *p10ptr = pkcs10) { using (PointerMemoryManager <byte> manager = new PointerMemoryManager <byte>(p10ptr, encodedLength)) { ReadOnlyMemory <byte> rebind = manager.Memory; ReadOnlySpan <byte> encodedRequestInfo = pkcs10Asn.PeekEncodedValue(); CertificationRequestInfoAsn requestInfo; AlgorithmIdentifierAsn algorithmIdentifier; ReadOnlySpan <byte> signature; int signatureUnusedBitCount; CertificationRequestInfoAsn.Decode(ref pkcs10Asn, rebind, out requestInfo); AlgorithmIdentifierAsn.Decode(ref pkcs10Asn, rebind, out algorithmIdentifier); if (!pkcs10Asn.TryReadPrimitiveBitString(out signatureUnusedBitCount, out signature)) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } pkcs10Asn.ThrowIfNotEmpty(); if (requestInfo.Version < 0) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } // They haven't bumped from v0 to v1 as of 2022. const int MaxSupportedVersion = 0; if (requestInfo.Version != MaxSupportedVersion) { throw new CryptographicException( SR.Format( SR.Cryptography_CertReq_Load_VersionTooNew, requestInfo.Version, MaxSupportedVersion)); } PublicKey publicKey = PublicKey.DecodeSubjectPublicKeyInfo(ref requestInfo.SubjectPublicKeyInfo); if (!skipSignatureValidation) { // None of the supported signature algorithms support signatures that are not full bytes. // So, shortcut the verification on the bit length if (signatureUnusedBitCount != 0 || !VerifyX509Signature(encodedRequestInfo, signature, publicKey, algorithmIdentifier)) { throw new CryptographicException(SR.Cryptography_CertReq_SignatureVerificationFailed); } } X500DistinguishedName subject = new X500DistinguishedName(requestInfo.Subject.Span); req = new CertificateRequest( subject, publicKey, signerHashAlgorithm, signerSignaturePadding); if (requestInfo.Attributes is not null) { bool foundCertExt = false; foreach (AttributeAsn attr in requestInfo.Attributes) { if (attr.AttrType == Oids.Pkcs9ExtensionRequest) { if (foundCertExt) { throw new CryptographicException( SR.Cryptography_CertReq_Load_DuplicateExtensionRequests); } foundCertExt = true; if (attr.AttrValues.Length != 1) { throw new CryptographicException( SR.Cryptography_CertReq_Load_DuplicateExtensionRequests); } AsnValueReader extsReader = new AsnValueReader( attr.AttrValues[0].Span, AsnEncodingRules.DER); AsnValueReader exts = extsReader.ReadSequence(); extsReader.ThrowIfNotEmpty(); // Minimum length is 1, so do..while do { X509ExtensionAsn.Decode(ref exts, rebind, out X509ExtensionAsn extAsn); if (unsafeLoadCertificateExtensions) { X509Extension ext = new X509Extension( extAsn.ExtnId, extAsn.ExtnValue.Span, extAsn.Critical); X509Extension?rich = X509Certificate2.CreateCustomExtensionIfAny(extAsn.ExtnId); if (rich is not null) { rich.CopyFrom(ext); req.CertificateExtensions.Add(rich); } else { req.CertificateExtensions.Add(ext); } } } while (exts.HasData); } else { if (attr.AttrValues.Length == 0) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } foreach (ReadOnlyMemory <byte> val in attr.AttrValues) { req.OtherRequestAttributes.Add( new AsnEncodedData(attr.AttrType, val.Span)); } } } } } } bytesConsumed = encodedLength; return(req); } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } }
/// <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)); }