private ServerCertificateGroup VerifyGroupAndTypeId( NodeId certificateGroupId, NodeId certificateTypeId ) { // verify typeid must be set if (NodeId.IsNull(certificateTypeId)) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "Certificate type not specified."); } // verify requested certificate group if (NodeId.IsNull(certificateGroupId)) { certificateGroupId = ObjectIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup; } ServerCertificateGroup certificateGroup = m_certificateGroups.FirstOrDefault(group => Utils.IsEqual(group.NodeId, certificateGroupId)); if (certificateGroup == null) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "Certificate group invalid."); } // verify certificate type bool foundCertType = certificateGroup.CertificateTypes.Any(t => Utils.IsEqual(t, certificateTypeId)); if (!foundCertType) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "Certificate type not valid for certificate group."); } return(certificateGroup); }
private ServiceResult CreateSigningRequest( ISystemContext context, MethodState method, NodeId objectId, NodeId certificateGroupId, NodeId certificateTypeId, string subjectName, bool regeneratePrivateKey, byte[] nonce, ref byte[] certificateRequest) { HasApplicationSecureAdminAccess(context); ServerCertificateGroup certificateGroup = VerifyGroupAndTypeId(certificateGroupId, certificateTypeId); if (!String.IsNullOrEmpty(subjectName)) { throw new ArgumentNullException(nameof(subjectName)); } // TODO: implement regeneratePrivateKey // TODO: use nonce for generating the private key var passwordProvider = m_configuration.SecurityConfiguration.CertificatePasswordProvider; X509Certificate2 certWithPrivateKey = certificateGroup.ApplicationCertificate.LoadPrivateKeyEx(passwordProvider).Result; Utils.LogCertificate(Utils.TraceMasks.Security, "Create signing request: ", certWithPrivateKey); certificateRequest = CertificateFactory.CreateSigningRequest(certWithPrivateKey, X509Utils.GetDomainsFromCertficate(certWithPrivateKey)); return(ServiceResult.Good); }
private ServiceResult CreateSigningRequest( ISystemContext context, MethodState method, NodeId objectId, NodeId certificateGroupId, NodeId certificateTypeId, string subjectName, bool regeneratePrivateKey, byte[] nonce, ref byte[] certificateRequest) { HasApplicationSecureAdminAccess(context); ServerCertificateGroup certificateGroup = VerifyGroupAndTypeId(certificateGroupId, certificateTypeId); if (!String.IsNullOrEmpty(subjectName)) { throw new ArgumentException(nameof(subjectName)); } // TODO: implement regeneratePrivateKey // TODO: use nonce for generating the private key string password = String.Empty; X509Certificate2 certWithPrivateKey = certificateGroup.ApplicationCertificate.LoadPrivateKey(password).Result; certificateRequest = CertificateFactory.CreateSigningRequest(certWithPrivateKey, Utils.GetDomainsFromCertficate(certWithPrivateKey)); return(ServiceResult.Good); }
/// <summary> /// Initializes the configuration and diagnostics manager. /// </summary> public ConfigurationNodeManager( IServerInternal server, ApplicationConfiguration configuration ) : base(server, configuration) { m_rejectedStorePath = configuration.SecurityConfiguration.RejectedCertificateStore.StorePath; m_certificateGroups = new List <ServerCertificateGroup>(); m_configuration = configuration; // TODO: configure cert groups in configuration ServerCertificateGroup defaultApplicationGroup = new ServerCertificateGroup { BrowseName = Opc.Ua.BrowseNames.DefaultApplicationGroup, CertificateTypes = new NodeId[] { ObjectTypeIds.RsaSha256ApplicationCertificateType }, ApplicationCertificate = configuration.SecurityConfiguration.ApplicationCertificate, IssuerStorePath = configuration.SecurityConfiguration.TrustedIssuerCertificates.StorePath, TrustedStorePath = configuration.SecurityConfiguration.TrustedPeerCertificates.StorePath }; m_certificateGroups.Add(defaultApplicationGroup); }
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); 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(); X509Certificate2 newCert; 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.SubjectName, newCert.SubjectName.Name)) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Subject Name of new certificate doesn't match the application."); } // self signed bool selfSigned = X509Utils.CompareDistinguishedName(newCert.Subject, newCert.Issuer); 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 { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to verify integrity of the new certificate and the issuer list."); } } 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 } } } } catch (Exception ex) { Utils.LogError(Utils.TraceMasks.Security, ServiceResult.BuildExceptionTrace(ex)); throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to update certificate.", ex); } } return(ServiceResult.Good); }
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); 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(); X509Certificate2 newCert; 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."); } // load existing application cert and private key if (!Utils.CompareDistinguishedName(certificateGroup.ApplicationCertificate.SubjectName, newCert.SubjectName.Name)) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Subject Name of new certificate doesn't match the application."); } // self signed bool selfSigned = Utils.CompareDistinguishedName(newCert.Subject, newCert.Issuer); 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 { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to verify integrity of the new certificate and the issuer list."); } } var updateCertificate = new UpdateCertificateData(); try { string password = String.Empty; switch (privateKeyFormat) { case null: case "": { X509Certificate2 certWithPrivateKey = certificateGroup.ApplicationCertificate.LoadPrivateKey(password).Result; updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPrivateKey(newCert, certWithPrivateKey); break; } case "PFX": { X509Certificate2 certWithPrivateKey = CertificateFactory.CreateCertificateFromPKCS12(privateKey, password); updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPrivateKey(newCert, certWithPrivateKey); break; } case "PEM": { updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPEMPrivateKey(newCert, privateKey, password); 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; return(ServiceResult.Good); }