/// <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); }
/// <summary> /// Issues the certificate. /// </summary> /// <param name="request">The request.</param> /// <param name="profile">The profile</param> /// <param name="notBefore">The not before.</param> /// <param name="notAfter">The not after.</param> /// <returns> /// Certificate /// </returns> /// <exception cref="System.ArgumentException">Invalid signature algorithm in request</exception> /// <exception cref="System.ArgumentOutOfRangeException">Invalid lifetime units in ValidityPeriod</exception> private X509Certificate issueCertificate(Pkcs10CertificationRequest request, Profile.Profile profile, DateTime notBefore, DateTime notAfter) { X509Certificate newCert; string profileName = ""; // Parse the request Pkcs10Parser p10 = new Pkcs10Parser(request); // Check that correct sig algorithm has been used DerObjectIdentifier sigAlgOid = X509Utilities.GetAlgorithmOid(signatureAlgorithm); if (!p10.SignatureAlgorithm.Equals(sigAlgOid)) { logEvent(LogEvent.EventType.Error, "Invalid signature algorithm in request: " + p10.SignatureAlgorithm.ToString()); throw new ArgumentException("Invalid signature algorithm in request", p10.SignatureAlgorithm.ToString()); } // Create a Cert Generator according to the FIPS 140 policy and CA Type ICertGen certGen; if ((fips140) && (type == CA_Type.dhTA.ToString())) { certGen = new SysV1CertGen(); } else if ((fips140) && (type != CA_Type.dhTA.ToString())) { certGen = new SysV3CertGen(policyEnforcement); } else { certGen = new BcV3CertGen(policyEnforcement); } // Setup the certificate certGen.SetSerialNumber(nextCertSerial()); certGen.SetIssuerDN(caCertificate.SubjectDN); certGen.SetSubjectDN(p10.Subject); certGen.SetPublicKey(p10.PublicKey); certGen.SetSignatureAlgorithm(signatureAlgorithm); if (certGen.GetVersion() == X509ver.V3) { ((V3CertGen)certGen).AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCertificate.GetPublicKey())); ((V3CertGen)certGen).AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(p10.PublicKey)); } // Add further extensions either from profile or request attributes // If a profile is specified ignore all attributes apart from SubjAltName if (profile != null) { // Add in SubjAltName if there is one if ((p10.SubjectAltNames != null) && (certGen.GetVersion() == X509ver.V3)) { bool critical = p10.IsCritical(X509Extensions.SubjectAlternativeName); ((V3CertGen)certGen).AddExtension(X509Extensions.SubjectAlternativeName, critical, p10.SubjectAltNames); } // Capture the profile name for database profileName = profile.Name; // cut the cert newCert = generate(certGen, profile, notBefore, notAfter); } else // No profile { // Set the validity period certGen.SetNotBefore(notBefore.ToUniversalTime()); certGen.SetNotAfter(notAfter.ToUniversalTime()); // Do what it says in the request newCert = generate(certGen, p10.Extensions); } // Add certificate to the CA DB Database.AddCertificate(newCert, request.GetDerEncoded(), profileName, dbFileLocation, caCertificate, cspParam); logEvent(LogEvent.EventType.DBAddCert, "DB: Certificate added: " + newCert.SerialNumber.ToString()); return(newCert); }