Due to a bug in Windows Azure, all self-signed client certificates used with the Azure REST API from a Windows 8 application must be listed as extended verification certificates.
To provide a better user experience, I am trying to create this self-signed certificate on a remote server. I am using the Certificate Certification API , a COM library distributed as part of Windows, as described in this answer to the question How to create a self-signed certificate using C #?
The code is basically the same, slightly modified for my use:
public static X509Certificate2 CreateSelfSignedCertificate( string cname, string friendlyName, string password) { // create DN for subject and issuer var dn = new CX500DistinguishedName(); dn.Encode("CN=" + cname, X500NameFlags.XCN_CERT_NAME_STR_NONE); // create a new private key for the certificate CX509PrivateKey privateKey = new CX509PrivateKey(); privateKey.ProviderName = "Microsoft Base Cryptographic Provider v1.0"; privateKey.MachineContext = true; privateKey.Length = 2048; privateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE; // use is not limited privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG; privateKey.Create(); // Use the stronger SHA512 hashing algorithm var hashobj = new CObjectId(); hashobj.InitializeFromAlgorithmName( ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "SHA512"); // Create the self signing request var cert = new CX509CertificateRequestCertificate(); cert.InitializeFromPrivateKey( X509CertificateEnrollmentContext.ContextMachine, privateKey, string.Empty); cert.Subject = dn; cert.Issuer = dn; // the issuer and the subject are the same cert.NotBefore = DateTime.Now; cert.NotAfter = DateTime.Now.AddYears(50); cert.HashAlgorithm = hashobj; var clientAuthenticationOid = new CObjectId(); clientAuthenticationOid.InitializeFromValue("1.3.6.1.5.5.7.3.2"); // Set up cert to be used for Client Authentication. var oids = new CObjectIds(); oids.Add(clientAuthenticationOid); var eku = new CX509ExtensionEnhancedKeyUsage(); eku.InitializeEncode(oids); cert.X509Extensions.Add((CX509Extension)eku); // Add the certificate policy. var policy = new CCertificatePolicy(); policy.Initialize(clientAuthenticationOid); // THIS IS WRONG - NEEDS A DIFFERENT QUALIFIER var qualifier = new CPolicyQualifier(); qualifier.InitializeEncode( "c0", PolicyQualifierType.PolicyQualifierTypeUserNotice); policy.PolicyQualifiers.Add(qualifier); var policies = new CCertificatePolicies(); policies.Add(policy); var ecp = new CX509ExtensionCertificatePolicies(); ecp.InitializeEncode(policies); cert.X509Extensions.Add((CX509Extension)ecp); cert.Encode(); // Do the final enrolment process var enroll = new CX509Enrollment(); enroll.InitializeFromRequest(cert); // load the certificate enroll.CertificateFriendlyName = friendlyName; string csr = enroll.CreateRequest(); // Output the request in base64 // and install it back as the response enroll.InstallResponse( InstallResponseRestrictionFlags.AllowUntrustedCertificate, csr, EncodingType.XCN_CRYPT_STRING_BASE64, ""); // no password // output a base64 encoded PKCS
I found the ICertificatePolicy interface, which appears to be the correct type of structure, but I cannot infer the correct IPolicyQualifier to use. In my code, the qualifier
For clarity, this is when you configure the information in the Windows 8 Certificate Manager:

What creates this property in the certificate:

My code is currently creating this property:

Close, but not yet.
Is there any other way to load data into IPolicyQualifier so that it IPolicyQualifier expected result, possibly using the InitialiseDecode method?