private byte[] Encode() { // CertificationRequestInfo::= SEQUENCE { // version INTEGER { v1(0) } (v1,...), // subject Name, // subjectPKInfo SubjectPublicKeyInfo{ { PKInfoAlgorithms } }, // attributes[0] Attributes{ { CRIAttributes } } // } // // Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} byte[][] attrSet = Attributes.SegmentedEncodeAttributeSet(); // Replace the tag with ContextSpecific0. attrSet[0][0] = DerSequenceReader.ContextSpecificConstructedTag0; return(DerEncoder.ConstructSequence( s_encodedVersion, Subject.RawData.WrapAsSegmentedForSequence(), PublicKey.SegmentedEncodeSubjectPublicKeyInfo(), attrSet)); }
private byte[] Encode(X509SignatureGenerator signatureGenerator, HashAlgorithmName hashAlgorithm) { // State validation should be runtime checks if/when this becomes public API Debug.Assert(Subject != null); Debug.Assert(PublicKey != null); // Under a public API model we could allow these to be null for a self-signed case. Debug.Assert(SerialNumber != null); Debug.Assert(Issuer != null); List <byte[][]> encodedFields = new List <byte[][]>(); byte version = Version; if (version != 0) { byte[][] encodedVersion = DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeUnsignedInteger(new[] { version })); encodedVersion[0][0] = DerSequenceReader.ContextSpecificConstructedTag0; encodedFields.Add(encodedVersion); } encodedFields.Add(DerEncoder.SegmentedEncodeUnsignedInteger(SerialNumber)); // SignatureAlgorithm: Use the specified value, or ask the generator (without mutating the class) byte[] signatureAlgorithm = SignatureAlgorithm ?? signatureGenerator.GetSignatureAlgorithmIdentifier(hashAlgorithm); EncodingHelpers.ValidateSignatureAlgorithm(signatureAlgorithm); encodedFields.Add(signatureAlgorithm.WrapAsSegmentedForSequence()); // For public API allowing self-sign ease-of-use, this could be (Issuer ?? Subject). encodedFields.Add(Issuer.RawData.WrapAsSegmentedForSequence()); encodedFields.Add( DerEncoder.ConstructSegmentedSequence( EncodeValidityField(NotBefore, nameof(NotBefore)), EncodeValidityField(NotAfter, nameof(NotAfter)))); encodedFields.Add(Subject.RawData.WrapAsSegmentedForSequence()); encodedFields.Add(PublicKey.SegmentedEncodeSubjectPublicKeyInfo()); // Issuer and Subject Unique ID values would go here, if they were supported. if (Extensions.Count > 0) { Debug.Assert(version >= 2); List <byte[][]> encodedExtensions = new List <byte[][]>(Extensions.Count); // extensions[3] Extensions OPTIONAL // // Since this doesn't say IMPLICIT, it will look like // // A3 [length] // 30 [length] // First Extension // Second Extension // ... // An interesting quirk of skipping null values here is that // Extensions.Count == 0 => no extensions // Extensions.ContainsOnly(null) => empty extensions list HashSet <string> usedOids = new HashSet <string>(Extensions.Count); foreach (X509Extension extension in Extensions) { if (extension == null) { continue; } if (!usedOids.Add(extension.Oid.Value)) { throw new InvalidOperationException( SR.GetString(SR.Cryptography_CertReq_DuplicateExtension, extension.Oid.Value)); } encodedExtensions.Add(extension.SegmentedEncodedX509Extension()); } byte[][] extensionField = DerEncoder.ConstructSegmentedSequence( DerEncoder.ConstructSegmentedSequence(encodedExtensions)); extensionField[0][0] = DerSequenceReader.ContextSpecificConstructedTag3; encodedFields.Add(extensionField); } return(DerEncoder.ConstructSequence(encodedFields)); }