File: System\Security\Cryptography\X509Certificates\Pkcs10CertificationRequestInfo.cs
Web Access
Project: src\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Formats.Asn1;
using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.X509Certificates.Asn1;
using Internal.Cryptography;
 
namespace System.Security.Cryptography.X509Certificates
{
    internal sealed class Pkcs10CertificationRequestInfo
    {
        internal X500DistinguishedName Subject { get; set; }
        internal PublicKey PublicKey { get; set; }
        internal Collection<X501Attribute> Attributes { get; } = new Collection<X501Attribute>();
 
        internal Pkcs10CertificationRequestInfo(
            X500DistinguishedName subject,
            PublicKey publicKey,
            IEnumerable<X501Attribute> attributes)
        {
            ArgumentNullException.ThrowIfNull(subject);
            ArgumentNullException.ThrowIfNull(publicKey);
 
            Subject = subject;
            PublicKey = publicKey;
 
            if (attributes != null)
            {
                Attributes.AddRange(attributes);
            }
        }
 
        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();
        }
    }
}