Esempio n. 1
0
        public void AddDomainName(string domainName)
        {
            if (DomainNames == null)
            {
                DomainNames = new List <string>();
            }

            if (!string.IsNullOrWhiteSpace(domainName))
            {
                if (!DomainNames.Exists(d => domainName.Equals(d, System.StringComparison.OrdinalIgnoreCase)))
                {
                    DomainNames.Add(domainName);
                    DomainNames = DomainNames.OrderBy(name => name).ToList();
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Parse certificate for alternate name extension.
        /// </summary>
        private void Parse(byte[] data)
        {
            if (Oid.Value != Oids.SubjectAltName &&
                Oid.Value != Oids.SubjectAltName2)
            {
                throw new FormatException("Extension has unknown oid.");
            }

            Uris.Clear();
            DomainNames.Clear();
            IPAddresses.Clear();

            var altNames        = new DerOctetString(data);
            var altNamesObjects = X509ExtensionUtilities.FromExtensionValue(altNames);
            var generalNames    =
                Org.BouncyCastle.Asn1.X509.GeneralNames.GetInstance(altNamesObjects);

            foreach (var generalName in generalNames.GetNames())
            {
                switch (generalName.TagNo)
                {
                case Org.BouncyCastle.Asn1.X509.GeneralName.UniformResourceIdentifier:
                    Uris.Add(generalName.Name.ToString());
                    break;

                case Org.BouncyCastle.Asn1.X509.GeneralName.DnsName:
                    DomainNames.Add(generalName.Name.ToString());
                    break;

                case Org.BouncyCastle.Asn1.X509.GeneralName.IPAddress:
                    try {
                        var addr = Asn1OctetString
                                   .GetInstance(generalName.Name)
                                   .GetOctets();
                        IPAddresses.Add(new IPAddress(addr).ToString());
                    }
                    catch {
                        throw new FormatException(
                                  "Certificate contains invalid IP address.");
                    }
                    break;

                default:
                    break;
                }
            }
        }
Esempio n. 3
0
        static int Main(string[] args)
        {
            Uri           Directory          = null;
            List <string> ContactURLs        = null;
            List <string> DomainNames        = null;
            DateTime?     NotBefore          = null;
            DateTime?     NotAfter           = null;
            string        HttpRootFolder     = null;
            string        EMail              = null;
            string        Country            = null;
            string        Locality           = null;
            string        StateOrProvince    = null;
            string        Organization       = null;
            string        OrganizationalUnit = null;
            string        FileName           = null;
            string        Password           = string.Empty;
            string        s;
            int?          PollingIngerval = null;
            int?          KeySize         = null;
            int           i       = 0;
            int           c       = args.Length;
            bool          Help    = false;
            bool          Verbose = false;
            bool          TermsOfServiceAgreed = false;
            bool          NewKey = false;

            try
            {
                while (i < c)
                {
                    s = args[i++].ToLower();

                    switch (s)
                    {
                    case "-dir":
                        if (i >= c)
                        {
                            throw new Exception("Missing directory URI.");
                        }

                        if (Directory == null)
                        {
                            Directory = new Uri(args[i++]);
                        }
                        else
                        {
                            throw new Exception("Only one directory URI allowed.");
                        }
                        break;

                    case "-le":
                        if (Directory == null)
                        {
                            Directory = new Uri("https://acme-v02.api.letsencrypt.org/directory");
                        }
                        else
                        {
                            throw new Exception("Only one directory URI allowed.");
                        }
                        break;

                    case "-let":
                        if (Directory == null)
                        {
                            Directory = new Uri("https://acme-staging-v02.api.letsencrypt.org/directory");
                        }
                        else
                        {
                            throw new Exception("Only one directory URI allowed.");
                        }
                        break;

                    case "-ce":
                        if (i >= c)
                        {
                            throw new Exception("Missing contact e-mail.");
                        }

                        if (ContactURLs == null)
                        {
                            ContactURLs = new List <string>();
                        }

                        if (EMail == null)
                        {
                            EMail = args[i];
                        }

                        ContactURLs.Add("mailto:" + args[i++]);
                        break;

                    case "-cu":
                        if (i >= c)
                        {
                            throw new Exception("Missing contact URI.");
                        }

                        if (ContactURLs == null)
                        {
                            ContactURLs = new List <string>();
                        }

                        ContactURLs.Add(args[i++]);
                        break;

                    case "-dns":
                        if (i >= c)
                        {
                            throw new Exception("Missing domain name.");
                        }

                        if (DomainNames == null)
                        {
                            DomainNames = new List <string>();
                        }

                        DomainNames.Add(args[i++]);
                        break;

                    case "-na":
                        if (i >= c)
                        {
                            throw new Exception("Missing timestamp.");
                        }

                        if (DateTime.TryParse(args[i++], out DateTime TP))
                        {
                            NotAfter = TP;
                        }
                        else
                        {
                            throw new Exception("Invalid timestamp: " + args[i - 1]);
                        }
                        break;

                    case "-nb":
                        if (i >= c)
                        {
                            throw new Exception("Missing timestamp.");
                        }

                        if (DateTime.TryParse(args[i++], out TP))
                        {
                            NotBefore = TP;
                        }
                        else
                        {
                            throw new Exception("Invalid timestamp: " + args[i - 1]);
                        }
                        break;

                    case "-http":
                        if (i >= c)
                        {
                            throw new Exception("Missing HTTP root folder.");
                        }

                        if (HttpRootFolder == null)
                        {
                            HttpRootFolder = args[i++];
                        }
                        else
                        {
                            throw new Exception("Only one HTTP Root Folder allowed.");
                        }
                        break;

                    case "-pi":
                        if (i >= c)
                        {
                            throw new Exception("Missing polling interval.");
                        }

                        if (!int.TryParse(args[i++], out int j) || j <= 0)
                        {
                            throw new Exception("Invalid polling interval.");
                        }

                        if (PollingIngerval.HasValue)
                        {
                            throw new Exception("Only one polling interval allowed.");
                        }
                        else
                        {
                            PollingIngerval = j;
                        }
                        break;

                    case "-ks":
                        if (i >= c)
                        {
                            throw new Exception("Missing key size.");
                        }

                        if (!int.TryParse(args[i++], out j) || j <= 0)
                        {
                            throw new Exception("Invalid key size.");
                        }

                        if (KeySize.HasValue)
                        {
                            throw new Exception("Only one key size allowed.");
                        }
                        else
                        {
                            KeySize = j;
                        }
                        break;

                    case "-c":
                        if (i >= c)
                        {
                            throw new Exception("Missing country name.");
                        }

                        if (Country == null)
                        {
                            Country = args[i++];
                        }
                        else
                        {
                            throw new Exception("Only one country name allowed.");
                        }
                        break;

                    case "-l":
                        if (i >= c)
                        {
                            throw new Exception("Missing locality name.");
                        }

                        if (Locality == null)
                        {
                            Locality = args[i++];
                        }
                        else
                        {
                            throw new Exception("Only one locality name allowed.");
                        }
                        break;

                    case "-st":
                        if (i >= c)
                        {
                            throw new Exception("Missing state or province name.");
                        }

                        if (StateOrProvince == null)
                        {
                            StateOrProvince = args[i++];
                        }
                        else
                        {
                            throw new Exception("Only one state or province name allowed.");
                        }
                        break;

                    case "-o":
                        if (i >= c)
                        {
                            throw new Exception("Missing organization name.");
                        }

                        if (Organization == null)
                        {
                            Organization = args[i++];
                        }
                        else
                        {
                            throw new Exception("Only one organization name allowed.");
                        }
                        break;

                    case "-ou":
                        if (i >= c)
                        {
                            throw new Exception("Missing organizational unit name.");
                        }

                        if (OrganizationalUnit == null)
                        {
                            OrganizationalUnit = args[i++];
                        }
                        else
                        {
                            throw new Exception("Only one organizational unit name allowed.");
                        }
                        break;

                    case "-f":
                        if (i >= c)
                        {
                            throw new Exception("Missing file name.");
                        }

                        if (FileName == null)
                        {
                            FileName = args[i++];
                        }
                        else
                        {
                            throw new Exception("Only one file name allowed.");
                        }
                        break;

                    case "-pwd":
                        if (i >= c)
                        {
                            throw new Exception("Missing password.");
                        }

                        if (string.IsNullOrEmpty(Password))
                        {
                            Password = args[i++];
                        }
                        else
                        {
                            throw new Exception("Only one password allowed.");
                        }
                        break;

                    case "-?":
                        Help = true;
                        break;

                    case "-v":
                        Verbose = true;
                        break;

                    case "-a":
                        TermsOfServiceAgreed = true;
                        break;

                    case "-nk":
                        NewKey = true;
                        break;

                    default:
                        throw new Exception("Unrecognized switch: " + s);
                    }
                }

                if (Help || c == 0)
                {
                    Console.Out.WriteLine("Helps you create certificates using the Automatic Certificate");
                    Console.Out.WriteLine("Management Environment (ACME) v2 protocol.");
                    Console.Out.WriteLine();
                    Console.Out.WriteLine("Command line switches:");
                    Console.Out.WriteLine();
                    Console.Out.WriteLine("-dir URI              URI to the ACME directory resource to use.");
                    Console.Out.WriteLine("                      If not provided, the default Let's Encrypt");
                    Console.Out.WriteLine("                      ACME v2 directory will be used:");
                    Console.Out.WriteLine("                      https://acme-v02.api.letsencrypt.org/directory");
                    Console.Out.WriteLine("-le                   Uses the Let's Encrypt ACME v2 directory:");
                    Console.Out.WriteLine("                      https://acme-v02.api.letsencrypt.org/directory");
                    Console.Out.WriteLine("-let                  Uses the Let's Encrypt ACME v2 staging directory:");
                    Console.Out.WriteLine("                      https://acme-staging-v02.api.letsencrypt.org/directory");
                    Console.Out.WriteLine("-ce EMAIL             Adds EMAIL to the list of contact e-mail addresses");
                    Console.Out.WriteLine("                      when creating an account. Can be used multiple");
                    Console.Out.WriteLine("                      times. The first e-mail address will also be");
                    Console.Out.WriteLine("                      encoded into the certificate request.");
                    Console.Out.WriteLine("-cu URI               Adds URI to the list of contact URIs when creating");
                    Console.Out.WriteLine("                      an account. Can be used multiple times.");
                    Console.Out.WriteLine("-a                    You agree to the terms of service agreement. This");
                    Console.Out.WriteLine("                      might be required if you want to be able to create");
                    Console.Out.WriteLine("                      an account.");
                    Console.Out.WriteLine("-nk                   Generates a new account key.");
                    Console.Out.WriteLine("-dns DOMAIN           Adds DOMAIN to the list of domain names when creating");
                    Console.Out.WriteLine("                      an order for a new certificate. Can be used multiple");
                    Console.Out.WriteLine("                      times. The first DOMAIN will be used as the common name");
                    Console.Out.WriteLine("                      for the certificate request. The following domain names");
                    Console.Out.WriteLine("                      will be used as altenative names.");
                    Console.Out.WriteLine("-nb TIMESTAMP         Generated certificate will not be valid before");
                    Console.Out.WriteLine("                      TIMESTAMP.");
                    Console.Out.WriteLine("-na TIMESTAMP         Generated certificate will not be valid after");
                    Console.Out.WriteLine("                      TIMESTAMP.");
                    Console.Out.WriteLine("-http ROOTFOLDER      Allows the application to respond to HTTP challenges");
                    Console.Out.WriteLine("                      by storing temporary files under the corresponding ACME");
                    Console.Out.WriteLine("                      challenge response folder /.well-known/acme-challenge");
                    Console.Out.WriteLine("-pi MS                Polling Interval, in milliseconds. Default value is");
                    Console.Out.WriteLine("                      5000.");
                    Console.Out.WriteLine("-ks BITS              Certificate key size, in bits. Default is 4096.");
                    Console.Out.WriteLine("-c COUNTRY            Country name (C) in the certificate request.");
                    Console.Out.WriteLine("-l LOCALITY           Locality name (L) in the certificate request.");
                    Console.Out.WriteLine("-st STATEORPROVINCE   State or Province name (ST) in the certificate request.");
                    Console.Out.WriteLine("-o ORGANIZATION       Organization name (O) in the certificate request.");
                    Console.Out.WriteLine("-ou ORGUNIT           Organizational unit name (OU) in the certificate request.");
                    Console.Out.WriteLine("-f FILENAME           Output filename of the certificate, without file");
                    Console.Out.WriteLine("                      extension.");
                    Console.Out.WriteLine("-pwd PASSWORD         Password to protect the private key in the generated");
                    Console.Out.WriteLine("                      certificate.");
                    Console.Out.WriteLine("-v                    Verbose mode.");
                    Console.Out.WriteLine("-?                    Help.");
                    return(0);
                }

                if (Verbose)
                {
                    Log.Register(new ConsoleEventSink(false));
                }

                if (Directory == null)
                {
                    Directory = new Uri("https://acme-v02.api.letsencrypt.org/directory");
                }

                if (!PollingIngerval.HasValue)
                {
                    PollingIngerval = 5000;
                }

                if (!KeySize.HasValue)
                {
                    KeySize = 4096;
                }

                if (FileName == null)
                {
                    throw new Exception("File name not provided.");
                }

                if (string.IsNullOrEmpty(Password))
                {
                    Log.Warning("No password provided to protect the private key.");
                }

                if (string.IsNullOrEmpty(HttpRootFolder))
                {
                    Log.Warning("No HTTP root folder provided. Challenge responses must be manually configured.");
                }

                Types.Initialize(
                    typeof(InternetContent).Assembly,
                    typeof(AcmeClient).Assembly);

                Process(Verbose, Directory, ContactURLs?.ToArray(), TermsOfServiceAgreed, NewKey,
                        DomainNames?.ToArray(), NotBefore, NotAfter, HttpRootFolder, PollingIngerval.Value,
                        KeySize.Value, EMail, Country, Locality, StateOrProvince, Organization,
                        OrganizationalUnit, FileName, Password).Wait();

                Console.Out.WriteLine("Press ENTER to continue."); // TODO: Remove
                Console.In.ReadLine();                             // TODO: Remove
                return(0);
            }
            catch (Exception ex)
            {
                ex = Log.UnnestException(ex);

                if (Verbose)
                {
                    Log.Error(ex.Message);
                }
                else
                {
                    Console.Out.WriteLine(ex.Message);
                }

                Console.Out.WriteLine("Press ENTER to continue."); // TODO: Remove
                Console.In.ReadLine();                             // TODO: Remove
                return(-1);
            }
        }