/// <summary>
        /// Create a Self signed certificate with all options which can also be used as a root certificate
        /// </summary>
        /// <param name="distinguishedName">Distinguished Name used for the subject and the issuer properties</param>
        /// <param name="validityPeriod">Valid from, Valid to certificate properties</param>
        /// <param name="subjectAlternativeName">SAN but only DnsNames can be added as a list + Email property</param>
        /// <param name="enhancedKeyUsages">Defines how the certificate key can be used.
        ///  new Oid("1.3.6.1.5.5.7.3.1")  // TLS Server auth
        ///  new Oid("1.3.6.1.5.5.7.3.2")  // TLS Client auth
        ///  new Oid("1.3.6.1.5.5.7.3.3")  // Code signing
        ///  new Oid("1.3.6.1.5.5.7.3.4")  // Email
        ///  new Oid("1.3.6.1.5.5.7.3.8")  // Timestamping
        /// </param>
        /// <param name="x509KeyUsageFlags">Defines how the certificate key can be used.
        ///  None             No key usage parameters.
        ///  EncipherOnly     The key can be used for encryption only.
        ///  CrlSign          The key can be used to sign a certificate revocation list (CRL).
        ///  KeyCertSign      The key can be used to sign certificates.
        ///  KeyAgreement     The key can be used to determine key agreement, such as a key created using the Diffie-Hellman key agreement algorithm.
        ///  DataEncipherment The key can be used for data encryption.
        ///  KeyEncipherment  The key can be used for key encryption.
        ///  NonRepudiation   The key can be used for authentication.
        ///  DecipherOnly     The key can be used for decryption only.
        ///  </param>
        /// <returns>Self signed certificate</returns>
        public X509Certificate2 NewSelfSignedCertificate(
            DistinguishedName distinguishedName,
            BasicConstraints basicConstraints,
            ValidityPeriod validityPeriod,
            SubjectAlternativeName subjectAlternativeName,
            OidCollection enhancedKeyUsages,
            X509KeyUsageFlags x509KeyUsageFlags)
        {
            using var ecdsa = ECDsa.Create("ECDsa");

            ecdsa.KeySize = 256;
            var request = new CertificateRequest(
                _certificateUtility.CreateIssuerOrSubject(distinguishedName),
                ecdsa,
                HashAlgorithmName.SHA256);

            _certificateUtility.AddBasicConstraints(request, basicConstraints);
            _certificateUtility.AddExtendedKeyUsages(request, x509KeyUsageFlags);
            _certificateUtility.AddSubjectAlternativeName(request, subjectAlternativeName);

            request.CertificateExtensions.Add(
                new X509EnhancedKeyUsageExtension(enhancedKeyUsages, false));

            request.CertificateExtensions.Add(
                new X509SubjectKeyIdentifierExtension(request.PublicKey, false));

            var notbefore = validityPeriod.ValidFrom.AddDays(-1);
            var notafter  = validityPeriod.ValidTo;
            X509Certificate2 generatedCertificate = request.CreateSelfSigned(notbefore, notafter);

            return(generatedCertificate);
        }
Example #2
0
        private X509Certificate2 ChainedConfiguration(BasicConstraints basicConstraints, ValidityPeriod validityPeriod, SubjectAlternativeName subjectAlternativeName, X509Certificate2 signingCertificate, OidCollection enhancedKeyUsages, X509KeyUsageFlags x509KeyUsageFlags, CertificateRequest request)
        {
            _certificateUtility.AddBasicConstraints(request, basicConstraints);
            _certificateUtility.AddExtendedKeyUsages(request, x509KeyUsageFlags);

            // set the AuthorityKeyIdentifier. There is no built-in
            // support, so it needs to be copied from the Subject Key
            // Identifier of the signing certificate and massaged slightly.
            // AuthorityKeyIdentifier is "KeyID=<subject key identifier>"
            var issuerSubjectKey       = signingCertificate.Extensions["Subject Key Identifier"].RawData;
            var segment                = new ArraySegment <byte>(issuerSubjectKey, 2, issuerSubjectKey.Length - 2);
            var authorityKeyIdentifier = new byte[segment.Count + 4];

            // "KeyID" bytes
            authorityKeyIdentifier[0] = 0x30;
            authorityKeyIdentifier[1] = 0x16;
            authorityKeyIdentifier[2] = 0x80;
            authorityKeyIdentifier[3] = 0x14;
            segment.CopyTo(authorityKeyIdentifier, 4);
            request.CertificateExtensions.Add(new X509Extension("2.5.29.35", authorityKeyIdentifier, false));

            _certificateUtility.AddSubjectAlternativeName(request, subjectAlternativeName);

            // Enhanced key usages
            request.CertificateExtensions.Add(
                new X509EnhancedKeyUsageExtension(enhancedKeyUsages, false));

            // add this subject key identifier
            request.CertificateExtensions.Add(
                new X509SubjectKeyIdentifierExtension(request.PublicKey, false));

            // certificate expiry: Valid from Yesterday to Now+365 days
            // Unless the signing cert's validity is less. It's not possible
            // to create a cert with longer validity than the signing cert.
            var notbefore = validityPeriod.ValidFrom.AddDays(-1);

            if (notbefore < signingCertificate.NotBefore)
            {
                notbefore = new DateTimeOffset(signingCertificate.NotBefore);
            }

            var notafter = validityPeriod.ValidTo;

            if (notafter > signingCertificate.NotAfter)
            {
                notafter = new DateTimeOffset(signingCertificate.NotAfter);
            }

            // cert serial is the epoch/unix timestamp
            var epoch    = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            var unixTime = Convert.ToInt64((DateTime.UtcNow - epoch).TotalSeconds);
            var serial   = BitConverter.GetBytes(unixTime);
            var cert     = request.Create(
                signingCertificate,
                notbefore,
                notafter,
                serial);

            return(cert);
        }