pkisharp / acme-ps Goto Github PK
View Code? Open in Web Editor NEWPowerShell module supporting ACME v2 certificate management
License: MIT License
PowerShell module supporting ACME v2 certificate management
License: MIT License
ACMEs RFC (https://tools.ietf.org/html/rfc8555#section-6.3 and following) defines some of the requests to be POST-as-GET.
We do not adhere to that everywhere and have to adjust to be compliant.
The CmdLets will be examined and corrected where neccessary.
How using ACME-PS renew certificate after 90days?
I serialized the ServiceDirectory manually now, but I don't know, if that's good to Keep here.
I'm considering pulling Newtonsofts.JSON for Deserializing the JSON directly into the types.
Essentially the conversion should work oobe, but it didn't in practice...
When trying to use the acme-ps module in another script to automate renewals it seems to randomly fail for me when Invoke-SignedWebRequest is called. Simply retrying the command tends to get past the error, however on line 1183 the throw can end the script due to the default erroractionpreferece. Simply adding $errroractionpreference = "continue" to acme-ps.psm1 seems to resolve this ending my script (for whatever reason if I add this to the script calling acme-ps it does not work).
Edit: changing the throw to a write-error would probably be better, Q1 answered: yes I am
To get proper feedback from LE (eg. "rate limit reached"), I needed to do this:
from:
throw [AcmeException]::new($respone.ErrorMessage, $response)
to:
throw [AcmeHttpException]::new($response.ErrorMessage, $response)
and
from ("$this.Message" is read-only):
class AcmeHttpException : System.Exception {
AcmeHttpException([string]$_message, [AcmeHttpResponse]$_response) {
$this.Message = $_message;
$this.Response = $_response;
}
[AcmeHttpResponse]$Response;
}
to:
class AcmeHttpException : System.Exception {
AcmeHttpException([string]$_message, [AcmeHttpResponse]$_response) {
throw "$($_message)`n$($_response.Content)"
}
}
As per the new acme draft version the methods should support GET AS POST request instead of GET request. I updated the Get Authorization method below and tested it. Please incorporate it into the client
--- a/ACME-PS/functions/Authorization/Get-Authorization.ps1
+++ b/ACME-PS/functions/Authorization/Get-Authorization.ps1
@@ -30,16 +30,26 @@ function Get-Authorization {
[Parameter(Mandatory = $true, Position = 0, ParameterSetName = "FromUrl")]
[ValidateNotNullOrEmpty()]
[uri]
$Url
$Url,
[Parameter(Mandatory = $true, Position = 0)]
[ValidateNotNull()]
[ValidateScript({$_.Validate()})]
[AcmeState]
$State
)
process {
$payload = @{};
switch ($PSCmdlet.ParameterSetName) {
"FromOrder" {
$Order.AuthorizationUrls | ForEach-Object { Get-Authorization -Url $_ }
$Order.AuthorizationUrls | ForEach-Object { Get-Authorization -Url $_ $State }
}
Default {
$response = Invoke-AcmeWebRequest $Url -Method GET;
#$response = Invoke-AcmeWebRequest $Url -Method POST;
$response = Invoke-SignedWebRequest $Url $State $payload;
return [AcmeAuthorization]::new($response);
}
}
Certificate revocation is not yet implemented.
The CertKey Interface needs to be extended to have Sign(...)
and ExportJwsPublicKey(…)
Hello,
When an order fails to be created because you have been rate limited by Let'sEncrypt it returns the following error:
Cannot find an overload for "new" and the argument count: "2". You cannot call a method on a null-valued expression.
You cannot call a method on a null-valued expression.
At C:\MDaemon\LetsEncrypt\Modules\ACME-PS\1.1.0\ACME-PS.psm1:847 char:67
+ ... tifiers = $order.Identifiers | Foreach-Object { $_.ToString() } | Sor ...
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Cannot find an overload for "new" and the argument count: "2".
At C:\MDaemon\LetsEncrypt\Modules\ACME-PS\1.1.0\ACME-PS.psm1:2514 char:9
+ $order = [AcmeOrder]::new($response, $csrOptions);
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
I think the module should be improved to detect errors from Let's Encrypt so that error information can be returned. When I dug into it $response = Invoke-SignedWebRequest $requestUrl $State $payload; (at line 2512) was returning the following:
RequestUri : https://acme-v02.api.letsencrypt.org/acme/new-order
StatusCode : 429
NextNonce : 0001Mwcfu-A5FTl84_LLWqCDHBpSwJrtuaeeyR9QYS1eJDE
Headers : {Link, Server, Replay-Nonce, Date...}
Content : @{type=urn:ietf:params:acme:error:rateLimited; detail=Error creating new order :: too many certificates already issued for exact set of domains: List of domains here : see https://letsencrypt.org/docs/rate-limits/; status=429}
IsError : True
ErrorMessage : Server returned problem (Status: 429).
So - to allow this the following has to happen:
I don't see any donwsides to this approach currently.
Changing the state-object needs caution, due to probability of breaking changes, but else ...
Originally posted by @glatzert in #46 (comment)
for example
New-ACMEOrder $state -Identifiers $identifier -CertKeyLength 4096
Looks like currently it defaults to 4096 which is plenty large
Currently the module picks the CN of the certificate from the DNS name list.
Since Update-Order will normally be called before Complete-Order the list is updated from the ACME service, which orders the identifiers by name. Thus the CN will always be the first identifier in alphabetical order.
This Issue is to discuss:
#17 seems to be an valid approach, but could be refined to allow covering a broader set of use cases.
Export-Certificate currently only supports exporting pfx, which is okay, but needs additional steps in unix to get key.pem and cert.pem via openssl.
This can probably be implemented in the Export-Certificate cmdlet
Hi.
Generated a certificate using this module.
I get a PFX file that I import in Exchange 2013
It is imported with an invalid CSP provider:
"Microsoft Software Key Storage Provider"
And you need the provider to be:
"Microsoft Enhanced Cryptographic Provider v1.0"
or
"Microsoft RSA SChannel Cryptographic Provider"
Found a solution to work around this problem
openssl.exe pkcs12 -in certificate.pfx -out certificate.pem -nodes
openssl.exe pkcs12 -export -in certificate.pem -out new_certificate.pfx
After that, the certificate is imported with the desired provider:
"Microsoft Enhanced Cryptographic Provider v1.0"
Can you fix it?
We've completed a full regression test going from "1.1.0" to "1.1.4". Looks good Thomas! We are looking forward to a final test of your soon-to-be released "1.1.5" version of "AcmeHttpException".
While reviewing "AcmeState" we noticed something new, a PEM file that looks like:
.\Orders\Order-sPiHXRi3mrAaVVlnaiBlMN27Pe6qXz-ldnXhh0Ixgao.pem
We would prefer not to discard "AcmeState" after each "ACME-PS" run. We use it to diagnose issues, if any. We cleanup the previous "AcmeState" during the next run. So sensitive data can't linger there.
Since "Export-ACMECertificate" explicitly exports to PFX format, can you cleanup the PEM file in the "Orders" folder after "Export-ACMECertificate" completes?
Currently the module is set to support PS Core 6.0+ (since the Certificate functions are .NET Core App 2.1 only).
But it's also okay to run it with .NET 4.7.2 since, the relevant functions have been made available there also.
The psd1 should be changed to allow that.
There are currently no meaningful tests.
The test coverage should be 100% for all public functions.
To accomplish this mocking seems the only practical solution.
It might be possible to run an integration test with LE-Staging, but the Completion of an Challenge might be challenging.
First, I don't mean to pile on because I think the work you've done here is terrific Tom. Thank you for making such a valuable contribution to the developer community. And please let me know if my next comments would be more appropriate elsewhere.
I have seen the same issue reported by Slamich and I independently arrived at the same solution (ie. "openssl.exe"). I am fine with leaving it at that.
"The fact is that there were no such problems with the previous ASMESharp module."
This is my real concern.
I am sure there are many others who migrated to "ACME-PS" from "ASMESharp" (who are also very grateful for your efforts Tom). With that migration in mind I have been wondering about something else.
One nice feature of "ASMESharp" was its "stateless" implementation (ie. it saved 100% of its own state to disk). That approach allowed its various commands to be run independently in multiple (ie. separate) Powershell sessions (one after another) without concern for losing state.
"ACME-PS" does not allow this. While "ACME-PS" saves some of its state to disk, the balance requires the use of temporary in-memory PS variables. That means users must complete the entire process in a single Powershell session.
Can you please explain that design choice Tom? Is there an easy way to arrive at a similar "stateless" approach (ie. similar to how "ASMESharp" manages 100% of its own state itself) ?
Originally posted by @GeorgeSchiro in #45 (comment)
Hi
I'm able to get a PFX file, but if I tru to access it using OpenSSL i am promptet for a password ?
$order.CertificateUrl gives me an URL and that URL downloads a file with two certificates inside.
Is this two certificates two out of three of those I need ?
SSLCertificateFile "C:/Apache/g12ssl/www_sublim_dk/certificate.crt"
SSLCertificateKeyFile "C:/Apache/g12ssl/www_sublim_dk/private.key"
SSLCACertificateFile "C:/Apache/g12ssl/www_sublim_dk/ca_bundle.crt"
Please be aware that lot's of people just need some certificates. We don't nedd to understand the depth of ACME. So when you write this:
The certificate chain is not part of the issued certifcate. To get a correct certificate chain, you'll need to import the intermediate certificates from your acme service. For Lets Encrypt you can obtain them via https://letsencrypt.org/certificates/.
Then some of us are left behind...
Will it be possible to do some guidence so that we can make PowerShell, AcmeV2 and Apache to live together ?
the last line has a typo:
$CertificateKey.ExportPfx($certicate, $Passsword) | Set-Content $Path -Encoding byte
should be $Password instead of $Passsword
When using LetsEncrypt-Staging, the ResourceUrl and AuthorizationUrls are supposed to show the output/errors for a particular challenge. However they do not work properly. Instead of showing proper valid output, they show an error instead.
An example is https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/47902800
{
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Method not allowed",
"status": 405
}
This error 405 might be apparently related to a recent change in LetsEncrypt-Staging where anonymous requests result in this. But I'm not sure as I'm not familiar enough with the protocol.
Note, I'm not sure if it breaks the whole challenge or not. The returned result shows "Status : valid" but my script sometimes throws an exception when I try to Export-ACMECertificate but of course I can't see why.
ACME-PS v1.1.5
Az.Accounts v1.7.3
Az.automation v1.3.6
Hi,
Thanks for the work on your module, it works great! I do have one issue, which might already be supported, but I can't seem to find a solution right now.
Currently when completing a request for a new certificate I'm getting the cert fine, but I'm not getting the full chain. From certbot this is the fullchain.pem
file. This is sadly required for some Java applications which is running against my application. https://www.ssllabs.com also reports a missing file in the chain. Any suggestion on who I can mitigate it?
Here's my full script to update:
# Create a new state object for the LetsEncrypt Module
$state = New-ACMEState -Path $env:TEMP
$serviceName = 'LetsEncrypt'
# Fetch the service directory and save it in the state
Get-ACMEServiceDirectory $state -ServiceName $serviceName -PassThru
# Get the first anti-replay nonce
New-ACMENonce $state
# Create an account key. The state will make sure it's stored.
New-ACMEAccountKey $state -PassThru
# Register the account key with the acme service. The account key will automatically be read from the state
New-ACMEAccount $state -EmailAddresses $EmailAddress -AcceptTOS
# Load an state object to have service directory and account keys available
$state = Get-ACMEState -Path $env:TEMP
# It might be neccessary to acquire a new nonce, so we'll just do it for the sake of the example.
New-ACMENonce $state -PassThru
# Create the identifier for the DNS name
$identifier = New-ACMEIdentifier $domain
# Create the order object at the ACME service.
$order = New-ACMEOrder $state -Identifiers $identifier
# Fetch the authorizations for that order
$authZ = Get-ACMEAuthorization -State $state -Order $order
# Select a challenge to fullfill
$challenge = Get-ACMEChallenge $state $authZ "http-01"
# Inspect the challenge data
$challenge.Data
# Gets the content of the challenge
$challengeContent = $challenge.Data.Content
# Create the file requested by the challenge
$fileName = $env:TMP + '\' + $challenge.Token
Set-Content -Path $fileName -Value $challengeContent -NoNewline
# Stores the challenge file in a public storage account
$blobName = ".well-known/acme-challenge/" + $challenge.Token
$storageAccount = Get-AzStorageAccount -ResourceGroupName $STResourceGroupName -Name $storageName
$ctx = $storageAccount.Context
# Set the Blob Content type so it shows in a browser
$blobProperties = @{
"ContentType" = "text/plain; charset=utf-8"
}
Set-AzStorageBlobContent -File $fileName -Container $stContainer -Context $ctx -Blob $blobName -Properties $blobProperties
# Signal the ACME server that the challenge is ready
$challenge | Complete-ACMEChallenge $state
# Wait a little bit and update the order, until we see the states
while ($order.Status -notin ("ready", "invalid"))
{
Start-Sleep -Seconds 10
$order | Update-ACMEOrder $state -PassThru
}
# We should have a valid order now and should be able to complete it
# Therefore we need a certificate key
$certKey = New-ACMECertificateKey -Path "$env:TEMP\$domain.key.xml"
# Complete the order - this will issue a certificate singing request
Complete-ACMEOrder $state -Order $order -CertificateKey $certKey
# Now we wait until the ACME service provides the certificate url
while (-not $order.CertificateUrl)
{
Start-Sleep -Seconds 15
$order | Update-ACMEOrder $state -PassThru
}
# As soon as the url shows up we can create the PFX
$password = ConvertTo-SecureString -String $CertPW -Force -AsPlainText
Export-ACMECertificate $state -Order $order -CertificateKey $certKey -Path "$env:TEMP\$domain.pfx" -Password $password
In line 1389 you call the parameter "Suppresskeyid" however the function parameter is named "Supresskeyid" resulting in an error.
Some functions lack of proper documentation.
This needs to be added.
I have an Azure Automation runbook that uses ACME-PS and Az.Storage modules.
When ACME-PS module (1.1.5) is loaded, cmdlets from Az.Storage (1.12.0) throw exceptions.
$ErrorActionPreference = 'Stop'
"Loaded modules:"
Get-Module
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
$connectionResult = Connect-AzAccount -Tenant $servicePrincipalConnection.TenantID `
-ApplicationId $servicePrincipalConnection.ApplicationID `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint `
-ServicePrincipal
"Logged in."
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
$stateDir = "$($PWD.Path)\acmestate-LetsEncrypt-Staging"
# Ensure state directory exists
if(!(Test-Path $stateDir -t Container)){
New-Item -ItemType Directory -Force -Path $stateDir | Out-Null
}
if(Get-Module 'ACME-PS'){"Module ACME-PS is loaded"}else{"Module ACME-PS is not loaded"}
"New-ACMEState:"
# *** Comment/Uncomment the following line to trigger crashes
# *** Note that once uncommented, the crashes will recur even AFTER the line is commented out again
$state = New-ACMEState -Path $stateDir
if(Get-Module 'ACME-PS'){"Module ACME-PS is loaded"}else{"Module ACME-PS is not loaded"}
if(Get-Module 'ACME-PS'){
# This line does not appear to have any effect
"Unloading Removing module ACME-PS"
Remove-Module 'ACME-PS' -Force -Verbose
}
if(Get-Module 'ACME-PS'){"Module ACME-PS is loaded"}else{"Module ACME-PS is not loaded"}
try{
"Get-AzContext: "
$AzStorageProfile = Get-AzContext -ListAvailable | ? { $_.Subscription.Name -eq 'Pay-As-You-Go' }
$AzStorageProfile
"Get-AzStorageAccount: "
$AzStorageAcc = Get-AzStorageAccount -Name '__REDACTED_STORAGE_ACCOUNT_NAME__' -ResourceGroupName '__REDACTED_STORAGE_ACCOUNT_RG_NAME__' -DefaultProfile $AzStorageProfile
$AzStorageAcc
}
catch [System.Management.Automation.CommandNotFoundException]{
"Caught exception!"
$_ | Select-Object -Property *
}
System.Management.Automation.CommandNotFoundException: The 'Get-AzStorageAccount' command was found in the module 'Az.Storage', but the module could not be loaded. For more information, run 'Import-Module Az.Storage'. ---> System.Management.Automation.CmdletInvocationException: The following error occurred while loading the extended type data file:
Microsoft.PowerShell, C:\Modules\User\ACME-PS\Types.ps1xml(8) : Error in type "AcmeState": The "Type" node must have "Members", "TypeConverters", or "TypeAdapters".
Microsoft.PowerShell, C:\Modules\User\ACME-PS\Types.ps1xml(11) : Error: Unable to find type [AcmeObjectConverter].
Microsoft.PowerShell, C:\Modules\User\ACME-PS\Types.ps1xml(2) : Error in type "AcmeIdentifier": The "Type" node must have "Members", "TypeConverters", or "TypeAdapters".
Microsoft.PowerShell, C:\Modules\User\ACME-PS\Types.ps1xml(5) : Error: Unable to find type [AcmeObjectConverter].
---> System.Management.Automation.RuntimeException: The following error occurred while loading the extended type data file:
Microsoft.PowerShell, C:\Modules\User\ACME-PS\Types.ps1xml(8) : Error in type "AcmeState": The "Type" node must have "Members", "TypeConverters", or "TypeAdapters".
Microsoft.PowerShell, C:\Modules\User\ACME-PS\Types.ps1xml(11) : Error: Unable to find type [AcmeObjectConverter].
Microsoft.PowerShell, C:\Modules\User\ACME-PS\Types.ps1xml(2) : Error in type "AcmeIdentifier": The "Type" node must have "Members", "TypeConverters", or "TypeAdapters".
Microsoft.PowerShell, C:\Modules\User\ACME-PS\Types.ps1xml(5) : Error: Unable to find type [AcmeObjectConverter].
at System.Management.Automation.Runspaces.FormatAndTypeDataHelper.ThrowExceptionOnError(String errorId, Collection`1 independentErrors, Collection`1 PSSnapinFilesCollection, RunspaceConfigurationCategory category)
at System.Management.Automation.Runspaces.RunspaceConfigurationEntryCollection`1.Update(Boolean force)
at Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadModuleManifest(String moduleManifestPath, ExternalScriptInfo manifestScriptInfo, Hashtable data, Hashtable localizedData, ManifestProcessingFlags manifestProcessingFlags, Version minimumVersion, Version maximumVersion, Version requiredVersion, Nullable`1 requiredModuleGuid, ImportModuleOptions& options, Boolean& containedErrors)
--- End of inner exception stack trace ---
at System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input)
at System.Management.Automation.PowerShell.Worker.ConstructPipelineAndDoWork(Runspace rs, Boolean performSyncInvoke)
at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke[T]()
at System.Management.Automation.CommandDiscovery.AutoloadSpecifiedModule(String moduleName, ExecutionContext context, SessionStateEntryVisibility visibility, Exception& exception)
--- End of inner exception stack trace ---
at System.Management.Automation.CommandDiscovery.TryModuleAutoDiscovery(String commandName, ExecutionContext context, String originalCommandName, CommandOrigin commandOrigin, SearchResolutionOptions searchResolutionOptions, CommandTypes commandTypes, Exception& lastError)
at System.Management.Automation.CommandDiscovery.LookupCommandInfo(String commandName, CommandTypes commandTypes, SearchResolutionOptions searchResolutionOptions, CommandOrigin commandOrigin, ExecutionContext context)
at System.Management.Automation.CommandDiscovery.LookupCommandProcessor(String commandName, CommandOrigin commandOrigin, Nullable`1 useLocalScope)
at System.Management.Automation.ExecutionContext.CreateCommand(String command, Boolean dotSource)
at System.Management.Automation.PipelineOps.AddCommand(PipelineProcessor pipe, CommandParameterInternal[] commandElements, CommandBaseAst commandBaseAst, CommandRedirection[] redirections, ExecutionContext context)
at System.Management.Automation.PipelineOps.InvokePipeline(Object input, Boolean ignoreInput, CommandParameterInternal[][] pipeElements, CommandBaseAst[] pipeElementAsts, CommandRedirection[][] commandRedirections, FunctionContext funcContext)
at System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
Name | Last modified | Status | Version |
---|---|---|---|
ACME-PS | 18/02/2020, 11:27 am | Available | 1.1.5 |
AuditPolicyDsc | 27/02/2020, 8:07 pm | Available | 1.1.0.0 |
Az.Accounts | 02/03/2020, 9:57 am | Available | 1.7.2 |
Az.Automation | 02/03/2020, 9:59 am | Available | 1.3.6 |
Az.Dns | 19/02/2020, 3:51 pm | Available | 1.1.2 |
Az.Resources | 02/03/2020, 9:59 am | Available | 1.11.0 |
Az.Sql | 02/03/2020, 9:59 am | Available | 2.3.0 |
Az.Storage | 18/02/2020, 10:52 am | Available | 1.12.0 |
Azure | 25/02/2020, 10:44 am | Available | 5.3.0 |
Azure.Storage | 25/02/2020, 10:41 am | Available | 4.6.1 |
AzureRM.Automation | 25/02/2020, 10:41 am | Available | 6.1.1 |
AzureRM.Compute | 25/02/2020, 10:41 am | Available | 5.9.1 |
AzureRM.Profile | 25/02/2020, 10:39 am | Available | 5.8.3 |
AzureRM.Resources | 25/02/2020, 10:41 am | Available | 6.7.3 |
AzureRM.Sql | 25/02/2020, 10:41 am | Available | 4.12.1 |
AzureRM.Storage | 25/02/2020, 10:43 am | Available | 5.2.0 |
ComputerManagementDsc | 27/02/2020, 8:06 pm | Available | 5.0.0.0 |
GPRegistryPolicyParser | 27/02/2020, 8:07 pm | Available | 0.2 |
REDACTED_PRIVATE_MODULE | 02/03/2020, 11:25 am | Available | 1.0.0.2 |
Microsoft.PowerShell.Core | 27/02/2020, 7:55 pm | Available | 0.0 |
Microsoft.PowerShell.Diagnostics | 27/02/2020, 7:55 pm | Available | Microsoft.PowerShell.Management |
PSDscResources | 27/02/2020, 8:08 pm | Available | 2.9.0.0 |
SecurityPolicyDsc | 27/02/2020, 8:07 pm | Available | 2.1.0.0 |
StateConfigCompositeResources | 27/02/2020, 8:09 pm | Available | 1.0 |
xDSCDomainjoin | 27/02/2020, 8:06 pm | Available | 1.1 |
xPowerShellExecutionPolicy | 27/02/2020, 8:05 pm | Available | 1.1.0.0 |
xRemoteDesktopAdmin | 27/02/2020, 8:06 pm | Available | 1.1.0.0 |
A lot of "Terminating" errors (or should be terminating errors) are currently non-terminating.
This needs cleanup
Hi,
is it possible to get the private key as pem? I know, i can export the certificate as .pfx and afterwards convert it via openssl. But i think the ability to export the key pem would be helpful.
BR
JoePhanDro
We started full regression testing of "1.1.5" this morning and noticed an error not seen before. So we went back to "1.1.4" (which tested fine several days ago) to see if we get the same error. We did:
$challenge | Complete-ACMEChallenge "C:\Users\admin\Desktop\tmp\AcmeState"
Exception calling "GetResult" with "0" argument(s): "An error occurred while sending the request."
At C:\Users\admin\Desktop\tmp\ACME-PS\1.1.4\ACME-PS.psm1:1344 char:5
+ $httpResponse = $httpClient.SendAsync($httpRequest).GetAwaiter(). ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : HttpRequestException
Exception setting "expires": "Cannot convert null to type "System.DateTimeOffset"."
At C:\Users\admin\Desktop\tmp\ACME-PS\1.1.4\ACME-PS.psm1:750 char:9
+ $this.expires = $httpResponse.Content.expires;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
At first we thought it might be a problem with LE. Then we bounced the server and the problem went away.
Should this error possibly be handled differently? Perhaps at least a null check on the "expires" value?
All State changing operations should support -WhatIf
You mentioned in Issue #36 that it doesn't differentiate between renewals and new requests. However following the samples through and then re-running it to force a renewal results in
`Order-yyyyyyzzz.key.xml already exists. This method
will not override existing files
At C:\Program Files\WindowsPowerShell\Modules\ACME-PS\1.1.5\ACME-PS.psm1:2207 char:13
throw "$Path already exists. This method will not overrid ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Which is correct, as the Service\Orders folder contains the
Order-yyyyyyzzz.key.xml
Order-yyyyyyzzz.xml
Order-yyyyyyzzz.pem
and OrderList.txt contains the entry as well.
Are you proposing that these should be cleaned up manually, or is there a method currently not show in the samples to perform a clean-up to permit a renewal run to occur?
Thanks,
Hi,
please help.
I have tried to supply an array [AcmeIdentifier[]] for the New-ACMEOrder
that sows an error in the next function: Get-ACMEAuthorization
# Create the identifier for the DNS name
$ACMEIdentifierCN = New-ACMEIdentifier $LECERT_ServerCN;
# Build Identifier-Array
[AcmeIdentifier[]] $ACMEIdentifiers = $NULL;
$ACMEIdentifiers +=$ACMEIdentifierCN;
#Add SANs
foreach ($SAN in $LECERT_SANs)
{
$ACMEIdentifiers += New-ACMEIdentifier $SAN
}
# Create the order object at the ACME service.
$ACMEOrder = New-ACMEOrder $ACMEState -Identifiers $ACMEIdentifiers;
# Fetch the authorizations for that order
$ACMEauthZ = Get-ACMEAuthorization -Order $ACMEOrder;
Error:
-> The type System.Object[] cannot converted into type AcmeAuthorization
original (in german)
Get-ACMEChallenge : Die Argumenttransformation für den Parameter "Authorization" kann nicht verarbeitet werden. Der Wert "System.Object[]" vom Typ "System.Object[]" kann nicht in den Typ "AcmeAuthorization" konvertiert werden.
is there some problem if the identifier is not even a single value?
how does it work to get a certificate with more than one name (SANs)?
Thomas,
You still have the "Authroization" typo in your readme.
That said, this "issue" is just an excuse to let you know we've been testing V1.1.5 for the past 2 months with no issues and how impressed we are!
You've done excellent work and you should be very proud of it Thomas.
Thank you!
'Geo
Ps. You should also know that we were nonplussed when we learned your tool (a replacement for "ACMESharp" - after ACME v1 was deprecated) contains no DLLs! We were amazed to see your code doing everything the former could - with PS only! It's an unbelievably clean solution which makes our "GetCert2" that much cleaner than its predecessor as a result. Then, on top of all that, your non-hesitant willingness to add session independence (between ACME-PS calls) put our admiration over the top. Kudos my friend. If we can make a donation. please let me know how.
These commands offer feedback upon successful completion:
Complete-ACMEChallenge
Export-ACMECertificate (in the form of a PFX file)
Get-ACMEServiceDirectory
New-ACMEAccountKey
New-ACMEOrder
New-ACMEState
Update-ACMEOrder
These don't:
Complete-ACMEOrder
Get-ACMEAuthorization
New-ACMEAccount
New-ACMENonce
It would be nice if at least "Complete-ACMEOrder" offered some feedback.
Thank you again for all of your great effort Thomas. The tool is excellent.
Could you please share which acme draft version is supported by client?
Also do you think your library could support account deactivation? see https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-7.3.7
as proposed in #38
When I try to run Complete-ACMEOrder with an order with multiple identifiers, I get this error:
Server returned Problem: {
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Error finalizing order :: policy forbids issuing for: \"*.standardaction.net standardaction.net\"",
"status": 400
}
At C:\Program Files\WindowsPowerShell\Modules\ACME-PS\1.0.2\ACME-PS.psm1:1081 char:9
+ throw "Server returned Problem: $response"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Server returned..."status": 400
}:String) [], RuntimeException
+ FullyQualifiedErrorId : Server returned Problem: {
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Error finalizing order :: policy forbids issuing for: \"*.standardaction.net standardaction.net\"",
"status": 400
}
Export-Certificate
uses Set-Content -Encoding byte
to save the certificate.
There was a breaking change in PowerShell 6.0 that drops the byte
encoding. PS 6 requires a new -AsByteStream
switch instead.
Hi
I can not figure out what is wrong here... I think I have attached all relevant info.
Hope you can help
AcmeState.zip
ps_log.txt
.well-known.zip
Regards from rainy Copenhagen :-)
First, the new "stateless" features (which are really "stateful" - ie. session independent, see #46) are working great! Thank you Thomas.
I've completed most of my testing and noticed only one issue: new state is not limited to the "{path to AcmeState}" folder (where "{path to AcmeState}" is the path given to "New-ACMEState").
New state items are appearing in the parent folder of "{path to AcmeState}":
"{path to AcmeState}Orders\"
"{path to AcmeState}Account.xml"
"{path to AcmeState}AccountKey.xml"
Can you move the new state to the "{path to AcmeState}" folder?
Is there an example or can you expand on the sample in the Readme document for creating a certificate or 2 dns names? e.g. example.com & www.example.com
I was looking for a suitable solution to automate the IIS-Configuration to support files (mime-types) without extension. I have found a way to do this with powershell and don't have to config that by GUI but: (for me) the solution in the comments dit not work.
I think that was because there is also a handler configuration change neccessary.
After a lot of reading i found a probably better solution: Place a web.config into the challenge directory.
You can copy it from elsewhere or create ist with Set-Content.
At the end the web-config has do exist next to the challenge file before the Check if the challenge is readable ( Invoke-WebRequest $challenge.Data.AbsoluteUrl)
That works for me (Server2016 / IIS10 )without the need of a GUI
Content of web.config (sorry for the format):
<?xml version = "1.0" encoding="UTF-8"?> <configuration> <system.webServer> <staticContent> <mimeMap fileExtension="." mimeType="text/plain" /> <mimeMap fileExtension=".*" mimeType="text/plain" /> </staticContent> <handlers> <clear /> <add name="StaticFile" path="*" verb="*" type="" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" scriptProcessor="" resourceType="Either" requireAccess="Read" allowPathInfo="false" preCondition="" responseBufferLimit="4194304" /> </handlers> </system.webServer> </configuration>
OS: Windows 2012 R2
Powershell: 5.1
Webserver: IIS
Trying to automate my IIS server certificate using this ACME client. I followed the docs (including all the validation steps) up to the command Complete-ACMEChallenge
:
Complete-ACMEChallenge -IdentifierRef portal -ChallengeType http-01 -Handler iis -HandlerParameters @{WebSiteRef = 'Portal'}
Complete-ACMEChallenge : unresolved site for given site reference
At line:1 char:1
+ Complete-ACMEChallenge -IdentifierRef portal -ChallengeType http-01 - ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Complete-ACMEChallenge], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,ACMESharp.POSH.CompleteChallenge
Looks like the iis
handler can't find my IIS site Portal
but if I do Get-Website
I get the following:
Name ID State Physical Path Bindings
---- -- ----- ------------- --------
Portal 2 Started C:\inetpub\wwwroot https *:443: sslFlags=0
Any idea what am I doing wrong ?
Hey!
Thank you for this library. Very useful. Just a quick note to say that 1.1.0 is not published on PSGallery.
Also do you think your library could support account deactivation? see https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-7.3.7
Thank you
The main readme has Get-ServiceDirectory
but I think it should be Get-ACMEServiceDirectory
. THe first option failed when I attempted to run the script.
Hello,
First of all I wanted to express my appreciation for this Powershell module that support Acme v,2 protocol. Really great work. It was working perfectly till today..
I managed to issue certificates for may domains, but today when script was running I get the Status: Invalid
I have deleted AcmeState folder and tried to rerun the script, same error. Also Absolute Url is available and can be requested.
Thanks in advance for the help.
Moving the ACME-PS commands to another domain with my employee showed, that WPAD will be used.
Unfortunately WPAD is not available everywhere so we need to allow usage of a defined proxy.
Since it's common in *nix, we'll go for $env:HTTP_PROXY probably.
Add CreationDate to Order-Object and include in hash.
Keep compatibility with older orders.
In your IISExtensionless.md sample you have:
<mimeMap fileExtension=".*" mimeType="text/plain" />
It should be:
<mimeMap fileExtension="." mimeType="text/plain" />
.* causes the directory to be unreadable client side
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.