public string EncodeCrlNumberExtensionData(string[] crlNumber)
        {
            //var urisStr = D.CrlLocations;
            var uris   = crlNumber.Select(u => Encoding.UTF8.GetBytes(u));
            var zero   = new byte[] { 48 };  //"0", delimiter ?
            var nbsp   = new byte[] { 160 }; //" ", separator ?
            var dagger = new byte[] { 134 }; //"dagger", separator ?

            var zeroSize   = zero.Length + 1;
            var nbspSize   = nbsp.Length + 1;
            var daggerSize = dagger.Length + 1;

            var col = new List <byte>();

            col.AddRange(zero); //delimiter
            int totalBytes = uris.Sum(u => u.Length);

            totalBytes += (zeroSize + (nbspSize * 2) + daggerSize) * uris.Count();
            col.Add((byte)totalBytes); //size of everything it contains

            foreach (var uri in uris)
            {
                var uriSize = uri.Length;
                col.AddRange(zero);                                          //delimiter
                col.Add((byte)(nbspSize + nbspSize + uriSize + daggerSize)); //size of everything it contains
                col.AddRange(nbsp);
                col.Add((byte)(nbspSize + uriSize + daggerSize));            //size of everything it contains
                col.AddRange(nbsp);
                col.Add((byte)(uriSize + daggerSize));                       //size of everything it contains
                col.AddRange(dagger);                                        //separator ?
                col.Add((byte)uriSize);
                col.AddRange(uri);
            }
            var bytes  = col.ToArray();
            var base64 = Convert.ToBase64String(bytes);

            var oidCDP = new CERTENROLLLib.CObjectId();

            //oidCDP.InitializeFromName(CERTENROLLLib.CERTENROLL_OBJECTID.XCN_OID_CRL_DIST_POINTS);
            oidCDP.InitializeFromName(CERTENROLLLib.CERTENROLL_OBJECTID.XCN_OID_CRL_NUMBER);
            // There is no specific class to CDPs, so we use the CX509Extension
            var crlList = new CERTENROLLLib.CX509Extension();

            crlList.Initialize(oidCDP, CERTENROLLLib.EncodingType.XCN_CRYPT_STRING_BASE64, base64);
            //certRequest.X509Extensions.Add(crlList);

            return(crlList.RawData[CERTENROLLLib.EncodingType.XCN_CRYPT_STRING_BASE64]);
        }
        // From:
        //    http://blogs.interfacett.com/selecting-a-cryptographic-key-provider-in-windows-server-2012-ad-cs
        //    https://msdn.microsoft.com/en-us/library/windows/desktop/aa386983(v=vs.85).aspx
        //
        // Microsoft Base Smart Card Crypto Provider
        // Microsoft Enhanced Cryptographic Provider v1.0
        // ECDA_P256#Microsoft Smart Card Key Storage Provider
        // ECDA_P521#Microsoft Smart Card Key Storage Provider
        // RSA#Microsoft Software Key Storage Provider
        // Microsoft Base Cryptographic Provider v1.0
        // ECDA_P256#Microsoft Software Key Storage Provider
        // ECDA_P521#Microsoft Software Key Storage Provider
        // Microsoft Strong Cryptographic Provider
        // ECDA_P384#Microsoft Software Key Storage Provider
        // Microsoft Base DSS Cryptographic Provider
        // RSA#Microsoft Smart Card Key Storage Provider
        // DSA#Microsoft Software Key Storage Provider
        // ECDA_P384#Microsoft Smart Card Key Storage Provider


        public override PrivateKey GeneratePrivateKey(PrivateKeyParams pkp)
        {
            var rsaPkp = pkp as RsaPrivateKeyParams;
            var ecPkp  = pkp as EcPrivateKeyParams;

            var algId = new CERTENROLLLib.CObjectId();

            if (rsaPkp != null)
            {
                var oid = new System.Security.Cryptography.Oid("RSA");
                algId.InitializeFromValue(oid.Value);
            }
            else if (ecPkp != null)
            {
                throw new NotImplementedException("EC keys not implemented YET!");
            }
            else
            {
                throw new NotSupportedException("unsupported private key parameters type");
            }


            var cePk = new CERTENROLLLib.CX509PrivateKey();

            // MS_DEF_PROV
            //cePk.ProviderName = "Microsoft Base Cryptographic Provider";
            cePk.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";

            //cePk.ProviderType = CERTENROLLLib.X509ProviderType.XCN_PROV_RSA_FULL;
            cePk.Algorithm = algId;
            cePk.KeySpec   = CERTENROLLLib.X509KeySpec.XCN_AT_KEYEXCHANGE;
            cePk.Length    = rsaPkp.NumBits;

            // Don't store in the machine's local cert store and allow exporting of private key
            cePk.MachineContext = false;
            cePk.ExportPolicy   = CERTENROLLLib.X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG;
            cePk.Create();

            var pk = new CeRsaPrivateKey(rsaPkp.NumBits, null, null)
            {
                Exported = cePk.Export(BCRYPT_PRIVATE_KEY_BLOB),
            };

            return(pk);
        }
        public override Csr GenerateCsr(CsrParams csrParams, PrivateKey pk, Crt.MessageDigest md)
        {
            var rsaPk = pk as CeRsaPrivateKey;

            if (rsaPk != null)
            {
                var cePk = new CERTENROLLLib.CX509PrivateKey();

                // MS_DEF_PROV
                //cePk.ProviderName = "Microsoft Base Cryptographic Provider";
                cePk.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";

                // Don't store in the machine's local cert store and allow exporting of private key
                cePk.MachineContext = false;
                cePk.ExportPolicy   = CERTENROLLLib.X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG;

                cePk.Import(BCRYPT_PRIVATE_KEY_BLOB, rsaPk.Exported);

                var ceReq = new CERTENROLLLib.CX509CertificateRequestCertificate();
                ceReq.InitializeFromPrivateKey(
                    CERTENROLLLib.X509CertificateEnrollmentContext.ContextUser,
                    cePk, "");

                // CN=Test Cert, OU=Sandbox
                var subjParts = new[]
                {
                    new { name = "C", value = csrParams?.Details?.Country },
                    new { name = "ST", value = csrParams?.Details?.StateOrProvince },
                    new { name = "L", value = csrParams?.Details?.Locality },
                    new { name = "O", value = csrParams?.Details?.Organization },
                    new { name = "OU", value = csrParams?.Details?.OrganizationUnit },
                    new { name = "CN", value = csrParams?.Details?.CommonName },
                    new { name = "E", value = csrParams?.Details?.Email },
                };

                // Escape any non-standard character
                var re   = new Regex("[^A-Za-z0-9\\._-]");
                var subj = "";
                foreach (var sp in subjParts)
                {
                    if (!string.IsNullOrEmpty(sp.value))
                    {
                        var spVal = re.Replace(sp.value, "\\$0");
                        subj += $",{sp.name}={spVal}";
                    }
                }
                if (string.IsNullOrEmpty(subj))
                {
                    throw new InvalidOperationException("invalid CSR details");
                }
                subj = subj.Substring(1); // Skip over the first comma

                // http://msdn.microsoft.com/en-us/library/aa377051(VS.85).aspx
                var subjDN = new CERTENROLLLib.CX500DistinguishedName();
                subjDN.Encode(subj);
                ceReq.Subject = subjDN;

                if (csrParams.NotBefore != null)
                {
                    ceReq.NotBefore = csrParams.NotBefore.Value;
                }
                if (csrParams.NotAfter != null)
                {
                    ceReq.NotAfter = csrParams.NotAfter.Value;
                }

                var mdVal = Enum.GetName(typeof(Crt.MessageDigest), md);
                var mdOid = new System.Security.Cryptography.Oid(mdVal);
                var mdAlg = new CERTENROLLLib.CObjectId();
                mdAlg.InitializeFromValue(mdOid.Value);
                ceReq.SignatureInformation.HashAlgorithm = mdAlg;
                ceReq.Encode();

                var csr = new Csr(ceReq.RawData);
                return(csr);
            }
            else
            {
                throw new NotSupportedException("unsuppored private key type");
            }
        }