Example #1
0
        private OcspReq GenerateOcspRequest(CertificateID id, GeneralName requestorName,
                                            System.Security.Cryptography.X509Certificates.X509Certificate2 signCertificate, bool addNonce)
        {
            OcspReqGenerator ocspRequestGenerator = new OcspReqGenerator();

            ocspRequestGenerator.AddRequest(id);

            if (requestorName != null)
            {
                ocspRequestGenerator.SetRequestorName(requestorName);
            }

            if (addNonce)
            {
                List <DerObjectIdentifier> oids = new List <DerObjectIdentifier>();
                Hashtable values = new Hashtable();

                oids.Add(OcspObjectIdentifiers.PkixOcspNonce);

                _nonceAsn1OctetString = new DerOctetString(new DerOctetString(BigInteger.ValueOf(DateTime.Now.Ticks).ToByteArray()));

                values.Add(OcspObjectIdentifiers.PkixOcspNonce, new Org.BouncyCastle.Asn1.X509.X509Extension(false, _nonceAsn1OctetString));
                ocspRequestGenerator.SetRequestExtensions(new X509Extensions(oids, values));
            }
            if (signCertificate != null)
            {
                return(ocspRequestGenerator.Generate(signCertificate.GetRSAPrivateKey(), CertUtil.GetCertChain(signCertificate)));
            }
            else
            {
                return(ocspRequestGenerator.Generate());
            }
        }
Example #2
0
        public IActionResult PingCert()
        {
            var cert       = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath);
            var privateKey = cert.GetRSAPrivateKey();

            return(Ok("pong - cert OK"));
        }
