diff --git a/ACMESharp/ACMESharp.Providers.DuckDNS/ACMESharp.Providers.DuckDNS.csproj b/ACMESharp/ACMESharp.Providers.DuckDNS/ACMESharp.Providers.DuckDNS.csproj
new file mode 100644
index 00000000..aee14375
--- /dev/null
+++ b/ACMESharp/ACMESharp.Providers.DuckDNS/ACMESharp.Providers.DuckDNS.csproj
@@ -0,0 +1,67 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {9B6C05E7-A570-406D-8FFD-BF8AE5337AA1}
+ Library
+ Properties
+ ACMESharp.Providers.DuckDNS
+ ACMESharp.Providers.DuckDNS
+ v4.6.1
+ 512
+
+
+ true
+ full
+ false
+ bin\$(Configuration)\ACMESharp.Providers.DuckDNS\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\$(Configuration)\ACMESharp.Providers.DuckDNS\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties\SharedAssemblyVersionInfo.cs
+
+
+ Properties\SharedGlobalSuppressions.cs
+
+
+
+
+
+
+
+ {d551234b-0a8d-4dee-8178-a81998df0edb}
+ ACMESharp
+
+
+
+
+ PreserveNewest
+
+
+
+
+
\ No newline at end of file
diff --git a/ACMESharp/ACMESharp.Providers.DuckDNS/ACMESharp.Providers.DuckDNS.nuspec b/ACMESharp/ACMESharp.Providers.DuckDNS/ACMESharp.Providers.DuckDNS.nuspec
new file mode 100644
index 00000000..53c4cb47
--- /dev/null
+++ b/ACMESharp/ACMESharp.Providers.DuckDNS/ACMESharp.Providers.DuckDNS.nuspec
@@ -0,0 +1,23 @@
+
+
+
+
+ $id$
+ $version$.$buildNum$$versionLabel$
+ $title$
+ https://github.com/ebekker
+ https://github.com/ebekker
+ https://raw.githubusercontent.com/ebekker/ACMESharp/master/LICENSE
+ https://github.com/ebekker/ACMESharp
+ https://cdn.rawgit.com/ebekker/ACMESharp/49bf6524da8239ecf258ab3857dfbbf40366ecfd/artwork/ACMESharp-logo-square64.png
+ false
+ $description$
+ Early-access release of ACMESharp Provider Lib for Duck DNS.
+ Copyright © 2019 Philipp Nanz
+ pki ssl tls security certificates letsencrypt acme acmesharp duckdns
+
+
+
+
+
+
diff --git a/ACMESharp/ACMESharp.Providers.DuckDNS/ACMESharp.Providers.DuckDNS.psd1 b/ACMESharp/ACMESharp.Providers.DuckDNS/ACMESharp.Providers.DuckDNS.psd1
new file mode 100644
index 00000000..d2d34e23
--- /dev/null
+++ b/ACMESharp/ACMESharp.Providers.DuckDNS/ACMESharp.Providers.DuckDNS.psd1
@@ -0,0 +1,112 @@
+
+## For a reference of this file's elements, see:
+## https://technet.microsoft.com/library/hh849709.aspx
+## https://technet.microsoft.com/en-us/library/dd878297(v=vs.85).aspx
+
+## 64-bit:
+## %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
+## 32-bit:
+## %SystemRoot%\syswow64\WindowsPowerShell\v1.0\powershell.exe
+
+@{
+ ## This is a manifest-only module so we don't define any root
+ #RootModule = ''
+
+ ModuleVersion = '0.9.2'
+ GUID = '9ea5edb1-319e-4f9d-a538-aec3567a410d'
+
+ Author = 'https://github.com/ebekker'
+
+ CompanyName = 'https://github.com/ebekker/ACMESharp'
+
+ Copyright = '(c) 2019 Philipp Nanz. All rights reserved.'
+
+ Description = "Duck DNS Provider extension library for ACMESharp Client."
+
+ # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
+ DefaultCommandPrefix = 'ACME'
+
+ ## Minimum version of the Windows PowerShell engine required by this module
+ ## This does not appear to be enforce for versions > 2.0 as per
+ ## https://technet.microsoft.com/en-us/library/dd878297(v=vs.85).aspx
+ PowerShellVersion = '3.0'
+
+ DotNetFrameworkVersion = '4.5'
+
+ # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
+ PrivateData = @{
+
+ PSData = @{
+
+ # Tags applied to this module. These help with module discovery in online galleries.
+ Tags = @('pki','ssl','tls','security','certificates','letsencrypt','acme','powershell','acmesharp','duckdns','acmesharp_ext')
+
+ # A URL to the license for this module.
+ LicenseUri = 'https://raw.githubusercontent.com/ebekker/ACMESharp/master/LICENSE'
+
+ # A URL to the main website for this project.
+ ProjectUri = 'https://github.com/ebekker/ACMESharp'
+
+ # A URL to an icon representing this module.
+ IconUri = 'https://cdn.rawgit.com/ebekker/ACMESharp/master/artwork/ACMESharp-logo-square64.png'
+
+ # ReleaseNotes of this module
+ ReleaseNotes = 'Please see the release notes from the release distribution page: https://github.com/ebekker/ACMESharp/releases'
+
+ } # End of PSData hashtable
+
+ } # End of PrivateData hashtable
+
+ # Modules that must be imported into the global environment prior to importing this module
+ RequiredModules = @( ## FYI -- If one module uses the Hashtable spec, they all have to
+
+ ## The minimum version of ACMESharp that supports our form of a Provider
+ ## extension as a dynamically installed and *enabled* POSH Extension Module
+ , @{ModuleName="ACMESharp";ModuleVersion="0.9.0"}
+ )
+
+
+ ############################################################
+ ## Unused manifest elements reserved for possible future use
+ ############################################################
+
+ # HelpInfo URI of this module for updateable help
+ # HelpInfoURI = ''
+
+ # Assemblies that must be loaded prior to importing this module
+ # RequiredAssemblies = @()
+
+ # Script files (.ps1) that are run in the caller's environment prior to importing this module.
+ # ScriptsToProcess = @()
+
+ # Type files (.ps1xml) to be loaded when importing this module
+ # TypesToProcess = @()
+
+ # Format files (.ps1xml) to be loaded when importing this module
+ # FormatsToProcess = @()
+
+ # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
+ # NestedModules = @()
+
+ # Functions to export from this module
+ # FunctionsToExport = '*'
+
+ # Cmdlets to export from this module
+ # CmdletsToExport = '*'
+
+ # Variables to export from this module
+ # VariablesToExport = '*'
+
+ # Aliases to export from this module
+ # AliasesToExport = '*'
+
+ # DSC resources to export from this module
+ # DscResourcesToExport = @()
+
+ # List of all modules packaged with this module
+ # ModuleList = @()
+
+ # List of all files packaged with this module
+ # FileList = @()
+
+}
diff --git a/ACMESharp/ACMESharp.Providers.DuckDNS/DuckDnsChallengeHandler.cs b/ACMESharp/ACMESharp.Providers.DuckDNS/DuckDnsChallengeHandler.cs
new file mode 100644
index 00000000..2d1de935
--- /dev/null
+++ b/ACMESharp/ACMESharp.Providers.DuckDNS/DuckDnsChallengeHandler.cs
@@ -0,0 +1,65 @@
+using ACMESharp.ACME;
+using System;
+using System.Net;
+
+namespace ACMESharp.Providers.DuckDNS
+{
+ public class DuckDnsChallengeHandler : IChallengeHandler
+ {
+ public string Token { get; set; }
+
+ public bool IsDisposed
+ {
+ get; private set;
+ }
+
+ public void CleanUp(ChallengeHandlingContext ctx)
+ {
+ var dnsChallenge = (DnsChallenge)ctx.Challenge;
+ var domain = GetDomainId(dnsChallenge);
+
+ var wr = CreateRequest(Token, domain, "");
+ using (var response = wr.GetResponse())
+ { }
+ }
+
+ private void AssertNotDisposed()
+ {
+ if (IsDisposed)
+ throw new InvalidOperationException("handler is disposed");
+ }
+
+ public void Dispose()
+ {
+ IsDisposed = true;
+ }
+
+ public void Handle(ChallengeHandlingContext ctx)
+ {
+ AssertNotDisposed();
+ var dnsChallenge = (DnsChallenge)ctx.Challenge;
+ var domain = GetDomainId(dnsChallenge);
+
+ var wr = CreateRequest(Token, domain, dnsChallenge.RecordValue);
+ using (var response = wr.GetResponse())
+ { }
+ }
+
+ string GetDomainId(DnsChallenge dnsChallenge)
+ {
+ var segments = dnsChallenge.RecordName.Split('.');
+ return segments[1];
+ }
+
+ WebRequest CreateRequest(string token, string domain, string text)
+ {
+ var url = "https://www.duckdns.org/update?token=" + token + "&domains=" + domain + "&txt=" + text;
+ if (String.IsNullOrEmpty(text))
+ {
+ url += "&clear=true";
+ }
+ Console.WriteLine("Executing web request: " + url);
+ return WebRequest.Create(url);
+ }
+ }
+}
diff --git a/ACMESharp/ACMESharp.Providers.DuckDNS/DuckDnsChallengeHandlerProvider.cs b/ACMESharp/ACMESharp.Providers.DuckDNS/DuckDnsChallengeHandlerProvider.cs
new file mode 100644
index 00000000..8330faeb
--- /dev/null
+++ b/ACMESharp/ACMESharp.Providers.DuckDNS/DuckDnsChallengeHandlerProvider.cs
@@ -0,0 +1,55 @@
+using ACMESharp.ACME;
+using ACMESharp.Ext;
+using System.Collections.Generic;
+
+namespace ACMESharp.Providers.DuckDNS
+{
+ ///
+ /// Provider for a Challenge Handler that updates the TXT records on a
+ /// Duck DNS account.
+ ///
+ [ChallengeHandlerProvider("duckdns",
+ ChallengeTypeKind.DNS,
+ Label = "Duck DNS Provider",
+ Description = "A Duck DNS provider for handling Challenges." +
+ " This provider supports the DNS" +
+ " Challenge type and computes all the necessary" +
+ " response values.")]
+ public class DuckDnsChallengeHandlerProvider : IChallengeHandlerProvider
+ {
+ public static readonly ParameterDetail TOKEN = new ParameterDetail(
+ nameof(DuckDnsChallengeHandler.Token),
+ ParameterType.TEXT, isRequired: true, label: "Token",
+ desc: "The Token for your Duck DNS account");
+
+ private static readonly ParameterDetail[] PARAMS =
+ {
+ TOKEN
+ };
+
+ public IEnumerable DescribeParameters()
+ {
+ return PARAMS;
+ }
+
+ public bool IsSupported(Challenge c)
+ {
+ return c is DnsChallenge;
+ }
+
+ public IChallengeHandler GetHandler(Challenge c, IReadOnlyDictionary initParams)
+ {
+ if (initParams == null)
+ initParams = new Dictionary();
+
+ if (!initParams.ContainsKey(TOKEN.Name))
+ throw new KeyNotFoundException($"missing required parameter [{TOKEN.Name}]");
+
+ var h = new DuckDnsChallengeHandler();
+
+ h.Token = (string)initParams[TOKEN.Name];
+
+ return h;
+ }
+ }
+}
diff --git a/ACMESharp/ACMESharp.Providers.DuckDNS/Properties/AssemblyInfo.cs b/ACMESharp/ACMESharp.Providers.DuckDNS/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..51dd355e
--- /dev/null
+++ b/ACMESharp/ACMESharp.Providers.DuckDNS/Properties/AssemblyInfo.cs
@@ -0,0 +1,22 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ACMESharp Duck DNS Provider")]
+[assembly: AssemblyDescription("Duck DNS Provider extension for ACMESharp")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("github.com/ebekker/ACMESharp")]
+[assembly: AssemblyProduct("ACMESharp.Providers.DuckDNS")]
+[assembly: AssemblyCopyright("Copyright © 2019 Philipp Nanz. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("bc6d303a-71fb-4cc7-8d30-3c3b09f9c92a")]
diff --git a/ACMESharp/ACMESharp.Providers.DuckDNS/packages.config b/ACMESharp/ACMESharp.Providers.DuckDNS/packages.config
new file mode 100644
index 00000000..6b8deb9c
--- /dev/null
+++ b/ACMESharp/ACMESharp.Providers.DuckDNS/packages.config
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ACMESharp/ACMESharp.sln b/ACMESharp/ACMESharp.sln
index 1e6c551d..d6251cb4 100644
--- a/ACMESharp/ACMESharp.sln
+++ b/ACMESharp/ACMESharp.sln
@@ -78,6 +78,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACMESharp.PKI.Providers.Ope
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACMESharp.Providers.DNSMadeEasy", "ACMESharp.Providers.DNSMadeEasy\ACMESharp.Providers.DNSMadeEasy.csproj", "{BC6D303A-71FB-4CC7-8D30-3C3B09F9C92A}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACMESharp.Providers.DuckDNS", "ACMESharp.Providers.DuckDNS\ACMESharp.Providers.DuckDNS.csproj", "{9B6C05E7-A570-406D-8FFD-BF8AE5337AA1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -156,6 +158,10 @@ Global
{BC6D303A-71FB-4CC7-8D30-3C3B09F9C92A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC6D303A-71FB-4CC7-8D30-3C3B09F9C92A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC6D303A-71FB-4CC7-8D30-3C3B09F9C92A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9B6C05E7-A570-406D-8FFD-BF8AE5337AA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9B6C05E7-A570-406D-8FFD-BF8AE5337AA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9B6C05E7-A570-406D-8FFD-BF8AE5337AA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9B6C05E7-A570-406D-8FFD-BF8AE5337AA1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE