WCF Client Sign Soap Message with Smart Card - c#

I have forms application with service reference by using CustomBinding for signing soap request (Only need soap body will be signed). If I try to sign request with private key included pfx wcf client succesfully sign Basic256Sha256Rsa15.
Succesfull case below:
private CustomBinding GetCustomHttpBinding()
{
CustomBinding binding = new CustomBinding();
// Open and Close = 20s
binding.OpenTimeout = new TimeSpan(0, 0, 20);
binding.CloseTimeout = new TimeSpan(0, 0, 20);
// Send and Receive = 300s
binding.SendTimeout = new TimeSpan(0, 5, 0);
binding.ReceiveTimeout = new TimeSpan(0, 5, 0);
// ++ Setting security binding ++
var param = new X509SecurityTokenParameters();
param.X509ReferenceStyle = X509KeyIdentifierClauseType.IssuerSerial;
param.ReferenceStyle = SecurityTokenReferenceStyle.Internal;
param.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
param.RequireDerivedKeys = false;
var userNameToken = new UserNameSecurityTokenParameters();
userNameToken.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
var securityElement = new AsymmetricSecurityBindingElement();
securityElement.EnableUnsecuredResponse = true;
securityElement.IncludeTimestamp = true;
securityElement.RecipientTokenParameters = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.IssuerSerial, SecurityTokenInclusionMode.Never);
securityElement.InitiatorTokenParameters = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.IssuerSerial, SecurityTokenInclusionMode.AlwaysToRecipient);
securityElement.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15;
securityElement.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
securityElement.SetKeyDerivation(false);
securityElement.EndpointSupportingTokenParameters.Signed.Add(param);
//securityElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
securityElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
binding.Elements.Add(securityElement);
// ++ Setting message encoding binding ++
var encodingElement = new TextMessageEncodingBindingElement();
encodingElement.MessageVersion = MessageVersion.Soap12;
encodingElement.WriteEncoding = Encoding.UTF8;
//encodingElement.MaxReadPoolSize = 50000000;
//encodingElement.MaxWritePoolSize = 50000000;
encodingElement.ReaderQuotas.MaxArrayLength = 50000000;
encodingElement.ReaderQuotas.MaxStringContentLength = 50000000;
binding.Elements.Add(encodingElement);
// ++ Setting https transport binding ++
var httpsElement = new HttpsTransportBindingElement();
// Messagge buffer size
httpsElement.MaxBufferSize = 50000000;
httpsElement.MaxReceivedMessageSize = 50000000;
httpsElement.MaxBufferPoolSize = 50000000;
httpsElement.RequireClientCertificate = true;
// Others
httpsElement.UseDefaultWebProxy = true;
binding.Elements.Add(httpsElement);
return binding;
}
And Service Sertificate set as
client.ClientCredentials.ClientCertificate.Certificate=cert;// From pfx file
client.ClientCredentials.ServiceCertificate.DefaultCertificate =serverCert;//from server certificate
I try to sign with my company smart card which is ACS38 smart card. If I use DefaultAlgotihmSuite Basic128 or Basic128Rsa15 then smartCard certificate succesfully sign body elements. I change algorihmsuite Basic256Sha256Rsa15 for requirement then I get KeySet does not exist. In this Smart Card have private key but WCF does not reach that private key.
Is there way to sign to Sign Soap Body with Sha256Rsa on SmartCard ?

Related

YouTube API V3: CRUD RTMP

How do you get an RTMP key and associate it with LiveBroadcasts?
I would like to create RTMP keys and associate them with scheduled broadcasts.
When I create a LiveBroadcasts the default RTMP key is associated. I need to manage these keys to be able to program and broadcast several videos simultaneously.
The RTMP key information does not exist in the LiveBroadcast.insert response, but in YouTube Studio the default key is associated with the video schedule.
GoogleCredential cred = await auth.GetCredentialAsync();
var service = new YouTubeService(new BaseClientService.Initializer
{
HttpClientInitializer = cred
});
var liveBroadcast = new LiveBroadcast();
var snippet = new LiveBroadcastSnippet();
snippet.Title = "Video example 1";
snippet.ScheduledStartTime = new DateTime(2021, 7, 15, 9, 0, 0);
snippet.ScheduledEndTime = new DateTime(2021, 7, 15, 10, 30, 0);
liveBroadcast.Snippet = snippet;
var status = new LiveBroadcastStatus();
status.PrivacyStatus = "public";
status.SelfDeclaredMadeForKids = true;
liveBroadcast.Status = status;
var contentDetails = new LiveBroadcastContentDetails();
contentDetails.EnableAutoStart = true;
contentDetails.EnableAutoStop = true;
contentDetails.RecordFromStart = true;
contentDetails.EnableDvr = true;
liveBroadcast.ContentDetails = contentDetails;
var request = service.LiveBroadcasts.Insert(liveBroadcast, "snippet, contentDetails, status");
var response = await request.ExecuteAsync();
The answer is on LiveStreams and LiveBroadcasts: bind.
Once the LiveBroadcasts and LiveStreams have been created, you link them using LiveBroadcasts: bind
var liveStream = new LiveStream();
var snippet = new LiveStreamSnippet();
snippet.Title = "Key A";
liveStream.Snippet = snippet;
var cdn = new CdnSettings();
cdn.Format = "";
cdn.IngestionType = "rtmp";
cdn.FrameRate = "variable";
cdn.Resolution = "variable";
liveStream.Cdn = cdn;
var request = service.LiveStreams.Insert(liveStream, "snippet, cdn");
var response = await aux.ExecuteAsync();
var liveBroadcastsBind = service.LiveBroadcasts.Bind(IdLiveBroadcasts, "id, contentDetails");
liveBroadcastsBind.StreamId = IdLiveStream;
var response = await liveBroadcastsBind.ExecuteAsync();

C# wcf protobuf client

I have a Protobuf WCF Service. Everything works fine when I consume it.
Data is Protobuf and everythings good.
But now I want to use the same class I use with the Protobuf attributes
without Protobuf. How can someone achive that?
I want to consume the service that has Protobuf implemented without protobuf.
And I dont want to change/add another exact class just to have both ways.
EDIT:
var customBinding = new System.ServiceModel.Channels.CustomBinding();
customBinding.Elements.Add(new System.ServiceModel.Channels.TextMessageEncodingBindingElement(System.ServiceModel.Channels.MessageVersion.Soap11, System.Text.Encoding.UTF8));
var httpsBindingElmnt = new System.ServiceModel.Channels.HttpsTransportBindingElement();
httpsBindingElmnt.MaxReceivedMessageSize = 2147483647;
httpsBindingElmnt.UseDefaultWebProxy = true;
//httpsBindingElmnt.ReaderQuotas.MaxStringContentLength = 2147483647;
//httpsBindingElmnt.ReaderQuotas.MaxBytesPerRead = 2147483647;
//httpsBindingElmnt.ReaderQuotas.MaxArrayLength = 2147483647;
//httpsBindingElmnt.ReaderQuotas.MaxDepth = 2147483647;
//httpsBindingElmnt.ReaderQuotas.MaxNameTableCharCount = 2147483647;
//httpsBindingElmnt.ReceiveTimeout = new TimeSpan(0, 30, 0);
//httpsBindingElmnt.Name = "VaultBasicHttpBinding";
httpsBindingElmnt.MaxBufferSize = 2147483647;
httpsBindingElmnt.MaxBufferPoolSize = 2147483647;
//httpsBindingElmnt.ReceiveTimeout = new TimeSpan(0, 30, 0);
customBinding.Elements.Add(httpsBindingElmnt);
//string address = "https://adress/MobileService.svc";
//Uri baseAddress = new Uri(address);
//ServiceHost host = new ServiceHost(MobileService.MobileServiceClient), baseAddress);
//ChannelFactory<MobileService.MobileServiceClient> factory = new ChannelFactory<MobileService.MobileServiceClient>(customBinding, address);
//MobileService.MobileServiceClient client = factory.CreateChannel();
MobileService.MobileServiceClient client = new MobileService.MobileServiceClient(customBinding,
new EndpointAddress("https://adress/MobileService.svc"));
//MobileService.MobileServiceClient client = new MobileService.MobileServiceClient(customBinding,
// new EndpointAddress("http://127.0.0.1:4501/MobileService.svc"));
client.Endpoint.EndpointBehaviors.Add(new ProtoBuf.ServiceModel.ProtoEndpointBehavior());
And after that iam using the client objects functions.

The 'Action', 'http://www.w3.org/2005/08/addressing' required message part was not signed

I am accessing an external java-based web service I have no control over from a WCF client, using dual certificates for encryption and signature as well as custom binding. I am getting a successful response from the server but WCF is throwing a MessageSecurityException : The 'Action', 'http://www.w3.org/2005/08/addressing' required message part was not signed.
My custom binding:
private CustomBinding GetCustomBinding()
{
CustomBinding binding = new CustomBinding();
binding.OpenTimeout = new TimeSpan(0, 0, 20);
binding.CloseTimeout = new TimeSpan(0, 0, 20);
binding.SendTimeout = new TimeSpan(0, 5, 0);
binding.ReceiveTimeout = new TimeSpan(0, 5, 0);
var userNameToken = new UserNameSecurityTokenParameters();
userNameToken.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
var securityElement = new AsymmetricSecurityBindingElement();
securityElement.EnableUnsecuredResponse = true;
securityElement.IncludeTimestamp = true;
securityElement.RecipientTokenParameters = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.IssuerSerial, SecurityTokenInclusionMode.Never);
securityElement.InitiatorTokenParameters = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.IssuerSerial, SecurityTokenInclusionMode.AlwaysToRecipient);
securityElement.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic128Rsa15;
securityElement.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
securityElement.SetKeyDerivation(false);
securityElement.EndpointSupportingTokenParameters.Signed.Add(userNameToken);
securityElement.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
securityElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
binding.Elements.Add(securityElement);
var encodingElement = new TextMessageEncodingBindingElement();
encodingElement.MessageVersion = MessageVersion.Soap11WSAddressing10;
encodingElement.WriteEncoding = Encoding.UTF8;
encodingElement.ReaderQuotas.MaxArrayLength = 50000000;
encodingElement.ReaderQuotas.MaxStringContentLength = 50000000;
binding.Elements.Add(encodingElement);
var httpsElement = new HttpsTransportBindingElement();
httpsElement.MaxBufferSize = 50000000;
httpsElement.MaxReceivedMessageSize = 50000000;
httpsElement.MaxBufferPoolSize = 50000000;
httpsElement.UseDefaultWebProxy = true;
binding.Elements.Add(httpsElement);
return binding;
}
Now I don't care if that Action element is signed or not, or even if it's not there at all, but hacking the response to remove the tag altogether results in a 'No signature message parts were specified for messages with the '' action.' exception.
How can I configure my client to accept the Action and other addressing elements in the response message as they are? Alternatively, what can I change them to so WCF will let them pass?
To override the default checking of the remote Secure Sockets Layer (SSL) certificate used for authentication, specify this on client:
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
To investigate the certificate errors, check the sslPolicyErrors parameter of the RemoteCertificateValidationCallback delegate (Link to MSDN manual page).

How to Authenticate an AXIS camera with ONVIF

I have 3 ONVIF cameras (Bosch, Pansonic and AXIS). I find the cameras using WS-Discovery and can get information from the cameras using GetDeviceInformation. My problem is that the AXIS camera returns (400) Bad Request when I try to get information from it, the two others work like a charm.
I have installed ONVIF Device Manager from SourceForge. If I enter login credientials in the program, I can stream live video from the AXIS camera. If I don't enter any login credientials, I can find the camera, but not stream any video. So based on this I concluded that the camera is correct configured.
I think it has something to do with login credientials on the binding, but can't figure out what is wrong.
My code looks like this
private void CustomBinding2()
{
try
{
const string SERVICE_ADDRESS_DIRECT = "http://192.168.1.72/onvif/device_service"; //400 bad request
const string USERNAME = "cbk";
const string PASSWORD = "12";
HttpTransportBindingElement httpTransportBindingElement = new HttpTransportBindingElement();
httpTransportBindingElement.MaxReceivedMessageSize = Int32.MaxValue;
httpTransportBindingElement.KeepAliveEnabled = false;
httpTransportBindingElement.MaxBufferSize = Int32.MaxValue;
httpTransportBindingElement.ProxyAddress = null;
httpTransportBindingElement.BypassProxyOnLocal = true;
httpTransportBindingElement.UseDefaultWebProxy = false;
httpTransportBindingElement.TransferMode = TransferMode.StreamedResponse;
httpTransportBindingElement.AuthenticationScheme = AuthenticationSchemes.Basic;
TextMessageEncodingBindingElement messegeElement = new TextMessageEncodingBindingElement();
messegeElement.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None);
CustomBinding binding = new CustomBinding(messegeElement, httpTransportBindingElement);
binding.CloseTimeout = TimeSpan.FromSeconds(30.0);
binding.OpenTimeout = TimeSpan.FromSeconds(30.0);
binding.SendTimeout = TimeSpan.FromMinutes(10.0);
binding.ReceiveTimeout = TimeSpan.FromMinutes(3.0);
EndpointAddress serviceAddress = new EndpointAddress(SERVICE_ADDRESS_DIRECT);
ChannelFactory<Device> channelFactory = new ChannelFactory<Device>(binding, serviceAddress);
channelFactory.Credentials.UserName.UserName = USERNAME;
channelFactory.Credentials.UserName.Password = PASSWORD;
Device channel = channelFactory.CreateChannel();
string model, firmwareVersion, serialNumber, hardwareId;
channel.GetDeviceInformation(out model, out firmwareVersion, out serialNumber, out hardwareId);
MessageBox.Show(string.Format("Model: {0}", model));
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
Solved the problem...
One of the things that cheated me the most, was that the AXIS camera and the Client (PC) had to be time synchronous within +-5 sec. If I change the PC time, I just get the 400 bad request back. If the time matches everything works!!!
DateTime UTCTime = DateTime.UtcNow;
tbInfo.AppendText(string.Format("Client Local Time: {0}\n", DateTime.Now.ToString("HH:mm:ss")));
tbInfo.AppendText(string.Format("Client UTC Time: {0}\n", UTCTime.ToString("HH:mm:ss")));
tbInfo.AppendText("\n\n");
HttpTransportBindingElement httpTransport = new HttpTransportBindingElement();
TransportSecurityBindingElement transportSecurity = new TransportSecurityBindingElement();
transportSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(new UsernameTokenParameters());
transportSecurity.AllowInsecureTransport = true;
transportSecurity.IncludeTimestamp = false;
TextMessageEncodingBindingElement textMessageEncoding = new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8);
CustomBinding binding = new CustomBinding(transportSecurity, textMessageEncoding, httpTransport);
EndpointAddress serviceAddress = new EndpointAddress(addressDirect);
ChannelFactory<Device> channelFactory = new ChannelFactory<Device>(binding, serviceAddress);
UsernameClientCredentials credentials = new UsernameClientCredentials(new UsernameInfo(username, password));
channelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
channelFactory.Endpoint.Behaviors.Add(credentials);
Device channel = channelFactory.CreateChannel();
var unitTime = channel.GetSystemDateAndTime(new GetSystemDateAndTimeRequest());
tbInfo.AppendText(string.Format("Camera Local Time: {0}:{1}:{2}\n", unitTime.SystemDateAndTime.LocalDateTime.Time.Hour, unitTime.SystemDateAndTime.LocalDateTime.Time.Minute, unitTime.SystemDateAndTime.LocalDateTime.Time.Second));
tbInfo.AppendText(string.Format("Camera UTC Time: {0}:{1}:{2}\n", unitTime.SystemDateAndTime.UTCDateTime.Time.Hour, unitTime.SystemDateAndTime.UTCDateTime.Time.Minute, unitTime.SystemDateAndTime.UTCDateTime.Time.Second));
var info = channel.GetDeviceInformation(new GetDeviceInformationRequest());
MessageBox.Show(string.Format("Model: {0}", info.Model));

WCF SSL certificate using an enterprise CA

