kelunik / acme

Async ACME library written in PHP based on the Amp concurrency framework.
MIT License
122 stars 17 forks source link

Discrepancy between master and latest release #26

Closed prewk closed 7 years ago

prewk commented 7 years ago

Hi, I really need the "namshi/jose": "^7", constraint from master that isn't present in the latest release 0.3.3.

Is there a good reason why you haven't released the changes yet?

Thanks!

kelunik commented 7 years ago

Mostly time to finish some changes I planned. I can release v0.4.0 anyway and will add those features in v0.5.0 which will be based on Amp v2 then.

prewk commented 7 years ago

That'd be great!

kelunik commented 7 years ago

Just because I'm curious: Where are you using the library?

prewk commented 7 years ago

We're implementing HTTPS for our customers in a multi-tenant CMS. Our general idea is that some PHP workers are going to create and refresh the certs. Your library is the only one I've found suitable for PHP, although we won't be running stuff in async.

If we're not successful, we'll probably just wrap one of the CLI clients instead, though.

kelunik commented 7 years ago

Not running stuff in async is totally fine, I just wrote it in async so it can be used, e.g. in Aerys to automatically issue and renew certificates.

You could also just wrap https://github.com/kelunik/acme-client, yes, but then you could also wrap any other CLI client.

kelunik commented 7 years ago

v0.4.0 has been released. :tada:

prewk commented 7 years ago

Are you up for answering some simple questions about the process? I might be misunderstanding how the manual Let's Encrypt process works so it's okay to yell at me if that's the case, but I've dug around as much as I could and can't get further.

The process as I've imagined it:

// Trying the staging url but the production url gives me the same results
$directoryUri = "https://acme-staging.api.letsencrypt.org/directory";
  1. $key = $keyGenerator->generate()
  2. $service = new AcmeService(new AcmeClient($directoryUri, $key))
  3. $challenges = $service->requestChallenges("www.my-domain.com") (Shouldn't I provide a key here somehow?)
  4. $challenges contains some challenge types with tokens and uris. I pluck out the http-01 one.
  5. $keyAuth = generateKeyAuthorization($key, $challengeToken)
  6. I make sure www.my-domain.com/.well-known/acme-challenge/$challengeToken returns ?????? (Do I receive this JSON blob in step 3?)
  7. $answered = $service->answerChallenge($challengeUri, $keyAuth)
  8. $service->pollForChallenge($challengeUri) until validated/failed
  9. How do I generate a CSR using the service?
  10. $certUri = $service->requestCertificate($csr)
  11. $certChain = $service->pollForCertificate($certUri)

$certChain should now be a certificate chain. Is this somewhat correct?

Problem is right now that, everytime I try to do a requestChallenges I get this error:

Invalid response: No registration exists matching provided key. Request URI: https://acme-staging.api.letsencrypt.org/acme/new-authz.

Thanks a bunch. I understand you can't be expected to give detailed Let's Encrypt support, but any pointers would help.

kelunik commented 7 years ago

Yes, that's pretty much right.

If you don't want to use async, you can wrap the calls in Amp\wait, otherwise I'd recommend using a coroutine and yield to await the promises returned from the methods.

prewk commented 7 years ago

Thanks, this helped me a lot!

prewk commented 7 years ago

One final thing, which certificate in the chain is "the one" for my requested DNS name? First? Last?

I'm going to import them into AWS ACM, so I need both "the certificate" and "the chain".

kelunik commented 7 years ago

The first one, see https://github.com/kelunik/acme-client/blob/f4cabf755b0615ef1e33a0efbbfdeb2a8081cc33/src/Stores/CertificateStore.php#L46-L77

prewk commented 7 years ago

I'm struggling a bit with OpenSSLCSRGenerator->generate. The docs say that it returns a promise, but Amp\wait doesn't seem to work with it: Type error: Argument 1 passed to Amp\wait() must implement interface Amp\Promise, instance of Generator given

So I'm thinking, I should turn this generator into a Promise with Amp\resolve first. This seems to work, but the result from the generate method is a bool true instead of a string CSR.

So I dig into the OpenSSLCSRGenerator source and find: yield new CoroutineResult(openssl_csr_export($csr, $csr));.

It seems to be returning the result of openssl_scr_export which is always a bool (http://se2.php.net/manual/en/function.openssl-csr-export.php), instead of the &out ref argument that openssl_scr_export writes to (weird old C API, I suppose).

kelunik commented 7 years ago

Yes, I also noticed that earlier today while rewriting the library to Amp v2. Want to provide a PR that fixes it?

prewk commented 7 years ago

Gladly! I'll do one tomorrow.

prewk commented 7 years ago

https://github.com/kelunik/acme/pull/27