public KeyInfoX509Data(X509Certificate cert, X509IncludeOption includeOption) { if (cert == null) { throw new ArgumentNullException("cert"); } X509Certificate2 certificate = new X509Certificate2(cert); X509ChainElementCollection elements = null; X509Chain chain = null; switch (includeOption) { case X509IncludeOption.ExcludeRoot: // Build the certificate chain chain = new X509Chain(); chain.Build(certificate); // Can't honor the option if we only have a partial chain. if ((chain.ChainStatus.Length > 0) && ((chain.ChainStatus[0].Status & X509ChainStatusFlags.PartialChain) == X509ChainStatusFlags.PartialChain)) { throw new CryptographicException(CAPI.CERT_E_CHAINING); } elements = (X509ChainElementCollection)chain.ChainElements; for (int index = 0; index < (X509Utils.IsSelfSigned(chain) ? 1 : elements.Count - 1); index++) { AddCertificate(elements[index].Certificate); } break; case X509IncludeOption.EndCertOnly: AddCertificate(certificate); break; case X509IncludeOption.WholeChain: // Build the certificate chain chain = new X509Chain(); chain.Build(certificate); // Can't honor the option if we only have a partial chain. if ((chain.ChainStatus.Length > 0) && ((chain.ChainStatus[0].Status & X509ChainStatusFlags.PartialChain) == X509ChainStatusFlags.PartialChain)) { throw new CryptographicException(CAPI.CERT_E_CHAINING); } elements = (X509ChainElementCollection)chain.ChainElements; foreach (X509ChainElement element in elements) { AddCertificate(element.Certificate); } break; } }
private ServiceResult UpdateCertificate( ISystemContext context, MethodState method, NodeId objectId, NodeId certificateGroupId, NodeId certificateTypeId, byte[] certificate, byte[][] issuerCertificates, string privateKeyFormat, byte[] privateKey, ref bool applyChangesRequired) { HasApplicationSecureAdminAccess(context); object[] inputArguments = new object[] { certificateGroupId, certificateTypeId, certificate, issuerCertificates, privateKeyFormat, privateKey }; X509Certificate2 newCert = null; try { if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } privateKeyFormat = privateKeyFormat?.ToUpper(); if (!(String.IsNullOrEmpty(privateKeyFormat) || privateKeyFormat == "PEM" || privateKeyFormat == "PFX")) { throw new ServiceResultException(StatusCodes.BadNotSupported, "The private key format is not supported."); } ServerCertificateGroup certificateGroup = VerifyGroupAndTypeId(certificateGroupId, certificateTypeId); certificateGroup.UpdateCertificate = null; X509Certificate2Collection newIssuerCollection = new X509Certificate2Collection(); try { // build issuer chain if (issuerCertificates != null) { foreach (byte[] issuerRawCert in issuerCertificates) { var newIssuerCert = new X509Certificate2(issuerRawCert); newIssuerCollection.Add(newIssuerCert); } } newCert = new X509Certificate2(certificate); } catch { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Certificate data is invalid."); } // validate new subject matches the previous subject if (!X509Utils.CompareDistinguishedName(certificateGroup.ApplicationCertificate.Certificate.SubjectName, newCert.SubjectName)) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Subject Name of new certificate doesn't match the application."); } // self signed bool selfSigned = X509Utils.IsSelfSigned(newCert); if (selfSigned && newIssuerCollection.Count != 0) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer list not empty for self signed certificate."); } if (!selfSigned) { try { // verify cert with issuer chain CertificateValidator certValidator = new CertificateValidator(); CertificateTrustList issuerStore = new CertificateTrustList(); CertificateIdentifierCollection issuerCollection = new CertificateIdentifierCollection(); foreach (var issuerCert in newIssuerCollection) { issuerCollection.Add(new CertificateIdentifier(issuerCert)); } issuerStore.TrustedCertificates = issuerCollection; certValidator.Update(issuerStore, issuerStore, null); certValidator.Validate(newCert); } catch (Exception ex) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to verify integrity of the new certificate and the issuer list.", ex); } } var updateCertificate = new UpdateCertificateData(); try { var passwordProvider = m_configuration.SecurityConfiguration.CertificatePasswordProvider; switch (privateKeyFormat) { case null: case "": { X509Certificate2 certWithPrivateKey = certificateGroup.ApplicationCertificate.LoadPrivateKeyEx(passwordProvider).Result; updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPrivateKey(newCert, certWithPrivateKey); break; } case "PFX": { X509Certificate2 certWithPrivateKey = X509Utils.CreateCertificateFromPKCS12(privateKey, passwordProvider?.GetPassword(certificateGroup.ApplicationCertificate)); updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPrivateKey(newCert, certWithPrivateKey); break; } case "PEM": { updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPEMPrivateKey(newCert, privateKey, passwordProvider?.GetPassword(certificateGroup.ApplicationCertificate)); break; } } updateCertificate.IssuerCollection = newIssuerCollection; updateCertificate.SessionId = context.SessionId; } catch { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to verify integrity of the new certificate and the private key."); } certificateGroup.UpdateCertificate = updateCertificate; applyChangesRequired = true; if (updateCertificate != null) { try { using (ICertificateStore appStore = certificateGroup.ApplicationCertificate.OpenStore()) { Utils.LogCertificate(Utils.TraceMasks.Security, "Delete application certificate: ", certificateGroup.ApplicationCertificate.Certificate); appStore.Delete(certificateGroup.ApplicationCertificate.Thumbprint).Wait(); Utils.LogCertificate(Utils.TraceMasks.Security, "Add new application certificate: ", updateCertificate.CertificateWithPrivateKey); var passwordProvider = m_configuration.SecurityConfiguration.CertificatePasswordProvider; appStore.Add(updateCertificate.CertificateWithPrivateKey, passwordProvider?.GetPassword(certificateGroup.ApplicationCertificate)).Wait(); // keep only track of cert without private key var certOnly = new X509Certificate2(updateCertificate.CertificateWithPrivateKey.RawData); updateCertificate.CertificateWithPrivateKey.Dispose(); updateCertificate.CertificateWithPrivateKey = certOnly; } using (ICertificateStore issuerStore = CertificateStoreIdentifier.OpenStore(certificateGroup.IssuerStorePath)) { foreach (var issuer in updateCertificate.IssuerCollection) { try { Utils.LogCertificate(Utils.TraceMasks.Security, "Add new issuer certificate: ", issuer); issuerStore.Add(issuer).Wait(); } catch (ArgumentException) { // ignore error if issuer cert already exists } } } Server.ReportCertificateUpdatedAuditEvent(context, objectId, method, inputArguments, certificateGroupId, certificateTypeId); } catch (Exception ex) { Utils.LogError(Utils.TraceMasks.Security, ServiceResult.BuildExceptionTrace(ex)); throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to update certificate.", ex); } } } catch (Exception e) { // report the failure of UpdateCertificate via an audit event Server.ReportCertificateUpdatedAuditEvent(context, objectId, method, inputArguments, certificateGroupId, certificateTypeId, e); // Raise audit certificate event Server.ReportAuditCertificateEvent(newCert, e); throw; } return(ServiceResult.Good); }
/// <summary> /// Revoke the CA signed certificate. /// The issuer CA public key, the private key and the crl reside in the storepath. /// The CRL number is increased by one and existing CRL for the issuer are deleted from the store. /// </summary> public static async Task <X509CRL> RevokeCertificateAsync( string storePath, X509Certificate2 certificate, string issuerKeyFilePassword = null ) { X509CRL updatedCRL = null; X500DistinguishedName subjectName = certificate.IssuerName; string keyId = null; string serialNumber = null; // caller may want to create empty CRL using the CA cert itself bool isCACert = X509Utils.IsCertificateAuthority(certificate); // find the authority key identifier. X509AuthorityKeyIdentifierExtension authority = X509Extensions.FindExtension <X509AuthorityKeyIdentifierExtension>(certificate); if (authority != null) { keyId = authority.KeyIdentifier; serialNumber = authority.SerialNumber; } else { throw new ArgumentException("Certificate does not contain an Authority Key"); } if (!isCACert) { if (serialNumber == certificate.SerialNumber || X509Utils.IsSelfSigned(certificate)) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Cannot revoke self signed certificates"); } } X509Certificate2 certCA = null; using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(storePath)) { if (store == null) { throw new ArgumentException("Invalid store path/type"); } certCA = await X509Utils.FindIssuerCABySerialNumberAsync(store, certificate.IssuerName, serialNumber).ConfigureAwait(false); if (certCA == null) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Cannot find issuer certificate in store."); } CertificateIdentifier certCAIdentifier = new CertificateIdentifier(certCA) { StorePath = storePath, StoreType = CertificateStoreIdentifier.DetermineStoreType(storePath) }; X509Certificate2 certCAWithPrivateKey = await certCAIdentifier.LoadPrivateKey(issuerKeyFilePassword).ConfigureAwait(false); if (certCAWithPrivateKey == null) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Failed to load issuer private key. Is the password correct?"); } if (!certCAWithPrivateKey.HasPrivateKey) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer certificate has no private key, cannot revoke certificate."); } var certCACrl = await store.EnumerateCRLs(certCA, false).ConfigureAwait(false); var certificateCollection = new X509Certificate2Collection(); if (!isCACert) { certificateCollection.Add(certificate); } updatedCRL = CertificateFactory.RevokeCertificate(certCAWithPrivateKey, certCACrl, certificateCollection); await store.AddCRL(updatedCRL).ConfigureAwait(false); // delete outdated CRLs from store foreach (X509CRL caCrl in certCACrl) { await store.DeleteCRL(caCrl).ConfigureAwait(false); } store.Close(); } return(updatedCRL); }