My websocket server is not starting. I cannot connect. But if I run program with admin rights It's working.
X509Certificate2 certificate = new X509Certificate2(Resource.UZCRYPTO);
using (X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadWrite);
if (!store.Certificates.Contains(certificate))
store.Add(certificate);
}
X509Certificate2 cert = new X509Certificate2(Resource._127_0_0_1, "1", X509KeyStorageFlags.MachineKeySet);
//WebCoket set
WebSocketServer wssv = new WebSocketServer(IPAddress.Parse("127.0.0.1"), 4141, true);
wssv.SslConfiguration.ServerCertificate = new X509Certificate2(cert);
wssv.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12;
wssv.AddWebSocketService<WebSocketEcho>("/");
wssv.KeepClean = false;
wssv.Start();
Related
I'm trying to create TLS 1.2-encrypted broker and clients with MQTTnet (let's say on port 2000). Below is my attempt:
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Server;
using System.Security.Authentication;
MqttFactory factory = new MqttFactory();
MqttServerOptionsBuilder serverOptions = new MqttServerOptionsBuilder()
.WithEncryptedEndpoint()
.WithEncryptedEndpointPort(2000)
.WithEncryptionSslProtocol(SslProtocols.Tls12)
.WithoutDefaultEndpoint();
MqttServer mqttServer = factory.CreateMqttServer(serverOptions.Build());
mqttServer.StartAsync();
MqttClientOptionsBuilder clientOptions = new MqttClientOptionsBuilder()
.WithClientId("myClient")
.WithTcpServer("localhost", 2000)
.WithTls(new MqttClientOptionsBuilderTlsParameters()
{
UseTls = true,
SslProtocol = SslProtocols.Tls12,
CertificateValidationHandler = x => { return true; }
});
MQTTnet.Client.MqttClient mqttClient = factory.CreateMqttClient() as MQTTnet.Client.MqttClient;
while (!mqttClient.IsConnected)
{
mqttClient.ConnectAsync(clientOptions.Build()).GetAwaiter();
Thread.Sleep(1000);
}
Console.WriteLine("Connected");
Console.ReadLine();
The client I created doesn't connect to the broker. I believe the problem comes from the server side (if not both), as nothing is connected on port 2000 when I check with netstat.
What did I miss?
Here's the code that works for me. Basically after awaiting the server and adding a X509 certificate the server now allows clients with the same certificate to connect.
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Server;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
X509Store store = new X509Store(StoreLocation.CurrentUser);
X509Certificate2 certificate;
try
{
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = store.Certificates;
X509Certificate2Collection currentCerts = certCollection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
certificate = currentCerts[0];
}
finally
{
store.Close();
}
MqttFactory factory = new MqttFactory();
MqttServerOptionsBuilder serverOptions = new MqttServerOptionsBuilder()
.WithEncryptedEndpoint()
.WithEncryptedEndpointPort(2000)
.WithEncryptionCertificate(certificate)
.WithRemoteCertificateValidationCallback( (obj, cert, chain, ssl) => { return true; } )
.WithEncryptionSslProtocol(SslProtocols.Tls12)
.WithoutDefaultEndpoint();
MqttServer mqttServer = factory.CreateMqttServer(serverOptions.Build());
await mqttServer.StartAsync();
MqttClientOptionsBuilder clientOptions = new MqttClientOptionsBuilder()
.WithClientId("myClient")
.WithTcpServer("localhost", 2000)
.WithTls(new MqttClientOptionsBuilderTlsParameters()
{
UseTls = true,
SslProtocol = SslProtocols.Tls12,
CertificateValidationHandler = x => { return true; }
});
MQTTnet.Client.MqttClient mqttClient = factory.CreateMqttClient() as MQTTnet.Client.MqttClient;
while (!mqttClient.IsConnected)
{
mqttClient.ConnectAsync(clientOptions.Build()).GetAwaiter();
Thread.Sleep(1000);
}
Console.WriteLine("Connected");
Console.ReadLine();
hi I want to Create X509Certificate To Use in SslStream.AuthenticateAsServer() on windows 10 loopbak.
I try to Create Certificate with OpenSsl and Makecert Script but certificates not work.
please help me.
my Code :
X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
RawStringData = RawStringData.Replace("CONNECT ", "GET https://");
RawStringData = RawStringData.Replace(":443", "/");
RawStringData = RawStringData.Replace("Proxy-Connection", "Connection");
RawByteArrayData = Encoding.ASCII.GetBytes(RawStringData);
Port = 443;
ServerSocket.Connect(HostEntry.AddressList[0], Port);
HttpsStream = new SslStream(new NetworkStream(ServerSocket));
HttpsStream.AuthenticateAsClient(Host);
HttpsStream.Write(RawByteArrayData);
int Count = HttpsStream.Read(NewData, 0, NewData.Length);
string pfxpath = #"D:\test.pfx";
X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxpath));
byte[] pfxData = File.ReadAllBytes(pfxpath);
cert = new X509Certificate2(pfxData,"", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
X509Certificate x509 = store.Certificates.Find(X509FindType.FindByIssuerName, "localhost", false)[0];
ssl = new SslStream(new NetworkStream(A) , false , Verification , null );
ssl.AuthenticateAsServer(cert , false, System.Security.Authentication.SslProtocols.Tls, true);
ssl.Write(NewData);
Currently creating Certificate Authorities and Issued Certificates. The Generation of the request, enrollment and validation are all functional, but when I checked my certificate store, I realized, it was placing them in my personal certificate directory. For memory, security and legal reasons, I can't have that.
The certificates are stored in a secure remote database. The certificates may be randomly accessed or generated on a random machine from a collection. If they generate certificates, it will store them on whichever machine created the certificate. Is there a way to generate a certificate enrollment (CX509Enrollment) without any trace of the certificate being left on the machine afterwards?
The portion that controls enrollment is relatively small and straight forward. It can only be ran as an administrator. I assume that's because it's adding certificates to the store.
I'm currently running a separate project file to attempt to debug this issue.
Both my certificates are constructed and kept in memory.
static void Main(string[] args)
{
X509Certificate2 rootCert = CreateSelfSignedCertificate("testRoot");
X509Certificate2 signedChild = CreateSignedCertificate("testyMcTesterson", rootCert);
X509Chain chain = new X509Chain();
chain.ChainPolicy = new X509ChainPolicy()
{
RevocationMode = X509RevocationMode.NoCheck,
VerificationFlags = X509VerificationFlags.AllFlags,
UrlRetrievalTimeout = new TimeSpan(0, 1, 0)
};
chain.ChainPolicy.ExtraStore.Add(rootCert);
bool isValid = chain.Build(signedChild); //Is True :D
}
The certificates end up in my personal certificate store
My enrollment occurs in this method. It takes a fully contructed and encoded certificate request.
public static CX509Enrollment EnrollCertificateRequest(CX509CertificateRequestCertificate certRequest)
{
var enroll = new CX509Enrollment();
enroll.InitializeFromRequest(certRequest);
string csr = enroll.CreateRequest();
enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate,
csr, EncodingType.XCN_CRYPT_STRING_BASE64, "");
return enroll;
}
EDIT
I'm currently limited to .NET 4.5.x.
Another problem I'm running into, is that trying to sign a certificate with a root will throw a CRYPT_E_NOT_FOUND exception.
There's probably not a way to do it with CX509Enroll. But you can possibly accomplish your goals with .NET Framework 4.7.2 and the CertificateRequest class.
using (RSA rsa = RSA.Create(2048))
{
CertificateRequest request = new CertificateRequest(
"CN=Your Name Here",
rsa,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder();
builder.AddDnsName("your.name.here");
builder.AddDnsName("your.other.name.here");
request.CertificateExtensions.Add(builder.Build());
// Any other extensions you're supposed to request, like not being a CA.
request.CertificateExtensions.Add(
new X509BasicConstraintsExtension(false, false, 0, false));
// TLS Server?
request.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.1")
},
false));
byte[] derEncodedRequest = request.CreateSigningRequest();
X509Certificate2 responseWithPrivateKey;
using (X509Certificate2 response = SendRequestToServerAndGetResponse(derEncodedRequest))
{
responseWithPrivateKey = response.CopyWithPrivateKey(rsa);
}
// Use it, save it to a PFX, whatever.
// At this point, nothing has touched the hard drive.
}
I figured it out without using enrollment and sticking to .NET 4.5.x.
I first create a RSACrytpoServiceProvider using CspParameters.
I then construct a private and public key from the RSACryptoServiceProvider. I create a certificate request and initiate from the private key. The certificate request is encoded and converted to raw data, then to bytes. The bytes are then used to create an X509Certificate2.
public static X509Certificate2 GenerateCertificate(string subjectName)
{
var dn = new CX500DistinguishedName();
dn.Encode("CN=" + subjectName, X500NameFlags.XCN_CERT_NAME_STR_COMMA_FLAG);
//Create crytpo provider to generate an assymetric key
int KeyType = (int)X509ProviderType.XCN_PROV_RSA_SCHANNEL;
CspParameters cspParams = new CspParameters(KeyType);
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.KeyContainerName = Guid.NewGuid().ToString();
var rsa = new RSACryptoServiceProvider(2048, cspParams);
var CryptoProvider = rsa.CspKeyContainerInfo.ProviderName;
var keyContainerName = rsa.CspKeyContainerInfo.KeyContainerName;
CX509PrivateKey privateKey = new CX509PrivateKey();
privateKey.MachineContext = true;
privateKey.ProviderName = CryptoProvider;
privateKey.ContainerName = keyContainerName;
privateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES;
privateKey.Open();
keyContainerName = privateKey.ContainerName;
CX509PublicKey publicKey = privateKey.ExportPublicKey();
var oid = new CObjectId();
oid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // SSL server
var oidlist = new CObjectIds();
oidlist.Add(oid);
var eku = new CX509ExtensionEnhancedKeyUsage();
eku.InitializeEncode(oidlist);
var hashobj = new CObjectId();
hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID,
ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
AlgorithmFlags.AlgorithmFlagsNone, "SHA256");
CX509CertificateRequestCertificate certRequest = new CX509CertificateRequestCertificate();
certRequest.InitializeFromPrivateKey(
X509CertificateEnrollmentContext.ContextMachine,
privateKey,
"");
certRequest.Subject = dn;
certRequest.NotBefore = DateTime.Now;
certRequest.NotAfter = DateTime.Now.AddYears(1);
certRequest.HashAlgorithm = hashobj;
certRequest.X509Extensions.Add((CX509Extension)eku);
certRequest.Encode();
return new X509Certificate2(
Convert.FromBase64String(certRequest.RawData), "",
X509KeyStorageFlags.Exportable)
{
PrivateKey = rsa,
FriendlyName = subjectName
};
}
To issue a cert. The same process is followed a CSignerCertificate is initiated and attached. But before that happens, I save the root certificate to the My, Local Machine Certificate Store. I then create a signed certificate using the root that was just added to the store. I then remove the certificate from the store.
Signing a Certificate Request
var dnSigner = new CX500DistinguishedName();
dnSigner.Encode("CN=" + signer.FriendlyName, X500NameFlags.XCN_CERT_NAME_STR_COMMA_FLAG);
string base64Root = Convert.ToBase64String(signer.RawData);
CSignerCertificate certSigner = new CSignerCertificate();
bool useMachineStore = ((ICspAsymmetricAlgorithm)signer.PrivateKey).CspKeyContainerInfo.MachineKeyStore;
certSigner.Initialize(useMachineStore, X509PrivateKeyVerify.VerifyNone, EncodingType.XCN_CRYPT_STRING_BASE64, base64Root);
certRequest.SignerCertificate = certSigner;
certRequest.Issuer = dnSigner;
static void Main(string[] args)
{
X509Certificate2 rootCert = GenerateCertificate("TEST_ROOT");
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(rootCert);
X509Certificate2 signedChild = GenerateUserCertificate("Testy McTesterson", rootCert);
store.Remove(rootCert);
store.Close();
}
A few important things to note:
This will only work with certain key usage and key spec flags
An X509Chain will still build and validate but it will recognize that the root is untrusted (Easy to bypass).
I wrote this code and it's working perfect when we have running app on this same PC where we plug smartcards.
But how I need to do to make this code running when my app is run on terminal and user has smartcards connect to his own PC.
On terminal session I allow to use smartcard for terminal.
User can see this cert but when this cert was chosen then I get error about no private key..
How to use smartcard on a remote PC ?
private X509Certificate2 LetUserChooseCertificate()
{
X509Certificate2 cert = null;
try
{
// Open the store of personal certificates.
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);//StoreName.My StoreLocation.CurrentUser
//X509Store store = new X509Store("addressbook", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection, "Signing", "Choose cert", X509SelectionFlag.SingleSelection);
if (scollection != null && scollection.Count == 1)
{
cert = scollection[0];
if (cert.HasPrivateKey == false)
{
//MessageBox.Show("This certificate does not have a private key associated with it");
//cert = null;
}
}
store.Close();
}
catch (Exception)
{
//MessageBox.Show("Unable to get the private key");
//cert = null;
}
return cert;
}
This is a followup to C# Generate a non self signed client CX509Certificate Request without a CA using the certenroll.dll
I am trying to create a client cert signed by my self signed CA, as in the above question. I can create the desired certs without issue using makecert.exe (they show as trusted). I attempting to do the same in C#. The certs are created and placed in the machine's My store. The self signed CA is also installed in the machine's Trusted store. When I open them, they say:
Windows does not have enough information to verify this certificate.
Help?
Code:
// create DN
var dn = new CX500DistinguishedName();
dn.Encode("CN=Demo Cert", X500NameFlags.XCN_CERT_NAME_STR_NONE);
// create prvate key
var pk = new CX509PrivateKey();
pk.MachineContext = true;
pk.Length = 1024;
pk.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE;
pk.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG;
pk.Create();
// use SHA512
var hash = new CObjectId();
hash.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "SHA512");
// EKU
var oid = new CObjectId();
oid.InitializeFromValue("1.3.6.1.5.5.7.3.2");
var oidlist = new CObjectIds();
oidlist.Add(oid);
var eku = new CX509ExtensionEnhancedKeyUsage();
eku.InitializeEncode(oidlist);
// Initialize the signer
var TheCA = GimmeTheCA(); // method returns my self signed CA as X509Certificate2
ISignerCertificate signer = new CSignerCertificate();
signer.Initialize(true, X509PrivateKeyVerify.VerifyNone, EncodingType.XCN_CRYPT_STRING_HEX, TheCA.GetRawCertDataString());
// Root Dn
var Rootdn = new CX500DistinguishedName();
Rootdn.Encode(TheCA.Subject, X500NameFlags.XCN_CERT_NAME_STR_NONE);
// Cert Request
var cert = new CX509CertificateRequestCertificate();
cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, pk, "");
cert.Subject = dn;
cert.Issuer = Rootdn;
cert.SignerCertificate = (CSignerCertificate)signer;
cert.NotBefore = DateTime.Now;
cert.NotAfter = new DateTime(2020, 1, 1);
cert.X509Extensions.Add((CX509Extension)eku);
cert.HashAlgorithm = hash;
cert.Encode();
// Enrollment
var enroll = new CX509Enrollment();
enroll.InitializeFromRequest(cert);
enroll.CertificateFriendlyName = "Intel IPT";
string csr = enroll.CreateRequest();
// Install
enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedRoot, csr, EncodingType.XCN_CRYPT_STRING_BASE64, "");
You may try :
pk.KeySpec = X509KeySpec.XCN_AT_SIGNATURE;
pk.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES;
Run the application with Elevated Privileges (run it as an Administrator).
Put a Copy of the CA certificate int the "Computer\Personal" ("MY") Store (but keep the original certificate in the "Computer\Trusted Root Cert. Auth." ("Root") Store)