Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does embedio lib support https? #72

Closed
videoguy opened this issue Apr 7, 2017 · 20 comments
Closed

Does embedio lib support https? #72

videoguy opened this issue Apr 7, 2017 · 20 comments

Comments

@videoguy
Copy link

videoguy commented Apr 7, 2017

We have been using this lib as a test web server before we push content to Akamai. It has been serving us well. It is simple to use and rock solid.

We have clients that need to access content over https. Does this lib support creating a https server with a self signed cert?
If not, do you have any pointers to get there?

Thanks

@geoperez
Copy link
Member

geoperez commented Apr 7, 2017

Hi, we have a closed issue related #26

Right now, we don't have plans to support HTTPS.

@videoguy
Copy link
Author

videoguy commented Apr 7, 2017

That link seem to be about wss which probably based on https. My request is for https only. Looking at all the links referenced in the other issue, https support seem to be built in HttpListener of .Net assuming user configured things right using netsh.

Am I on the right path if I were to do the same?

@geoperez
Copy link
Member

geoperez commented Apr 7, 2017

Yes, if you are using the .NET HttpListener you can use HTTPS with a manual binding. But you can't run EmbedIO with Net Standard or Mono. The HttpListener implementation that we maintain doesn't support HTTPS.

@videoguy
Copy link
Author

videoguy commented Apr 8, 2017

I am using older version of your lib. I believe I used version that was latest around an year back. I am using it from a .Net 4.5 winforms application.
Did this version has same limitation as above?

@geoperez
Copy link
Member

geoperez commented Apr 8, 2017 via email

@videoguy
Copy link
Author

videoguy commented Apr 11, 2017

I am confused. From what I understand, embedio implementation of web server doesn't use .Net builtin HttpListener (and http.sys). Instead it implements web server on top of tcp sockets. And it doesn't support https.

What I am confused about is how embedio will help even if I move to .Net 4.6. You are not using the builtin HttpListener. Does it matter what .Net framework I use?

Thanks

@geoperez
Copy link
Member

Yes, only target NET46 is using the builtin HttpListener.

@videoguy
Copy link
Author

If I understand this correctly, all I have to do is change my winforms project settings to use .Net 4.6 and rebuild the app. Then embedio uses builtin httplistener for all the http traffic.

@geoperez
Copy link
Member

geoperez commented Apr 11, 2017 via email

@videoguy
Copy link
Author

Thats great! In this case, can my app listen and accept https connections and serve static files?
I am assuming yes as the https is builtin the kernel driver (http.sys).
I understand I have to go do all the netsh configuration stuff to get it working.

@geoperez
Copy link
Member

You are right. You application can use the builtin httplistener and you need to setup the netsh to handle SSL.

@videoguy
Copy link
Author

It worked. I am able to use embedio with .Net 4.6.1 serve https content on localhost.

I looked at other options for https. I always come back to embedio as it has been serving us well and is a rock solid web server for our use case.

Thanks a lot for your help!

@geoperez
Copy link
Member

Cool. Closing ticket.

@buvar
Copy link

buvar commented Apr 19, 2017

@geoperez please did you do any investigation of other solutions like websocket-sharp for that? SSL for both HTTP and WebSocket is critical for our new project (will be .NETStandard based, .NET 4.6 is not enough for us). I don't know if there are any issuses with classes like SslStream or X509Certificate with .NETStandard? If you don't know about any and the decision not to support SSL is only about the time/timeplan, I could invest some time to implement it...

@geoperez
Copy link
Member

Hi @buvar, the reason we are not supporting SSL is because time, but if you provide a solution it's welcome

@henon
Copy link

henon commented Sep 14, 2018

@videoguy can you post a code snippet how you used EmbedIO with SSL?

@OneB1t
Copy link

OneB1t commented Feb 24, 2020

   private static WebServer CreateWebServer(string url,int port)
        {
            // Ssl Support :
            var ca1 = new X509Certificate2Builder { SubjectName = "CN=SomeCA" }.Build();
            var cert1 = new X509Certificate2Builder { SubjectName = "CN=SelfSignedCert", Issuer = ca1, Intermediate = false }.Build();
            var server = new WebServer(o => o
                    .WithMode(HttpListenerMode.EmbedIO)
                    .WithCertificate(cert1)
                    .WithUrlPrefix("https://*:" + port))
                
                // First, we will configure our web server by adding Modules.
                .WithStaticFolder("/", SimpleLogManager.CurrentDirectory, true,m =>
                {
                    m.WithDirectoryLister(DirectoryLister.Html).WithoutDefaultDocument().WithContentCaching(false);
                })
                .WithModule(new ActionModule("/", HttpVerbs.Any, ctx => ctx.SendDataAsync(new { Message = "Error" }))); ;

            return server;
        }