Example #3
0
        /// <summary>
        /// Create a certificate using the established subject, key, and optional extensions using
        /// the provided certificate as the issuer.
        /// </summary>
        /// <param name="issuerCertificate">
        ///   An X509Certificate2 instance representing the issuing Certificate Authority (CA).
        /// </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="issuerCertificate"/> is null.</exception>
        /// <exception cref="ArgumentException">
        ///   The <see cref="X509Certificate2.HasPrivateKey"/> value for <paramref name="issuerCertificate"/> is false.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   The type of signing key represented by <paramref name="issuerCertificate"/> could not be determined.
        /// </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>
        public X509Certificate2 Create(
            X509Certificate2 issuerCertificate,
            DateTimeOffset notBefore,
            DateTimeOffset notAfter,
            byte[] serialNumber)
        {
            if (issuerCertificate == null)
            {
                throw new ArgumentNullException(nameof(issuerCertificate));
            }
            if (!issuerCertificate.HasPrivateKey)
            {
                throw new ArgumentException(SR.Cryptography_CertReq_IssuerRequiresPrivateKey, nameof(issuerCertificate));
            }

            AsymmetricAlgorithm key = null;
            string keyAlgorithm     = issuerCertificate.GetKeyAlgorithm();
            X509SignatureGenerator generator;

            try
            {
                switch (keyAlgorithm)
                {
                case Oids.RsaRsa:
                    RSA rsa = issuerCertificate.GetRSAPrivateKey();
                    key       = rsa;
                    generator = X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1);
                    break;

                case Oids.Ecc:
                    ECDsa ecdsa = issuerCertificate.GetECDsaPrivateKey();
                    key       = ecdsa;
                    generator = X509SignatureGenerator.CreateForECDsa(ecdsa);
                    break;

                default:
                    throw new ArgumentException(
                              SR.Format(SR.Cryptography_UnknownKeyAlgorithm, keyAlgorithm),
                              nameof(issuerCertificate));
                }

                return(Create(issuerCertificate.SubjectName, generator, notBefore, notAfter, serialNumber));
            }
            finally
            {
                key?.Dispose();
            }
        }
        /// <summary>
        /// Export private key
        /// </summary>
        /// <param name="certificate"></param>
        /// <returns></returns>
        internal static Key ExportPrivateKey(this X509Certificate2 certificate)
        {
            var rsa = certificate.GetRSAPrivateKey();

            if (rsa != null)
            {
                using (rsa) {
                    return(rsa.ToKey());
                }
            }
            var ecdsa = certificate.GetECDsaPrivateKey();

            if (ecdsa != null)
            {
                using (ecdsa) {
                    return(ecdsa.ToKey());
                }
            }
            return(null);
        }
        /// <summary>
        /// Create a certificate using the established subject, key, and optional extensions using
        /// the provided certificate as the issuer.
        /// </summary>
        /// <param name="issuerCertificate">
        ///   An X509Certificate2 instance representing the issuing Certificate Authority (CA).
        /// </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="issuerCertificate"/> is null.</exception>
        /// <exception cref="ArgumentException">
        ///   The <see cref="X509Certificate2.HasPrivateKey"/> value for <paramref name="issuerCertificate"/> is false.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   The type of signing key represented by <paramref name="issuerCertificate"/> could not be determined.
        /// </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="ArgumentException">
        ///   <paramref name="issuerCertificate"/> has a different key algorithm than the requested certificate.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///   <paramref name="issuerCertificate"/> is an RSA certificate and this object was created via a constructor
        ///   which does not accept a <see cref="RSASignaturePadding"/> value.
        /// </exception>
        public X509Certificate2 Create(
            X509Certificate2 issuerCertificate,
            DateTimeOffset notBefore,
            DateTimeOffset notAfter,
            ReadOnlySpan <byte> serialNumber)
        {
            if (issuerCertificate == null)
            {
                throw new ArgumentNullException(nameof(issuerCertificate));
            }
            if (!issuerCertificate.HasPrivateKey)
            {
                throw new ArgumentException(SR.Cryptography_CertReq_IssuerRequiresPrivateKey, nameof(issuerCertificate));
            }
            if (notAfter < notBefore)
            {
                throw new ArgumentException(SR.Cryptography_CertReq_DatesReversed);
            }
            if (serialNumber.IsEmpty)
            {
                throw new ArgumentException(SR.Arg_EmptyOrNullArray, nameof(serialNumber));
            }

            if (issuerCertificate.PublicKey.Oid.Value != PublicKey.Oid.Value)
            {
                throw new ArgumentException(
                          SR.Format(
                              SR.Cryptography_CertReq_AlgorithmMustMatch,
                              issuerCertificate.PublicKey.Oid.Value,
                              PublicKey.Oid.Value),
                          nameof(issuerCertificate));
            }

            DateTime notBeforeLocal = notBefore.LocalDateTime;

            if (notBeforeLocal < issuerCertificate.NotBefore)
            {
                throw new ArgumentException(
                          SR.Format(
                              SR.Cryptography_CertReq_NotBeforeNotNested,
                              notBeforeLocal,
                              issuerCertificate.NotBefore),
                          nameof(notBefore));
            }

            DateTime notAfterLocal = notAfter.LocalDateTime;

            // Round down to the second, since that's the cert accuracy.
            // This makes one method which uses the same DateTimeOffset for chained notAfters
            // not need to do the rounding locally.
            long notAfterLocalTicks = notAfterLocal.Ticks;
            long fractionalSeconds  = notAfterLocalTicks % TimeSpan.TicksPerSecond;

            notAfterLocalTicks -= fractionalSeconds;
            notAfterLocal       = new DateTime(notAfterLocalTicks, notAfterLocal.Kind);

            if (notAfterLocal > issuerCertificate.NotAfter)
            {
                throw new ArgumentException(
                          SR.Format(
                              SR.Cryptography_CertReq_NotAfterNotNested,
                              notAfterLocal,
                              issuerCertificate.NotAfter),
                          nameof(notAfter));
            }

            // Check the Basic Constraints and Key Usage extensions to help identify inappropriate certificates.
            // Note that this is not a security check. The system library backing X509Chain will use these same criteria
            // to determine if a chain is valid; and a user can easily call the X509SignatureGenerator overload to
            // bypass this validation.  We're simply helping them at signing time understand that they've
            // chosen the wrong cert.
            var basicConstraints = (X509BasicConstraintsExtension?)issuerCertificate.Extensions[Oids.BasicConstraints2];
            var keyUsage         = (X509KeyUsageExtension?)issuerCertificate.Extensions[Oids.KeyUsage];

            if (basicConstraints == null)
            {
                throw new ArgumentException(SR.Cryptography_CertReq_BasicConstraintsRequired, nameof(issuerCertificate));
            }
            if (!basicConstraints.CertificateAuthority)
            {
                throw new ArgumentException(SR.Cryptography_CertReq_IssuerBasicConstraintsInvalid, nameof(issuerCertificate));
            }
            if (keyUsage != null && (keyUsage.KeyUsages & X509KeyUsageFlags.KeyCertSign) == 0)
            {
                throw new ArgumentException(SR.Cryptography_CertReq_IssuerKeyUsageInvalid, nameof(issuerCertificate));
            }

            AsymmetricAlgorithm?key = null;
            string keyAlgorithm     = issuerCertificate.GetKeyAlgorithm();
            X509SignatureGenerator generator;

            try
            {
                switch (keyAlgorithm)
                {
                case Oids.Rsa:
                    if (_rsaPadding == null)
                    {
                        throw new InvalidOperationException(SR.Cryptography_CertReq_RSAPaddingRequired);
                    }

                    RSA?rsa = issuerCertificate.GetRSAPrivateKey();
                    key       = rsa;
                    generator = X509SignatureGenerator.CreateForRSA(rsa !, _rsaPadding);
                    break;

                case Oids.EcPublicKey:
                    ECDsa?ecdsa = issuerCertificate.GetECDsaPrivateKey();
                    key       = ecdsa;
                    generator = X509SignatureGenerator.CreateForECDsa(ecdsa !);
                    break;

                default:
                    throw new ArgumentException(
                              SR.Format(SR.Cryptography_UnknownKeyAlgorithm, keyAlgorithm),
                              nameof(issuerCertificate));
                }

                return(Create(issuerCertificate.SubjectName, generator, notBefore, notAfter, serialNumber));
            }
            finally
            {
                key?.Dispose();
            }
        }
        /// <summary>
        /// Loads the private key from a PFX file in the certificate store.
        /// </summary>
        public X509Certificate2 LoadPrivateKey(string thumbprint, string subjectName, string password)
        {
            if (m_certificateSubdir == null || !m_certificateSubdir.Exists)
            {
                return null;
            }

            if (string.IsNullOrEmpty(thumbprint) && string.IsNullOrEmpty(subjectName))
            {
                return null;
            }

            foreach (FileInfo file in m_certificateSubdir.GetFiles("*.der"))
            {
                try
                {
                    X509Certificate2 certificate = new X509Certificate2(file.FullName);

                    if (!String.IsNullOrEmpty(thumbprint))
                    {
                        if (!string.Equals(certificate.Thumbprint, thumbprint, StringComparison.CurrentCultureIgnoreCase))
                        {
                            continue;
                        }
                    }

                    if (!String.IsNullOrEmpty(subjectName))
                    {
                        if (!Utils.CompareDistinguishedName(subjectName, certificate.Subject))
                        {
                            if (subjectName.Contains("=") || !certificate.Subject.Contains("CN=" + subjectName))
                            {
                                continue;
                            }
                        }
                    }

                    string fileRoot = file.Name.Substring(0, file.Name.Length - file.Extension.Length);

                    StringBuilder filePath = new StringBuilder();
                    filePath.Append(m_privateKeySubdir.FullName);
                    filePath.Append(Path.DirectorySeparatorChar);
                    filePath.Append(fileRoot);

                    FileInfo privateKeyFile = new FileInfo(filePath.ToString() + ".pfx");
                    RSA rsa = null;

                    try
                    {
                        certificate = new X509Certificate2(
                            privateKeyFile.FullName,
                            (password == null) ? String.Empty : password,
                            X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
                        rsa = certificate.GetRSAPrivateKey();
                    }
                    catch (Exception)
                    {
                        certificate = new X509Certificate2(
                            privateKeyFile.FullName,
                            (password == null) ? String.Empty : password,
                            X509KeyStorageFlags.Exportable | X509KeyStorageFlags.DefaultKeySet);
                        rsa = certificate.GetRSAPrivateKey();
                    }
                    if (rsa != null)
                    {
                        int inputBlockSize = rsa.KeySize / 8 - 42;
                        byte[] bytes1 = rsa.Encrypt(new byte[inputBlockSize], RSAEncryptionPadding.OaepSHA1);
                        byte[] bytes2 = rsa.Decrypt(bytes1, RSAEncryptionPadding.OaepSHA1);
                        if (bytes2 != null)
                        {
                            // Utils.Trace(1, "RSA: {0}", certificate.Thumbprint);
                            return certificate;
                        }
                    }
                }
                catch (Exception e)
                {
                    Utils.Trace(e, "Could not load private key for certificate " + subjectName);
                }
            }

            return null;
        }
        /// <summary>
        /// Computes an RSA/SHA1 PKCS#1 v1.5 signature.
        /// </summary>
        public static byte[] RsaPkcs15Sha1_Sign(
            ArraySegment<byte> dataToSign,
            X509Certificate2 signingCertificate)
        {
            // extract the private key.
            using (RSA rsa = signingCertificate.GetRSAPrivateKey())
            {

                if (rsa == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate.");
                }

                // create the signature.
                return rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
            }
        }
        /// <summary>
        /// Des the message using RSA OAEP encryption.
        /// </summary>
        public static ArraySegment<byte> Decrypt(
            ArraySegment<byte> dataToDecrypt,
            X509Certificate2 encryptingCertificate,
            bool useOaep,
            ArraySegment<byte> outputBuffer)
        {
            // get the encrypting key.
            using (RSA rsa = encryptingCertificate.GetRSAPrivateKey())
            {
                if (rsa == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate.");
                }

                int inputBlockSize = rsa.KeySize / 8;
                int outputBlockSize = GetPlainTextBlockSize(encryptingCertificate, useOaep);

                // verify the input data is the correct block size.
                if (dataToDecrypt.Count % inputBlockSize != 0)
                {
                    Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize);
                }

                byte[] decryptedBuffer = outputBuffer.Array;

                using (MemoryStream ostrm = new MemoryStream(
                    decryptedBuffer,
                    outputBuffer.Offset,
                    outputBuffer.Count))
                {

                    // decrypt body.
                    byte[] input = new byte[inputBlockSize];

                    for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize)
                    {
                        Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length);
                        if (useOaep == true)
                        {
                            byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1);
                            ostrm.Write(plainText, 0, plainText.Length);
                        }
                        else
                        {
                            byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1);
                            ostrm.Write(plainText, 0, plainText.Length);
                        }
                    }
                }

                // return buffers.
                return new ArraySegment<byte>(decryptedBuffer, outputBuffer.Offset, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize);
            }
        }
        /// <summary>
        /// Creates a certificate from a PKCS #12 store with a private key.
        /// </summary>
        /// <param name="rawData">The raw PKCS #12 store data.</param>
        /// <param name="password">The password to use to access the store.</param>
        /// <returns>The certificate with a private key.</returns>
        public static X509Certificate2 CreateCertificateFromPKCS12(
            byte[] rawData, 
            string password
            )
        {
            Exception ex = null;
            int flagsRetryCounter = 0;
            X509Certificate2 certificate = null;
            X509KeyStorageFlags[] storageFlags = {
                X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet,
                X509KeyStorageFlags.Exportable | X509KeyStorageFlags.DefaultKeySet
            };

            // try some combinations of storage flags, support is platform dependent
            while (certificate == null &&
                flagsRetryCounter < storageFlags.Length)
            {
                try
                {
                    // merge first cert with private key into X509Certificate2
                    certificate = new X509Certificate2(
                        rawData, 
                        (password == null) ? String.Empty : password, 
                        storageFlags[flagsRetryCounter]);
                    // can we really access the private key?
                    using (RSA rsa = certificate.GetRSAPrivateKey()) { }
                }
                catch (Exception e)
                {
                    ex = e;
                    certificate = null;
                }
                flagsRetryCounter++;
            }

            if (certificate == null)
            {
                throw new NotSupportedException("Creating X509Certificate from PKCS #12 store failed", ex);
            }

            return certificate;
        }
        private byte[] Build(
            X509Certificate2 issuerCertificate,
            BigInteger crlNumber,
            DateTimeOffset nextUpdate,
            DateTimeOffset thisUpdate,
            HashAlgorithmName hashAlgorithm,
            RSASignaturePadding?rsaSignaturePadding)
        {
            ArgumentNullException.ThrowIfNull(issuerCertificate);

            if (!issuerCertificate.HasPrivateKey)
            {
                throw new ArgumentException(
                          SR.Cryptography_CertReq_IssuerRequiresPrivateKey,
                          nameof(issuerCertificate));
            }
            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));

            // Check the Basic Constraints and Key Usage extensions to help identify inappropriate certificates.
            // Note that this is not a security check. The system library backing X509Chain will use these same criteria
            // to determine if the CRL is valid; and a user can easily call the X509SignatureGenerator overload to
            // bypass this validation.  We're simply helping them at signing time understand that they've
            // chosen the wrong cert.
            var basicConstraints     = (X509BasicConstraintsExtension?)issuerCertificate.Extensions[Oids.BasicConstraints2];
            var keyUsage             = (X509KeyUsageExtension?)issuerCertificate.Extensions[Oids.KeyUsage];
            var subjectKeyIdentifier =
                (X509SubjectKeyIdentifierExtension?)issuerCertificate.Extensions[Oids.SubjectKeyIdentifier];

            if (basicConstraints == null)
            {
                throw new ArgumentException(
                          SR.Cryptography_CertReq_BasicConstraintsRequired,
                          nameof(issuerCertificate));
            }

            if (!basicConstraints.CertificateAuthority)
            {
                throw new ArgumentException(
                          SR.Cryptography_CertReq_IssuerBasicConstraintsInvalid,
                          nameof(issuerCertificate));
            }

            if (keyUsage != null && (keyUsage.KeyUsages & X509KeyUsageFlags.CrlSign) == 0)
            {
                throw new ArgumentException(
                          SR.Cryptography_CRLBuilder_IssuerKeyUsageInvalid,
                          nameof(issuerCertificate));
            }

            AsymmetricAlgorithm?key = null;
            string keyAlgorithm     = issuerCertificate.GetKeyAlgorithm();
            X509SignatureGenerator generator;

            try
            {
                switch (keyAlgorithm)
                {
                case Oids.Rsa:
                    if (rsaSignaturePadding is null)
                    {
                        throw new ArgumentException(SR.Cryptography_CertReq_RSAPaddingRequired);
                    }

                    RSA?rsa = issuerCertificate.GetRSAPrivateKey();
                    key       = rsa;
                    generator = X509SignatureGenerator.CreateForRSA(rsa !, rsaSignaturePadding);
                    break;

                case Oids.EcPublicKey:
                    ECDsa?ecdsa = issuerCertificate.GetECDsaPrivateKey();
                    key       = ecdsa;
                    generator = X509SignatureGenerator.CreateForECDsa(ecdsa !);
                    break;

                default:
                    throw new ArgumentException(
                              SR.Format(SR.Cryptography_UnknownKeyAlgorithm, keyAlgorithm),
                              nameof(issuerCertificate));
                }

                X509AuthorityKeyIdentifierExtension akid;

                if (subjectKeyIdentifier is not null)
                {
                    akid = X509AuthorityKeyIdentifierExtension.CreateFromSubjectKeyIdentifier(subjectKeyIdentifier);
                }
                else
                {
                    akid = X509AuthorityKeyIdentifierExtension.CreateFromIssuerNameAndSerialNumber(
                        issuerCertificate.IssuerName,
                        issuerCertificate.SerialNumberBytes.Span);
                }

                return(Build(
                           issuerCertificate.SubjectName,
                           generator,
                           crlNumber,
                           nextUpdate,
                           thisUpdate,
                           hashAlgorithm,
                           akid));
            }
            finally
            {
                key?.Dispose();
            }
        }
            /// <summary>Extracts a <see cref="Key"/> from the given certificate.</summary>
            public Initializer FromCertificate(X509Certificate2 certificate)
            {
#if NETSTANDARD
                Key = certificate.GetRSAPrivateKey();
#else
                // Workaround to correctly cast the private key as a RSACryptoServiceProvider type 24.
                RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)certificate.PrivateKey;
                byte[] privateKeyBlob = rsa.ExportCspBlob(true);
                Key = new RSACryptoServiceProvider();
                Key.ImportCspBlob(privateKeyBlob);
#endif
                return this;
            }