How do I configure a client to sign or encrypt message headers that are generated dynamically at runtime?

The client uses the same ChannelProtectionRequirements mechanism to specify the protection of message headers as the service does. Your intuition may be flipped though as Incoming message parts are always message parts being sent from client to server while Outgoing message parts are always message parts being sent from server to client. Therefore, IncomingSignatureParts are message parts that are signed for transmission from client to server. If this still isn’t clear, try out OutgoingSignatureParts on the client and look at the resulting messages to see if it does what you expect. Then, repeat with IncomingSignatureParts.

A simple behavior that you can use to experiment with is here.

public class SignMessageHeaderBehavior : IContractBehavior
{
    string header;
    string ns;
    
    public SignMessageHeaderBehavior(string header, string ns)
    {
        this.header = header;
        this.ns = ns;
    }
    
    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        ChannelProtectionRequirements requirements = bindingParameters.Find<ChannelProtectionRequirements>();
        XmlQualifiedName qName = new XmlQualifiedName(header, ns);
        requirements.OutgoingSignatureParts.ChannelParts.HeaderTypes.Add(qName);
    }
    
    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }
    
    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
    {
    }
    
    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
    {
    }
}