For an application, I need to have a SSL certificate for a WCF service,
So we installed it. If I go with an internet browser with a web browser trough https, I've got no problem, no warning, nothing, so I suppose that this certificate is considered as valid for windows.
The problem is that when I'm trying to connect to my WCF server, I got this error:
The X.509 certificate CN=myHostName, OU=tom, O=myDomainName,
L=MyLocation, S=SO, C=CH chain building failed. The certificate that
was used has a trust chain that cannot be verified. Replace the
certificate or change the certificateValidationMode. The revocation
function was unable to check revocation because the revocation server
was offline.
What can be wrong? How can I know which part of the chain is unvalid? Is there any way to know what is the missing part?
Here is my code
The server:
ServiceHost myHost = new ServiceHost(typeof(MyService));
WSHttpBinding binding = new WSHttpBinding
{
ReaderQuotas = { MaxStringContentLength = int.MaxValue, MaxArrayLength = int.MaxValue, MaxDepth = int.MaxValue, MaxBytesPerRead = int.MaxValue, MaxNameTableCharCount = int.MaxValue },
MaxReceivedMessageSize = int.MaxValue
};
TimeSpan timeoutSpan = TimeSpan.FromMilliseconds(timeout);
binding.CloseTimeout = timeoutSpan;
binding.OpenTimeout = timeoutSpan;
binding.ReceiveTimeout = timeoutSpan;
binding.SendTimeout = timeoutSpan;
binding.ReliableSession.InactivityTimeout = timeoutSpan;
binding.MaxBufferPoolSize = int.MaxValue;
//we set the security type
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
//we set the server's certificate
myHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, ConfigurationManager.AppSettings["Hostname"]);
myHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
//we add the endPoint(and we indicate which methods are exposed through the interface
myHost.AddServiceEndpoint(services[port], binding, String.Format("http://localhost:{0}", port));
//Some services doesn't need an authentication
if (!servicesWithoutAuth.Contains(services[port]))
{
//We set the authentifier:
myHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
myHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();
myHost.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
//we set the AuthorizationPolicy
List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy> { new CustomAuthorizationPolicy() };
myHost.Authorization.ExternalAuthorizationPolicies = policies.AsReadOnly();
}
else
{
//We set the authentifier:
myHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
myHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new NoUserNamePasswordValidator();
}
//We bypass the certificate verification(our certificate is only self signed)
//HACK Only to desactivate the SSL check:
ServicePointManager.ServerCertificateValidationCallback += ValidateCertificate;
//HACK: Remove when debug finished
private static bool ValidateCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
{
return true;
}
My client side:
// the remote adress is of the form "net.tcp://localhost:8000"
string remoteAddress = String.Format("{0}://{1}:{2}", Tools.GetDescription(accessInfo.ServiceHost.Protocol), accessInfo.ServiceHost.HostName, accessInfo.PortNumber);
// HACK: binding depends on protocol -> switch over accessInfo.ServiceHost.Protocol
// avoid seralization/deserialization problems with large XML's
WSHttpBinding binding = new WSHttpBinding();
binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
binding.MaxReceivedMessageSize = int.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
binding.ReaderQuotas.MaxDepth = int.MaxValue;
binding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
binding.ReaderQuotas.MaxNameTableCharCount = int.MaxValue;
TimeSpan timeoutSpan = DateTime.Now.AddMinutes(30) - DateTime.Now;
binding.CloseTimeout = timeoutSpan;
binding.OpenTimeout = timeoutSpan;
binding.ReceiveTimeout = timeoutSpan;
binding.SendTimeout = timeoutSpan;
binding.ReliableSession.InactivityTimeout = timeoutSpan;
//++
binding.MaxBufferPoolSize = int.MaxValue;
//we set the security type
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
ChannelFactory<TService> channelFactory = new ChannelFactory<TService>(binding, remoteAddress);
channelFactory.Credentials.UserName.UserName = ((UsernamePasswordAuthentication)authInfos).Username;
channelFactory.Credentials.UserName.Password = ((UsernamePasswordAuthentication)authInfos).Password;
//We set the maxItemsInObjectGraph
foreach (OperationDescription op in channelFactory.Endpoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dataContractBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dataContractBehavior != null)
{
dataContractBehavior.MaxItemsInObjectGraph = int.MaxValue;
}
}
SamlSecurityTokenAuthenticator authenticator = new SamlSecurityTokenAuthenticator(new List<SecurityTokenAuthenticator>(new SecurityTokenAuthenticator[] { new RsaSecurityTokenAuthenticator(), new X509SecurityTokenAuthenticator(X509CertificateValidator.None) }), TimeSpan.FromDays(5));
_service = channelFactory.CreateChannel();
How can I know which part of the chain is unvalid? Is there any way to
know what is the missing part?
Well, from my experience, if you open your keystore and view it, you should see that your certificate clearly forms a chain. I don't know what tool you use to view your keystore (or if your using the windows keystore), but when you view your key, you should see a chain of some kind. If a chain is formed correctly, it will appear correctly, and doesn't have any missing parts.
My guess is that when you imported your certificate reply, it didn't form the chain for some reason. In other words, your certificate is in your keystore as a "unchained" public key.

Categories