@neilsilver
Copy link

@OneB1t I know this is an old closed thread but .... Is the X509CertificateBuilder class in your example from the Mono.Security Library ?

@OneB1t
Copy link

OneB1t commented Oct 8, 2021

Sorry this is probably not relevant anymore but i used this:
https://stackoverflow.com/questions/22230745/generate-a-self-signed-certificate-on-the-fly

and as my project switched to .NET 5.0 there was modification required in order to make it compatible so now im using this
`
namespace SimpleUpdater
{
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.X509.Extension;
using System;
using System.Numerics;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

public class X509Certificate2Builder
{
    public string SubjectName { get; set; }

    public DateTime? NotBefore { get; set; }

    public DateTime? NotAfter { get; set; }

    public bool Intermediate { get; set; } = true;

    public X509Certificate2 Issuer { get; set; }
    public string IssuerName { get; set; }
    public AsymmetricAlgorithm IssuerPrivateKey { get; set; }
    private const int KEY_STRENGTH = 2048;


    public X509Certificate2Builder()
    {
    }

    public X509Certificate2 Build()
    {
        // Generating Random Numbers
        var randomGenerator = new CryptoApiRandomGenerator();
        var random = new SecureRandom(randomGenerator);

        // The Certificate Generator
        var certificateGenerator = new X509V3CertificateGenerator();

        // Serial Number
        var serialNumber = BigIntegers.CreateRandomInRange(Org.BouncyCastle.Math.BigInteger.One, Org.BouncyCastle.Math.BigInteger.ValueOf(long.MaxValue), random);
        certificateGenerator.SetSerialNumber(serialNumber);

        // Issuer and Subject Name
        certificateGenerator.SetIssuerDN(new X509Name(IssuerName ?? SubjectName));
        certificateGenerator.SetSubjectDN(new X509Name(SubjectName));

        // Authority Key Identifier
        if (Issuer != null)
        {
            var authorityKeyIdentifier = new AuthorityKeyIdentifierStructure(
                DotNetUtilities.FromX509Certificate(Issuer));
            certificateGenerator.AddExtension(
                X509Extensions.AuthorityKeyIdentifier.Id, false, authorityKeyIdentifier);
        }

        // Basic Constraints - certificate is allowed to be used as intermediate.
        certificateGenerator.AddExtension(
            X509Extensions.BasicConstraints.Id, true, new BasicConstraints(Intermediate));

        // Valid For
        certificateGenerator.SetNotBefore(NotBefore ?? DateTime.UtcNow.Date);
        certificateGenerator.SetNotAfter(NotAfter ?? DateTime.UtcNow.Date.AddYears(2));

        // Subject Public Key
        var keyGenerationParameters = new KeyGenerationParameters(random, KEY_STRENGTH);
        var keyPairGenerator = new RsaKeyPairGenerator();
        keyPairGenerator.Init(keyGenerationParameters);

        var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
        var issuerKeyPair = IssuerPrivateKey == null
            ? subjectKeyPair
            : DotNetUtilities.GetKeyPair(IssuerPrivateKey);

        certificateGenerator.SetPublicKey(subjectKeyPair.Public);

        // selfsign certificate
        ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", issuerKeyPair.Private, random);

        var certificate = certificateGenerator.Generate(signatureFactory);

        // Merge into X509Certificate2
        X509Certificate2 cert = new X509Certificate2(certificate.GetEncoded());
        X509Certificate2 certWithPrivateKey = cert.CopyWithPrivateKey(ConvertToRsaPrivateKey(subjectKeyPair));
        return certWithPrivateKey;
    }

    private static RSA ConvertToRsaPrivateKey(AsymmetricCipherKeyPair keyPair)
    {
        var keyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
        Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(keyInfo.ParsePrivateKey().GetDerEncoded());
        if (seq.Count != 9)
        {
            const string Message = "malformed sequence in RSA private key";
            throw new PemException(Message);
        }

        var rsa = RsaPrivateKeyStructure.GetInstance(seq);
        var rsaparams = new RsaPrivateCrtKeyParameters(
            rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1,
            rsa.Exponent2, rsa.Coefficient);

        return DotNetUtilities.ToRSA(rsaparams);
    }
}

}
`

@pracplayopen
Copy link

for getting this to run on non-windows platforms, per this bouncycastle issue, replace the last line of ConvertToRsaPrivateKey method:

        //return DotNetUtilities.ToRSA(rsaparams); // this uses something called CspParameters which is only available on windows platforms
        return RSA.Create(DotNetUtilities.ToRSAParameters(rsaparams)); // workaround, per: https://github.com/novotnyllc/bc-csharp/issues/6#issuecomment-590298804

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants