Esempio n. 1
0
        /// <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 = AsnSerializer.Deserialize <AlgorithmIdentifierAsn>(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, false));
                }

                tbsCertificate.Extensions = extensionAsns.ToArray();
            }

            using (AsnWriter writer = AsnSerializer.Serialize(tbsCertificate, AsnEncodingRules.DER))
            {
                byte[]         encodedTbsCertificate = writer.Encode();
                CertificateAsn certificate           = new CertificateAsn
                {
                    TbsCertificate     = tbsCertificate,
                    SignatureAlgorithm = signatureAlgorithmAsn,
                    SignatureValue     = generator.SignData(encodedTbsCertificate, HashAlgorithm),
                };

                using (AsnWriter signedWriter = AsnSerializer.Serialize(certificate, AsnEncodingRules.DER))
                {
                    return(new X509Certificate2(signedWriter.Encode()));
                }
            }
        }