3

I am currently working on generating a Certificate Request using CertificateEnrollmentManager from Windows.Security.Cryptography.Certificates. The CSR has been successfully generated but its extensions have different attributes than what I specified in the CertificateRequestProperties.

This is the request properties:

           var basicConstraint = new CertificateExtension
            {
                ObjectId = Constants.Oids.BASIC_CONSTRAINT,
                IsCritical = false,
                Value = new BasicConstraints(false).GetEncoded()
            };

            var extendedKeyUsage = new CertificateExtension
            {
                ObjectId = Constants.Oids.EXTENDED_KEY_USAGE,
                IsCritical = false,
                Value = new ExtendedKeyUsage(
                    new[] {KeyPurposeID.IdKPClientAuth}
                ).GetEncoded()
            };

            var keyUsage = new CertificateExtension
            {
                ObjectId = Constants.Oids.KEY_USAGE,
                IsCritical = false,
                Value = new KeyUsage(KeyUsage.DigitalSignature).GetEncoded()
            };
            
            var certificateRequestProperties = new CertificateRequestProperties
            {
                Subject = subject,
                KeyUsages = EnrollKeyUsages.Signing,
                KeyStorageProviderName = microsoftPlatformCryptoProvider,
                Exportable = ExportOption.NotExportable,
                KeyProtectionLevel = keyProtectionLevel,
                KeyAlgorithmName = keyAlgorithmName,
                HashAlgorithmName = hashAlgorithmName,
                FriendlyName = CERTIFICATE_FRIENDLY_NAME,
                Extensions = {basicConstraint, extendedKeyUsage, keyUsage},
                UseExistingKey = false
            }; 

This is how I generate the SCR:

 var csr = await CertificateEnrollmentManager.UserCertificateEnrollmentManager
            .CreateRequestAsync(certificateRequestProperties);

The CSR is successfully generated but it generated the incorrect extensions:(Excluded some attributes for brevity)

BasicConstraints=ObjectId: 2.5.29.19 Criticality=true
ExtendedKeyUsage=ObjectId: 2.5.29.37 Criticality=false
KeyUsage=ObjectId: 2.5.29.15 Criticality=true
SubjectKeyIdentifier=ObjectId: 2.5.29.14 Criticality=false

What is wrong with the generated CSR:

  • It has automatically added SubjectKeyIdentifier, but I only specified 3 extensions.
  • The criticality is NOT as specified in the properties. I specified false, but it generated true.

My question is, how can I generate the CSR as I specified in the request properties?

PS:

  • We can't just modify the received CSR on the server-side.
  • I am required to use TPM (MicrosoftPlatformCryptoProvider) for the CSR so private keys are not exportable.
jamsubzero
  • 31
  • 4
  • Check if [Web Browser Certificate Enrollment (CSR Generation) and Certificate Download to Smartcard or USB Token](https://stackoverflow.com/a/68556286/9659885) is useful – Bharat Vasant May 04 '22 at 13:06
  • The System.Security.Cryptography.X509Certificates.CertificateRequest class doesn’t add anything you don’t ask for. It might do more what you want (though it has no facility to send the CSR anywhere, that’s a problem left to the caller). – bartonjs Jun 17 '22 at 16:55

1 Answers1

0

I solved it myself and the answer is very simple. It turns out that we can suppress the defaults using the SuppressedDefaults property in the request. Documented here.

So the request properties will look like:

// added new constant
public const string SUBJECT_KEY_IDENTIFIER = "2.5.29.14";

// updated request properties
var certificateRequestProperties = new CertificateRequestProperties
        {
            Subject = subject,
            KeyUsages = EnrollKeyUsages.Signing,
            KeyStorageProviderName = microsoftPlatformCryptoProvider,
            Exportable = ExportOption.NotExportable,
            KeyProtectionLevel = keyProtectionLevel,
            KeyAlgorithmName = keyAlgorithmName,
            HashAlgorithmName = hashAlgorithmName,
            FriendlyName = CERTIFICATE_FRIENDLY_NAME,
            Extensions = {basicConstraint, extendedKeyUsage, keyUsage},
            UseExistingKey = false,
            SuppressedDefaults = { SUBJECT_KEY_IDENTIFIER } 
        }; 

I'm pretty sure I tried this solution before I posted the problem here, but perhaps I just used the wrong OID back then.

jamsubzero
  • 31
  • 4