/// <summary> /// Create an initial CA Config file /// </summary> /// <param name="config">CA Config object</param> /// <param name="serialNumber">Initial serial number</param> /// <param name="request">Certificate request</param> /// <param name="caKey">CA keyfile</param> /// <returns>CA Config file location</returns> private static string createPendingCAConfig(CAConfig config, BigInteger serialNumber, Pkcs10CertificationRequest request, string caKey) { string version = "3.1"; string caEntry = "rqstPending"; string caValue = Utility.rqst64(request); return(createCaConfFile(config, serialNumber, version, caEntry, caValue, null)); }
/// <summary> /// Create a final CA Config file /// </summary> /// <param name="config">CA Config object</param> /// <param name="serialNumber">Initial serial number</param> /// <param name="cert">CA certificate</param> /// <param name="caKey">CA keyfile</param> /// <returns>CA Config file location</returns> private static string createFinalCAConfig(CAConfig config, BigInteger serialNumber, X509Certificate cert, string caKey) { string version = ""; string caEntry = ""; string caValue = ""; if (config.FIPS140) { version = "3.1"; caEntry = "caCert"; caValue = Utility.cert64(cert); } else { version = "3.0"; caEntry = "caKey"; caValue = caKey; } return(createCaConfFile(config, serialNumber, version, caEntry, caValue, cert)); }
/// <summary> /// Create a new Subordinate CA certificate request using the setup parameters from a CAConfig object /// </summary> /// <remarks>Only System cryptography supported</remarks> /// <param name="Config">CAConfig object</param> /// <returns>PKCS#10 certificate request</returns> public static Pkcs10CertificationRequest CreateSubCA(CAConfig Config) { if (Config.profile != CA_Profile.SubCA) { throw new ArgumentException("Invalid profile specified", Config.profile.ToString()); } if (!Config.FIPS140) { throw new InvalidParameterException("Only FIPS mode supported"); } // Serial number BigInteger serialNumber = new BigInteger(1, BitConverter.GetBytes(DateTime.Now.Ticks)); // Key material CspParameters cspParam = SysKeyManager.Create(Config.pkSize, Config.pkAlgo, Config.name); // PKCS#10 Request Pkcs10CertificationRequestDelaySigned p10 = new Pkcs10CertificationRequestDelaySigned( Config.sigAlgo, Config.DN, SysKeyManager.getPublicKey(cspParam, Config.pkAlgo), null); // Signature byte[] buffer = p10.GetDataToSign(); byte[] signature = SysSigner.Sign(buffer, cspParam, Config.sigAlgo); p10.SignRequest(signature); if (!p10.Verify()) { throw new SignatureException("Cannot validate POP signature"); } // Create the CA Config file createPendingCAConfig(Config, serialNumber, p10, ""); return(p10); }
/// <summary> /// Create a root (self-signed) CA /// </summary> /// <param name="Config">CA Config structure containing the initialisation parameters</param> /// <returns>Full pathname for the configuration file</returns> public static string CreateRootCA(CAConfig Config) { if (Config.profile != CA_Profile.rootCA) { throw new ArgumentException("Invalid profile specified", Config.profile.ToString()); } // Start/end dates DateTime startDate = DateTime.UtcNow; DateTime expiryDate; switch (Config.units) { case "Years": expiryDate = startDate.AddYears(Config.life); break; case "Months": expiryDate = startDate.AddMonths(Config.life); break; case "Days": expiryDate = startDate.AddDays(Config.life); break; default: throw new ArgumentException("Invalid lifetime unit", Config.units); } // Serial number BigInteger serialNumber = new BigInteger(1, BitConverter.GetBytes(DateTime.Now.Ticks)); // Certificate ICertGen certGen; // The OLD method was to use the Config.pkAlgo field to select a hard-coded CSP // The new approach is to have the user select a CSP //OLD method if (Config.FIPS140) { switch (Config.caType) { case CA_Type.sysCA: case CA_Type.dhTA: privateKeyCapi = SysKeyManager.Create(Config.pkSize, Config.pkAlgo, Config.name); publicKey = SysKeyManager.getPublicKey(privateKeyCapi, Config.pkAlgo); if (Config.version == X509ver.V1) { certGen = new SysV1CertGen(); } else { certGen = new SysV3CertGen(); } break; case CA_Type.cngCA: privateKeyCng = CngKeyManager.Create(CngAlgorithm.ECDsaP256, Config.name); publicKey = CngKeyManager.getPublicKey(privateKeyCng); //if (Config.version == X509ver.V1) // certGen = new CngV1CertGen(); //else certGen = new CngV3CertGen(); break; default: throw new InvalidParameterException("CA Type not compatible with Fips140 flag: " + Config.caType.ToString()); } } else { keyPair = BcKeyManager.Create(Config.pkSize, Config.pkAlgo); // Create a system CspParameters entry for use by XmlSigner // Only for RSA and DSA currently until EC XML signing is sorted if (!Config.pkAlgo.Contains("EC")) { privateKeyCapi = SysKeyManager.LoadCsp(keyPair.Private); } else { privateKeyCapi = null; } publicKey = keyPair.Public; if (Config.version == X509ver.V1) { certGen = new BcV1CertGen(); } else { certGen = new BcV3CertGen(); } } //NEW method //if ((Config.FIPS140) && (Config.CSPNum > 0)) // System crypto //{ // cspParam = SysKeyManager.Create(Config.pkSize, Config.CSPName, Config.CSPNum, Config.name); //} // V1 and V3 fields certGen.SetSerialNumber(serialNumber); certGen.SetIssuerDN(Config.DN); certGen.SetNotBefore(startDate); certGen.SetNotAfter(expiryDate); certGen.SetSubjectDN(Config.DN); certGen.SetPublicKey(publicKey); certGen.SetSignatureAlgorithm(Config.sigAlgo); // V3 extensions if (Config.version == X509ver.V3) { ((V3CertGen)certGen).AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(publicKey)); ((V3CertGen)certGen).AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(publicKey)); ((V3CertGen)certGen).AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true)); ((V3CertGen)certGen).AddExtension(X509Extensions.KeyUsage, true, new X509KeyUsage(Config.keyUsage)); } X509Certificate caCert; if (Config.FIPS140) { switch (Config.caType) { case CA_Type.sysCA: case CA_Type.dhTA: caCert = ((IsysCertGen)certGen).Generate(privateKeyCapi); break; case CA_Type.cngCA: caCert = ((IcngCertGen)certGen).Generate(privateKeyCng); break; default: throw new InvalidParameterException("CA Type not compatible with Fips140 flag: " + Config.caType.ToString()); } } else { caCert = ((IbcCertGen)certGen).Generate(keyPair.Private); } caCert.Verify(caCert.GetPublicKey()); string configFile; if (Config.FIPS140) { // Create the CA Config file configFile = createFinalCAConfig(Config, serialNumber, caCert, null); LogEvent.WriteEvent(eventLog, LogEvent.EventType.CreateCA, "Root CA (FIPS) Created: " + configFile); } else { // Store key material in a PKCS#12 file MemoryStream stream = BcKeyManager.SaveP12(keyPair.Private, caCert, Config.password, Config.name); string caKey = Convert.ToBase64String(stream.ToArray()); // Create the CA Config file configFile = createFinalCAConfig(Config, serialNumber, caCert, caKey); LogEvent.WriteEvent(eventLog, LogEvent.EventType.CreateCA, "Root CA (BC) Created: " + configFile); } // Create CA database string dbFile = Database.CreateDB(Config, caCert, privateKeyCapi); // Insert Root CA certificate byte[] dummy = new byte[0]; Database.AddCertificate(caCert, dummy, "rootCA", dbFile, caCert, privateKeyCapi); return(configFile); }
private static string createCaConfFile(CAConfig config, BigInteger serialNumber, string version, string caEntry, string caValue, X509Certificate caCert) { string crlFileLocation = config.location + "\\" + config.name + ".crl"; string dbfile = config.location + "\\CADatabase.xml"; string logFile = config.location + "\\CALog.xml"; string profilesLocation = config.location + "\\Profiles"; // Create CA config file XDocument conf = new XDocument( new XDeclaration("1.0", "utf-8", "yes"), new XComment("CA Configuration"), new XElement("OSCA", new XAttribute("version", version), new XElement("CA", new XElement("name", config.name), new XElement("dn", config.DN), new XElement("type", config.profile.ToString()), // Called 'type' for historical reasons new XElement("caType", config.caType.ToString()), new XElement("created", DateTime.Now.ToUniversalTime()), new XElement("dbFileLocation", dbfile), new XElement("logFileLocation", logFile), new XElement("profilesLocation", profilesLocation), new XElement("publicKeyAlgorithm", config.pkAlgo), new XElement("publicKeySize", config.pkSize), new XElement("signatureAlgorithm", config.sigAlgo), new XElement("fips140", config.FIPS140), new XElement("cryptoServiceProvider", new XAttribute("cspNumber", config.CSPNum), config.CSPName), new XElement("lastSerial", serialNumber), new XElement("crlFileLocation", crlFileLocation), new XElement("lastCRL", 0), new XElement("crlInterval", config.crlInterval), new XElement("policyEnforcement"), new XElement(caEntry, caValue) ) ) ); // Do the policyEnforcement bit XElement pe = new XElement("policyEnforcement"); if (config.rollOver != 0) { pe.Add(new XElement("keyRollOver", config.rollOver.ToString())); } XElement policyEnforcement = conf.Element("OSCA").Element("CA").Element("policyEnforcement"); policyEnforcement.ReplaceWith(pe); // Sign and save the config file // Can't sign for a pending request! (no certificate) string configFile = config.location + "\\CAConfig.xml"; if (caCert != null) { XmlSigning.SignXml(conf, configFile, caCert, privateKeyCapi); // Setup the log file LogFile.createLogFile(logFile, version, caCert, privateKeyCapi); eventLog = new Logger(logFile, caCert, privateKeyCapi); } else { XmlWriter xmlw = XmlWriter.Create(new StreamWriter(configFile)); conf.WriteTo(xmlw); xmlw.Flush(); xmlw.Close(); } return(configFile); }
/// <summary> /// Create a new Subordinate CA using the setup parameters from a CAConfig object /// The Issuing CA must be available to create and sign a certificate /// </summary> /// <param name="Config">CAConfig object</param> /// <param name="IssuingCA">Object reference for issuing CA</param> /// <returns>Full pathname of CA config file</returns> public static string CreateSubCA(CAConfig Config, ICA IssuingCA) { if (Config.profile != CA_Profile.SubCA) { throw new ArgumentException("Invalid profile specified", Config.profile.ToString()); } // Serial number BigInteger serialNumber = new BigInteger(1, BitConverter.GetBytes(DateTime.Now.Ticks)); // Key material Pkcs10CertificationRequest p10; if (Config.FIPS140) { privateKeyCapi = SysKeyManager.Create(Config.pkSize, Config.pkAlgo, Config.name); // PKCS#10 Request p10 = new Pkcs10CertificationRequestDelaySigned( Config.sigAlgo, Config.DN, SysKeyManager.getPublicKey(privateKeyCapi, Config.pkAlgo), null); // Signature byte[] buffer = ((Pkcs10CertificationRequestDelaySigned)p10).GetDataToSign(); byte[] signature = SysSigner.Sign(buffer, privateKeyCapi, Config.sigAlgo); ((Pkcs10CertificationRequestDelaySigned)p10).SignRequest(signature); } else { keyPair = BcKeyManager.Create(Config.pkSize, Config.pkAlgo); // Create a system CspParameters entry for use by XmlSigner privateKeyCapi = SysKeyManager.LoadCsp(keyPair.Private); // PKCS#10 Request p10 = new Pkcs10CertificationRequest( Config.sigAlgo, Config.DN, keyPair.Public, null, keyPair.Private); } // Test the signature if (!p10.Verify()) { throw new SignatureException("Cannot validate POP signature"); } // Request cert from issuing CA X509Certificate cert = IssuingCA.IssueCertificate(p10, new Profile.Profile(Config.profileFile)); string configFile; if (Config.FIPS140) { // Create the CA Config file configFile = createFinalCAConfig(Config, serialNumber, cert, null); LogEvent.WriteEvent(eventLog, LogEvent.EventType.CreateCA, "Subordinate CA (FIPS) Created: " + configFile); } else { // Store key material in a PKCS#12 file MemoryStream stream = BcKeyManager.SaveP12(keyPair.Private, cert, Config.password, Config.name); string caKey = Convert.ToBase64String(stream.ToArray()); // Create the CA Config file configFile = createFinalCAConfig(Config, serialNumber, null, caKey); LogEvent.WriteEvent(eventLog, LogEvent.EventType.CreateCA, "Root CA (BC) Created: " + configFile); } // Create CA database Database.CreateDB(Config, cert, privateKeyCapi); return(configFile); }
/// <summary> /// Create a CA Database file /// </summary> /// <param name="config">CA Config object</param> /// <param name="cert">CA certificate</param> /// <param name="cspParam">CSP with signing key</param> /// <returns>Location of the DB file</returns> internal static string CreateDB(CAConfig config, X509Certificate cert, CspParameters cspParam) { string dbfile = config.location + "\\CADatabase.xml"; return(CreateDB(dbfile, cert, cspParam)); }
/// <summary> /// Derive a DN from a CAConfig object /// </summary> /// <param name="config">CA Config object</param> /// <returns>DN of CA</returns> public static X509Name getDN(CAConfig config) { return(new X509Name("CN=" + config.name)); }