2011-04-01

Enabling the Issuer Statement button on a Windows certificate

You may have seen a few of these certificates where clicking on the "Issuer Statement" button brings you to a specific webpage, usually a "Certification Practice Statement", or CPS, on the issuer's webserver. Maybe you've wondered how you could achieve the same on certificates you generate? Well, wonder no more.

It basically all boils down to adding a CPS Policy Identifier in the Certificate Policies field, and the Windows PKI API provides everything you need to do so:

  DWORD dwSize;
  CERT_POLICY_QUALIFIER_INFO certPolicyQualifier;
  CERT_POLICY_INFO certPolicyInfo = { "1.3.6.1.5.5.7.2.1", 1, &certPolicyQualifier };
  CERT_POLICIES_INFO certPolicyInfoArray = { 1, &certPolicyInfo };
  CHAR szCPSName[] = "http://cps-page.yourserver.com";
  CERT_NAME_VALUE certCPSValue;
  CERT_EXTENSION certExtension;
  CERT_EXTENSIONS certExtensionsArray = { 1, &certExtension };

  // Set the CPS Certificate Policies field - this enables the "Issuer Statement" button on the cert
  certCPSValue.dwValueType = CERT_RDN_IA5_STRING;
  certCPSValue.Value.cbData = sizeof(szCPSName);
  certCPSValue.Value.pbData = (BYTE*)szCPSName;
  if ( (!CryptEncodeObject(X509_ASN_ENCODING, X509_NAME_VALUE, (LPVOID)&certCPSValue, NULL, &dwSize))
    || ((pbCPSNotice = (BYTE*)malloc(dwSize)) == NULL)
    || (!CryptEncodeObject(X509_ASN_ENCODING, X509_NAME_VALUE, (LPVOID)&certCPSValue, pbCPSNotice, &dwSize)) ) {
    printf("could not setup CPS\n");
    goto out;
  }

  certPolicyQualifier.pszPolicyQualifierId = szOID_PKIX_POLICY_QUALIFIER_CPS;
  certPolicyQualifier.Qualifier.cbData = dwSize;
  certPolicyQualifier.Qualifier.pbData = pbCPSNotice;
  if ( (!CryptEncodeObject(X509_ASN_ENCODING, X509_CERT_POLICIES, (LPVOID)&certPolicyInfoArray, NULL, &dwSize))
    || ((pbPolicyInfo = (BYTE*)malloc(dwSize)) == NULL)
    || (!CryptEncodeObject(X509_ASN_ENCODING, X509_CERT_POLICIES, (LPVOID)&certPolicyInfoArray, pbPolicyInfo, &dwSize)) ) {
    printf("could not setup Certificate Policies\n");
    goto out;
  }

  certExtension.pszObjId = szOID_CERT_POLICIES;
  certExtension.fCritical = FALSE;
  certExtension.Value.cbData = dwSize;
  certExtension.Value.pbData = pbPolicyInfo;

  // Call CertCreateSelfSignCertificate() with certExtensionsArray as the last parameter or something...
  (...)

out:
  // Cleanup...
  if (pbCPSNotice != NULL) free(pbCPSNotice);
  if (pbPolicyInfo != NULL) free(pbPolicyInfo);
For a real-life example of the above, as well as the setting of other certificate properties such as the Enhanced Key Usage or an URL in the Subject Alternative Name, you may want to have a look at the LGPL pki.c from libwdi, and our CreateSelfSignedCert() function there.

Oh, and we pretty much rewrote basic LPGL redistributable versions of the MakeCat/Inf2Cat, MakeCert, CertMgr and Signtool WDK utilities, so if you need them, there's here as well. For additional details, look here

No comments:

Post a Comment