Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
"""Let's Encrypt client API."""
|
2014-12-10 05:32:22 -05:00
|
|
|
import logging
|
2014-11-21 15:06:13 -05:00
|
|
|
import os
|
2012-05-28 02:14:55 -04:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
from cryptography.hazmat.backends import default_backend
|
|
|
|
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
2015-07-06 07:48:09 -04:00
|
|
|
import OpenSSL
|
2015-11-10 19:03:18 -05:00
|
|
|
import zope.component
|
2014-11-13 04:49:32 -05:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
from acme import client as acme_client
|
2015-05-10 07:26:21 -04:00
|
|
|
from acme import jose
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
from acme import messages
|
2015-02-01 05:07:36 -05:00
|
|
|
|
2016-03-11 18:37:24 -05:00
|
|
|
import letsencrypt
|
|
|
|
|
|
2015-05-10 08:25:29 -04:00
|
|
|
from letsencrypt import account
|
|
|
|
|
from letsencrypt import auth_handler
|
2015-06-02 08:10:22 -04:00
|
|
|
from letsencrypt import configuration
|
|
|
|
|
from letsencrypt import constants
|
2015-05-10 08:25:29 -04:00
|
|
|
from letsencrypt import crypto_util
|
|
|
|
|
from letsencrypt import errors
|
2015-09-23 18:02:20 -04:00
|
|
|
from letsencrypt import error_handler
|
2015-11-10 19:03:18 -05:00
|
|
|
from letsencrypt import interfaces
|
2015-05-10 08:25:29 -04:00
|
|
|
from letsencrypt import le_util
|
|
|
|
|
from letsencrypt import reverter
|
2015-05-13 15:10:36 -04:00
|
|
|
from letsencrypt import storage
|
2012-08-10 00:07:59 -04:00
|
|
|
|
2015-05-10 08:25:29 -04:00
|
|
|
from letsencrypt.display import ops as display_ops
|
|
|
|
|
from letsencrypt.display import enhancements
|
2016-03-11 18:24:57 -05:00
|
|
|
from letsencrypt.plugins import selection as plugin_selection
|
2014-11-18 11:13:06 -05:00
|
|
|
|
2012-08-06 18:27:05 -04:00
|
|
|
|
2015-06-11 09:45:41 -04:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
2015-11-12 22:52:32 -05:00
|
|
|
def acme_from_config_key(config, key):
|
2015-11-13 15:48:44 -05:00
|
|
|
"Wrangle ACME client construction"
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
# TODO: Allow for other alg types besides RS256
|
2015-11-10 19:04:56 -05:00
|
|
|
net = acme_client.ClientNetwork(key, verify_ssl=(not config.no_verify_ssl),
|
2015-11-12 22:52:32 -05:00
|
|
|
user_agent=_determine_user_agent(config))
|
2015-11-13 20:09:54 -05:00
|
|
|
return acme_client.Client(config.server, key=key, net=net)
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
|
|
|
|
|
|
2015-11-12 22:52:32 -05:00
|
|
|
def _determine_user_agent(config):
|
|
|
|
|
"""
|
|
|
|
|
Set a user_agent string in the config based on the choice of plugins.
|
|
|
|
|
(this wasn't knowable at construction time)
|
|
|
|
|
|
2015-11-13 15:48:44 -05:00
|
|
|
:returns: the client's User-Agent string
|
2015-11-12 22:52:32 -05:00
|
|
|
:rtype: `str`
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
if config.user_agent is None:
|
|
|
|
|
ua = "LetsEncryptPythonClient/{0} ({1}) Authenticator/{2} Installer/{3}"
|
|
|
|
|
ua = ua.format(letsencrypt.__version__, " ".join(le_util.get_os_info()),
|
|
|
|
|
config.authenticator, config.installer)
|
|
|
|
|
else:
|
|
|
|
|
ua = config.user_agent
|
|
|
|
|
return ua
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def register(config, account_storage, tos_cb=None):
|
|
|
|
|
"""Register new account with an ACME CA.
|
|
|
|
|
|
|
|
|
|
This function takes care of generating fresh private key,
|
|
|
|
|
registering the account, optionally accepting CA Terms of Service
|
|
|
|
|
and finally saving the account. It should be called prior to
|
|
|
|
|
initialization of `Client`, unless account has already been created.
|
2014-11-30 07:56:09 -05:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
:param .IConfig config: Client configuration.
|
2014-11-30 07:56:09 -05:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
:param .AccountStorage account_storage: Account storage where newly
|
|
|
|
|
registered account will be saved to. Save happens only after TOS
|
|
|
|
|
acceptance step, so any account private keys or
|
|
|
|
|
`.RegistrationResource` will not be persisted if `tos_cb`
|
|
|
|
|
returns ``False``.
|
2015-04-06 20:03:07 -04:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
:param tos_cb: If ACME CA requires the user to accept a Terms of
|
|
|
|
|
Service before registering account, client action is
|
|
|
|
|
necessary. For example, a CLI tool would prompt the user
|
|
|
|
|
acceptance. `tos_cb` must be a callable that should accept
|
|
|
|
|
`.RegistrationResource` and return a `bool`: ``True`` iff the
|
|
|
|
|
Terms of Service present in the contained
|
|
|
|
|
`.Registration.terms_of_service` is accepted by the client, and
|
|
|
|
|
``False`` otherwise. ``tos_cb`` will be called only if the
|
|
|
|
|
client acction is necessary, i.e. when ``terms_of_service is not
|
|
|
|
|
None``. This argument is optional, if not supplied it will
|
|
|
|
|
default to automatic acceptance!
|
2014-11-30 07:56:09 -05:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
:raises letsencrypt.errors.Error: In case of any client problems, in
|
|
|
|
|
particular registration failure, or unaccepted Terms of Service.
|
|
|
|
|
:raises acme.errors.Error: In case of any protocol problems.
|
2014-11-30 07:56:09 -05:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
:returns: Newly registered and saved account, as well as protocol
|
|
|
|
|
API handle (should be used in `Client` initialization).
|
|
|
|
|
:rtype: `tuple` of `.Account` and `acme.client.Client`
|
2015-01-30 21:48:14 -05:00
|
|
|
|
2014-11-30 07:56:09 -05:00
|
|
|
"""
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
# Log non-standard actions, potentially wrong API calls
|
|
|
|
|
if account_storage.find_all():
|
|
|
|
|
logger.info("There are already existing accounts for %s", config.server)
|
|
|
|
|
if config.email is None:
|
2015-10-25 06:18:06 -04:00
|
|
|
if not config.register_unsafely_without_email:
|
|
|
|
|
msg = ("No email was provided and "
|
|
|
|
|
"--register-unsafely-without-email was not present.")
|
|
|
|
|
logger.warn(msg)
|
|
|
|
|
raise errors.Error(msg)
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
logger.warn("Registering without email!")
|
|
|
|
|
|
|
|
|
|
# Each new registration shall use a fresh new key
|
|
|
|
|
key = jose.JWKRSA(key=jose.ComparableRSAKey(
|
|
|
|
|
rsa.generate_private_key(
|
|
|
|
|
public_exponent=65537,
|
|
|
|
|
key_size=config.rsa_key_size,
|
|
|
|
|
backend=default_backend())))
|
2015-11-12 22:52:32 -05:00
|
|
|
acme = acme_from_config_key(config, key)
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
# TODO: add phone?
|
2015-11-16 14:17:41 -05:00
|
|
|
regr = perform_registration(acme, config)
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
|
|
|
|
|
if regr.terms_of_service is not None:
|
|
|
|
|
if tos_cb is not None and not tos_cb(regr):
|
|
|
|
|
raise errors.Error(
|
|
|
|
|
"Registration cannot proceed without accepting "
|
|
|
|
|
"Terms of Service.")
|
|
|
|
|
regr = acme.agree_to_tos(regr)
|
|
|
|
|
|
|
|
|
|
acc = account.Account(regr, key)
|
|
|
|
|
account.report_new_account(acc, config)
|
|
|
|
|
account_storage.save(acc)
|
2015-11-10 19:04:56 -05:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
return acc, acme
|
|
|
|
|
|
|
|
|
|
|
2015-11-16 14:17:41 -05:00
|
|
|
def perform_registration(acme, config):
|
|
|
|
|
"""
|
|
|
|
|
Actually register new account, trying repeatedly if there are email
|
|
|
|
|
problems
|
|
|
|
|
|
2015-11-17 19:01:53 -05:00
|
|
|
:param .IConfig config: Client configuration.
|
|
|
|
|
:param acme.client.Client client: ACME client object.
|
|
|
|
|
|
|
|
|
|
:returns: Registration Resource.
|
|
|
|
|
:rtype: `acme.messages.RegistrationResource`
|
|
|
|
|
|
|
|
|
|
:raises .UnexpectedUpdate:
|
2015-11-16 14:17:41 -05:00
|
|
|
"""
|
|
|
|
|
try:
|
2015-11-16 15:46:26 -05:00
|
|
|
return acme.register(messages.NewRegistration.from_data(email=config.email))
|
2016-01-30 22:53:50 -05:00
|
|
|
except messages.Error as e:
|
2016-03-17 19:01:40 -04:00
|
|
|
if e.typ == "urn:acme:error:invalidEmail":
|
2015-11-16 14:17:41 -05:00
|
|
|
config.namespace.email = display_ops.get_email(more=True, invalid=True)
|
|
|
|
|
return perform_registration(acme, config)
|
|
|
|
|
else:
|
|
|
|
|
raise
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
|
2015-11-20 18:12:05 -05:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
class Client(object):
|
|
|
|
|
"""ACME protocol client.
|
2015-01-09 08:30:15 -05:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
:ivar .IConfig config: Client configuration.
|
|
|
|
|
:ivar .Account account: Account registered with `register`.
|
|
|
|
|
:ivar .AuthHandler auth_handler: Authorizations handler that will
|
2016-03-01 18:24:43 -05:00
|
|
|
dispatch DV challenges to appropriate authenticators
|
|
|
|
|
(providing `.IAuthenticator` interface).
|
2016-03-01 17:53:10 -05:00
|
|
|
:ivar .IAuthenticator auth: Prepared (`.IAuthenticator.prepare`)
|
2016-03-01 20:56:23 -05:00
|
|
|
authenticator that can solve ACME challenges.
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
:ivar .IInstaller installer: Installer.
|
|
|
|
|
:ivar acme.client.Client acme: Optional ACME client API handle.
|
|
|
|
|
You might already have one from `register`.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
2016-03-01 17:53:10 -05:00
|
|
|
def __init__(self, config, account_, auth, installer, acme=None):
|
2015-09-16 01:48:36 -04:00
|
|
|
"""Initialize a client."""
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
self.config = config
|
2015-04-23 02:17:53 -04:00
|
|
|
self.account = account_
|
2016-03-01 17:53:10 -05:00
|
|
|
self.auth = auth
|
2014-12-17 09:27:21 -05:00
|
|
|
self.installer = installer
|
2015-04-06 20:03:07 -04:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
# Initialize ACME if account is provided
|
|
|
|
|
if acme is None and self.account is not None:
|
2015-11-12 22:52:32 -05:00
|
|
|
acme = acme_from_config_key(config, self.account.key)
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
self.acme = acme
|
2014-11-23 13:52:57 -05:00
|
|
|
|
2016-03-01 17:53:10 -05:00
|
|
|
if auth is not None:
|
2015-01-24 05:15:23 -05:00
|
|
|
self.auth_handler = auth_handler.AuthHandler(
|
2016-03-01 17:53:10 -05:00
|
|
|
auth, self.acme, self.account)
|
2015-01-24 05:15:23 -05:00
|
|
|
else:
|
|
|
|
|
self.auth_handler = None
|
2015-01-06 04:57:07 -05:00
|
|
|
|
2016-02-08 22:15:28 -05:00
|
|
|
def obtain_certificate_from_csr(self, domains, csr,
|
2016-03-17 02:30:07 -04:00
|
|
|
typ=OpenSSL.crypto.FILETYPE_ASN1, authzr=None):
|
2015-06-15 06:17:17 -04:00
|
|
|
"""Obtain certificate.
|
2015-04-06 20:03:07 -04:00
|
|
|
|
2015-06-15 06:17:17 -04:00
|
|
|
Internal function with precondition that `domains` are
|
|
|
|
|
consistent with identifiers present in the `csr`.
|
2015-01-30 21:48:14 -05:00
|
|
|
|
2015-06-16 02:26:44 -04:00
|
|
|
:param list domains: Domain names.
|
|
|
|
|
:param .le_util.CSR csr: DER-encoded Certificate Signing
|
|
|
|
|
Request. The key used to generate this CSR can be different
|
|
|
|
|
than `authkey`.
|
2016-03-21 18:38:59 -04:00
|
|
|
:param list authzr: List of
|
|
|
|
|
:class:`acme.messages.AuthorizationResource`
|
2014-12-17 06:02:15 -05:00
|
|
|
|
2015-06-16 02:26:44 -04:00
|
|
|
:returns: `.CertificateResource` and certificate chain (as
|
|
|
|
|
returned by `.fetch_chain`).
|
|
|
|
|
:rtype: tuple
|
2012-11-07 22:13:14 -05:00
|
|
|
|
2014-12-17 09:27:21 -05:00
|
|
|
"""
|
2015-01-24 05:15:23 -05:00
|
|
|
if self.auth_handler is None:
|
2015-04-06 20:03:07 -04:00
|
|
|
msg = ("Unable to obtain certificate because authenticator is "
|
|
|
|
|
"not set.")
|
2015-06-11 09:45:41 -04:00
|
|
|
logger.warning(msg)
|
2015-06-12 10:10:39 -04:00
|
|
|
raise errors.Error(msg)
|
2015-04-17 06:40:22 -04:00
|
|
|
if self.account.regr is None:
|
2015-06-12 10:45:28 -04:00
|
|
|
raise errors.Error("Please register with the ACME server first.")
|
2014-12-17 09:27:21 -05:00
|
|
|
|
2015-06-11 09:45:41 -04:00
|
|
|
logger.debug("CSR: %s, domains: %s", csr, domains)
|
2014-11-07 06:38:48 -05:00
|
|
|
|
2016-03-17 02:30:07 -04:00
|
|
|
if authzr is None:
|
|
|
|
|
authzr = self.auth_handler.get_authorizations(domains)
|
2016-02-12 07:45:19 -05:00
|
|
|
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
certr = self.acme.request_issuance(
|
2016-02-08 22:15:28 -05:00
|
|
|
jose.ComparableX509(
|
|
|
|
|
OpenSSL.crypto.load_certificate_request(typ, csr.data)),
|
2016-02-12 07:45:19 -05:00
|
|
|
authzr)
|
Rewrite acccounts and registration.
Save accounts to:
/etc/letsencrypt/accounts/www.letsencrypt-dmeo.org/acme/new-reg/ \
kuba.le.wtf@2015-07-04T14:04:10Z/ \
{regr.json,meta.json,private_key.json}
Account now represents a combination of private key, Registration
Resource and client account metadata. `Account.id` based on the
account metadata (creation host and datetime). UI interface
(`cli._determine_account`) based on the `id`, and not on email as
previously.
Add `AccountStorage` interface and `AccountFileStorage`,
`AccountMemoryStorage` implementations (latter, in-memory, useful for
testing).
Create Account only after Registration Resource is received
(`register()` returns `Account`).
Allow `client.Client(..., acme=acme, ...)`: API client might reuse
acme.client.Client as returned by `register()`.
Move report_new_account to letsencrypt.account, client.Client.register
into client.register.
Use Registration.from_data acme API.
achallenges.AChallenge.key is now the `acme.jose.JWK`, not
`le_util.Key`. Plugins have to export PEM/DER as necessary
(c.f. `letsencrypt.plugins.common.Dvsni.get_key_path`)
Add --agree-tos, save --agree-eula to "args.eula". Prompt for EULA as
soon as client is launched, add prompt for TOS.
Remove unnecessary letsencrypt.network. Remove, now irrelevant,
`IConfig.account_keys_dir`.
Based on the draft from
https://github.com/letsencrypt/letsencrypt/pull/362#issuecomment-97946817.
2015-07-04 02:46:36 -04:00
|
|
|
return certr, self.acme.fetch_chain(certr)
|
2014-11-07 06:38:48 -05:00
|
|
|
|
2015-06-15 06:17:17 -04:00
|
|
|
def obtain_certificate(self, domains):
|
|
|
|
|
"""Obtains a certificate from the ACME server.
|
|
|
|
|
|
2015-06-16 02:26:44 -04:00
|
|
|
`.register` must be called before `.obtain_certificate`
|
2015-06-15 06:17:17 -04:00
|
|
|
|
2016-02-03 22:48:00 -05:00
|
|
|
:param list domains: domains to get a certificate
|
2015-05-09 23:58:54 -04:00
|
|
|
|
2015-06-16 02:26:44 -04:00
|
|
|
:returns: `.CertificateResource`, certificate chain (as
|
|
|
|
|
returned by `.fetch_chain`), and newly generated private key
|
|
|
|
|
(`.le_util.Key`) and DER-encoded Certificate Signing Request
|
|
|
|
|
(`.le_util.CSR`).
|
|
|
|
|
:rtype: tuple
|
2015-06-15 06:17:17 -04:00
|
|
|
|
|
|
|
|
"""
|
2016-03-17 02:30:07 -04:00
|
|
|
authzr = self.auth_handler.get_authorizations(
|
|
|
|
|
domains,
|
|
|
|
|
self.config.allow_subset_of_names)
|
|
|
|
|
|
2016-03-21 17:43:38 -04:00
|
|
|
domains = [a.body.identifier.value.encode('ascii')
|
|
|
|
|
for a in authzr]
|
2016-02-03 04:54:39 -05:00
|
|
|
|
2015-06-15 06:17:17 -04:00
|
|
|
# Create CSR from names
|
|
|
|
|
key = crypto_util.init_save_key(
|
|
|
|
|
self.config.rsa_key_size, self.config.key_dir)
|
2015-09-26 01:26:32 -04:00
|
|
|
csr = crypto_util.init_save_csr(key, domains, self.config.csr_dir)
|
2015-06-15 06:17:17 -04:00
|
|
|
|
2016-03-17 02:30:07 -04:00
|
|
|
return (self.obtain_certificate_from_csr(domains, csr, authzr=authzr)
|
|
|
|
|
+ (key, csr))
|
2014-11-09 07:30:40 -05:00
|
|
|
|
2015-11-12 22:52:32 -05:00
|
|
|
def obtain_and_enroll_certificate(self, domains):
|
2015-05-28 03:24:18 -04:00
|
|
|
"""Obtain and enroll certificate.
|
|
|
|
|
|
|
|
|
|
Get a new certificate for the specified domains using the specified
|
2015-05-11 18:02:02 -04:00
|
|
|
authenticator and installer, and then create a new renewable lineage
|
2015-05-22 17:29:50 -04:00
|
|
|
containing it.
|
|
|
|
|
|
|
|
|
|
:param list domains: Domains to request.
|
|
|
|
|
:param plugins: A PluginsFactory object.
|
|
|
|
|
|
2015-05-22 17:42:19 -04:00
|
|
|
:returns: A new :class:`letsencrypt.storage.RenewableCert` instance
|
2016-01-28 21:09:59 -05:00
|
|
|
referred to the enrolled cert lineage, False if the cert could not
|
|
|
|
|
be obtained, or None if doing a successful dry run.
|
2015-05-28 03:24:18 -04:00
|
|
|
|
2015-05-22 17:29:50 -04:00
|
|
|
"""
|
2015-06-16 02:26:44 -04:00
|
|
|
certr, chain, key, _ = self.obtain_certificate(domains)
|
2015-06-15 06:17:17 -04:00
|
|
|
|
2016-02-02 21:02:31 -05:00
|
|
|
if (self.config.config_dir != constants.CLI_DEFAULTS["config_dir"] or
|
|
|
|
|
self.config.work_dir != constants.CLI_DEFAULTS["work_dir"]):
|
2015-06-11 09:45:41 -04:00
|
|
|
logger.warning(
|
2015-06-02 08:10:22 -04:00
|
|
|
"Non-standard path(s), might not work with crontab installed "
|
|
|
|
|
"by your operating system package manager")
|
2015-06-15 06:17:17 -04:00
|
|
|
|
2016-02-02 21:02:31 -05:00
|
|
|
if self.config.dry_run:
|
2016-01-29 20:43:21 -05:00
|
|
|
logger.info("Dry run: Skipping creating new lineage for %s",
|
|
|
|
|
domains[0])
|
2016-01-28 21:09:59 -05:00
|
|
|
return None
|
|
|
|
|
else:
|
|
|
|
|
return storage.RenewableCert.new_lineage(
|
|
|
|
|
domains[0], OpenSSL.crypto.dump_certificate(
|
|
|
|
|
OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped),
|
|
|
|
|
key.pem, crypto_util.dump_pyopenssl_chain(chain),
|
2016-02-02 21:02:31 -05:00
|
|
|
configuration.RenewerConfiguration(self.config.namespace))
|
2015-06-02 20:11:00 -04:00
|
|
|
|
2015-10-22 03:35:52 -04:00
|
|
|
def save_certificate(self, certr, chain_cert,
|
|
|
|
|
cert_path, chain_path, fullchain_path):
|
2014-12-17 09:27:21 -05:00
|
|
|
"""Saves the certificate received from the ACME server.
|
2014-11-09 07:30:40 -05:00
|
|
|
|
2015-04-11 02:02:01 -04:00
|
|
|
:param certr: ACME "certificate" resource.
|
2015-05-10 07:26:21 -04:00
|
|
|
:type certr: :class:`acme.messages.Certificate`
|
2015-02-01 18:02:41 -05:00
|
|
|
|
2015-09-10 16:13:30 -04:00
|
|
|
:param list chain_cert:
|
2015-05-22 03:55:22 -04:00
|
|
|
:param str cert_path: Candidate path to a certificate.
|
|
|
|
|
:param str chain_path: Candidate path to a certificate chain.
|
2015-10-22 00:00:30 -04:00
|
|
|
:param str fullchain_path: Candidate path to a full cert chain.
|
2014-11-11 04:42:46 -05:00
|
|
|
|
2015-10-22 03:35:52 -04:00
|
|
|
:returns: cert_path, chain_path, and fullchain_path as absolute
|
|
|
|
|
paths to the actual files
|
2014-12-17 09:27:21 -05:00
|
|
|
:rtype: `tuple` of `str`
|
2014-11-11 04:42:46 -05:00
|
|
|
|
2014-12-17 09:27:21 -05:00
|
|
|
:raises IOError: If unable to find room to write the cert files
|
2014-11-08 06:11:29 -05:00
|
|
|
|
2014-11-23 13:52:57 -05:00
|
|
|
"""
|
2015-10-22 00:00:30 -04:00
|
|
|
for path in cert_path, chain_path, fullchain_path:
|
2015-06-15 06:17:17 -04:00
|
|
|
le_util.make_or_verify_dir(
|
2015-09-16 16:13:24 -04:00
|
|
|
os.path.dirname(path), 0o755, os.geteuid(),
|
|
|
|
|
self.config.strict_permissions)
|
2015-06-15 06:17:17 -04:00
|
|
|
|
2015-12-23 19:09:05 -05:00
|
|
|
cert_pem = OpenSSL.crypto.dump_certificate(
|
|
|
|
|
OpenSSL.crypto.FILETYPE_PEM, certr.body.wrapped)
|
2015-10-22 03:35:52 -04:00
|
|
|
cert_file, act_cert_path = le_util.unique_file(cert_path, 0o644)
|
2015-04-13 20:33:11 -04:00
|
|
|
try:
|
2015-04-30 21:35:49 -04:00
|
|
|
cert_file.write(cert_pem)
|
2015-04-13 20:33:11 -04:00
|
|
|
finally:
|
|
|
|
|
cert_file.close()
|
2015-06-11 09:45:41 -04:00
|
|
|
logger.info("Server issued certificate; certificate written to %s",
|
|
|
|
|
act_cert_path)
|
2014-11-11 04:42:46 -05:00
|
|
|
|
2015-10-22 03:35:52 -04:00
|
|
|
cert_chain_abspath = None
|
|
|
|
|
fullchain_abspath = None
|
2015-09-10 16:13:30 -04:00
|
|
|
if chain_cert:
|
2015-09-10 17:48:23 -04:00
|
|
|
chain_pem = crypto_util.dump_pyopenssl_chain(chain_cert)
|
2015-10-22 03:35:52 -04:00
|
|
|
cert_chain_abspath = _save_chain(chain_pem, chain_path)
|
|
|
|
|
fullchain_abspath = _save_chain(cert_pem + chain_pem,
|
|
|
|
|
fullchain_path)
|
2015-10-22 00:00:30 -04:00
|
|
|
|
|
|
|
|
return os.path.abspath(act_cert_path), cert_chain_abspath, fullchain_abspath
|
2014-12-17 09:27:21 -05:00
|
|
|
|
2015-10-11 13:20:08 -04:00
|
|
|
def deploy_certificate(self, domains, privkey_path,
|
2015-10-16 18:25:20 -04:00
|
|
|
cert_path, chain_path, fullchain_path):
|
2014-12-17 09:27:21 -05:00
|
|
|
"""Install certificate
|
|
|
|
|
|
2015-01-15 04:43:54 -05:00
|
|
|
:param list domains: list of domains to install the certificate
|
2015-05-28 14:07:26 -04:00
|
|
|
:param str privkey_path: path to certificate private key
|
2015-05-28 03:12:19 -04:00
|
|
|
:param str cert_path: certificate file path (optional)
|
|
|
|
|
:param str chain_path: chain file path
|
2015-01-15 04:43:54 -05:00
|
|
|
|
2014-12-17 09:27:21 -05:00
|
|
|
"""
|
2015-01-24 05:15:23 -05:00
|
|
|
if self.installer is None:
|
2015-06-11 09:45:41 -04:00
|
|
|
logger.warning("No installer specified, client is unable to deploy"
|
|
|
|
|
"the certificate")
|
2015-06-12 10:10:39 -04:00
|
|
|
raise errors.Error("No installer available")
|
2015-01-24 05:15:23 -05:00
|
|
|
|
2015-05-28 03:12:19 -04:00
|
|
|
chain_path = None if chain_path is None else os.path.abspath(chain_path)
|
2014-12-17 09:27:21 -05:00
|
|
|
|
2015-09-23 18:02:20 -04:00
|
|
|
with error_handler.ErrorHandler(self.installer.recovery_routine):
|
|
|
|
|
for dom in domains:
|
|
|
|
|
self.installer.deploy_cert(
|
2015-10-11 13:20:08 -04:00
|
|
|
domain=dom, cert_path=os.path.abspath(cert_path),
|
|
|
|
|
key_path=os.path.abspath(privkey_path),
|
|
|
|
|
chain_path=chain_path,
|
|
|
|
|
fullchain_path=fullchain_path)
|
2015-10-30 19:53:04 -04:00
|
|
|
self.installer.save() # needed by the Apache plugin
|
2013-05-15 17:30:00 -04:00
|
|
|
|
2015-09-23 18:02:20 -04:00
|
|
|
self.installer.save("Deployed Let's Encrypt Certificate")
|
2015-11-04 21:32:17 -05:00
|
|
|
|
2015-11-12 16:58:55 -05:00
|
|
|
msg = ("We were unable to install your certificate, "
|
|
|
|
|
"however, we successfully restored your "
|
|
|
|
|
"server to its prior configuration.")
|
|
|
|
|
with error_handler.ErrorHandler(self._rollback_and_restart, msg):
|
|
|
|
|
# sites may have been enabled / final cleanup
|
2015-11-04 21:32:17 -05:00
|
|
|
self.installer.restart()
|
2015-11-17 02:23:19 -05:00
|
|
|
def enhance_config(self, domains, config):
|
2015-01-15 04:43:54 -05:00
|
|
|
"""Enhance the configuration.
|
2014-11-07 06:38:48 -05:00
|
|
|
|
2015-01-15 04:43:54 -05:00
|
|
|
:param list domains: list of domains to configure
|
2014-12-01 06:05:06 -05:00
|
|
|
|
2015-11-16 15:06:16 -05:00
|
|
|
:ivar config: Namespace typically produced by
|
2015-11-11 21:24:57 -05:00
|
|
|
:meth:`argparse.ArgumentParser.parse_args`.
|
2015-11-17 02:23:19 -05:00
|
|
|
it must have the redirect, hsts and uir attributes.
|
2015-11-11 21:24:57 -05:00
|
|
|
:type namespace: :class:`argparse.Namespace`
|
|
|
|
|
|
2015-06-12 10:45:28 -04:00
|
|
|
:raises .errors.Error: if no installer is specified in the
|
|
|
|
|
client.
|
2015-01-24 05:15:23 -05:00
|
|
|
|
2014-12-01 06:05:06 -05:00
|
|
|
"""
|
2015-11-12 00:08:30 -05:00
|
|
|
|
2015-01-24 05:15:23 -05:00
|
|
|
if self.installer is None:
|
2015-06-11 09:45:41 -04:00
|
|
|
logger.warning("No installer is specified, there isn't any "
|
|
|
|
|
"configuration to enhance.")
|
2015-06-12 10:10:39 -04:00
|
|
|
raise errors.Error("No installer available")
|
2015-01-24 05:15:23 -05:00
|
|
|
|
2015-11-16 15:06:16 -05:00
|
|
|
if config is None:
|
2015-11-17 02:23:19 -05:00
|
|
|
logger.warning("No config is specified.")
|
|
|
|
|
raise errors.Error("No config available")
|
|
|
|
|
|
2015-12-16 05:47:45 -05:00
|
|
|
supported = self.installer.supported_enhancements()
|
|
|
|
|
redirect = config.redirect if "redirect" in supported else False
|
|
|
|
|
hsts = config.hsts if "ensure-http-header" in supported else False
|
|
|
|
|
uir = config.uir if "ensure-http-header" in supported else False
|
2015-11-17 02:23:19 -05:00
|
|
|
|
|
|
|
|
if redirect is None:
|
2015-02-09 03:12:43 -05:00
|
|
|
redirect = enhancements.ask("redirect")
|
2015-11-17 02:23:19 -05:00
|
|
|
|
|
|
|
|
if redirect:
|
|
|
|
|
self.apply_enhancement(domains, "redirect")
|
|
|
|
|
|
|
|
|
|
if hsts:
|
2015-11-24 18:33:21 -05:00
|
|
|
self.apply_enhancement(domains, "ensure-http-header",
|
2015-11-17 02:23:19 -05:00
|
|
|
"Strict-Transport-Security")
|
|
|
|
|
if uir:
|
2015-11-24 18:33:21 -05:00
|
|
|
self.apply_enhancement(domains, "ensure-http-header",
|
2015-11-17 02:23:19 -05:00
|
|
|
"Upgrade-Insecure-Requests")
|
2015-11-12 00:08:30 -05:00
|
|
|
|
2015-11-16 15:06:16 -05:00
|
|
|
msg = ("We were unable to restart web server")
|
2015-11-12 00:25:44 -05:00
|
|
|
if redirect or hsts or uir:
|
2015-11-15 02:18:26 -05:00
|
|
|
with error_handler.ErrorHandler(self._rollback_and_restart, msg):
|
|
|
|
|
self.installer.restart()
|
2015-11-12 00:08:30 -05:00
|
|
|
|
2015-11-11 23:49:31 -05:00
|
|
|
def apply_enhancement(self, domains, enhancement, options=None):
|
2015-11-12 00:25:44 -05:00
|
|
|
"""Applies an enhacement on all domains.
|
2014-12-01 06:05:06 -05:00
|
|
|
|
2015-11-11 23:49:31 -05:00
|
|
|
:param domains: list of ssl_vhosts
|
2015-11-12 00:25:44 -05:00
|
|
|
:type list of str
|
2015-11-12 00:20:10 -05:00
|
|
|
|
2015-11-24 18:33:21 -05:00
|
|
|
:param enhancement: name of enhancement, e.g. ensure-http-header
|
2015-11-12 00:20:10 -05:00
|
|
|
:type str
|
|
|
|
|
|
|
|
|
|
.. note:: when more options are need make options a list.
|
|
|
|
|
:param options: options to enhancement, e.g. Strict-Transport-Security
|
|
|
|
|
:type str
|
2014-12-01 06:05:06 -05:00
|
|
|
|
2015-11-23 18:58:58 -05:00
|
|
|
:raises .errors.PluginError: If Enhancement is not supported, or if
|
|
|
|
|
there is any other problem with the enhancement.
|
|
|
|
|
|
2015-11-16 15:41:39 -05:00
|
|
|
|
2014-12-01 06:05:06 -05:00
|
|
|
"""
|
2015-11-16 15:06:16 -05:00
|
|
|
msg = ("We were unable to set up enhancement %s for your server, "
|
|
|
|
|
"however, we successfully installed your certificate."
|
|
|
|
|
% (enhancement))
|
2015-11-12 16:58:55 -05:00
|
|
|
with error_handler.ErrorHandler(self._recovery_routine_with_msg, msg):
|
2015-09-23 18:02:20 -04:00
|
|
|
for dom in domains:
|
2015-09-24 19:23:40 -04:00
|
|
|
try:
|
2015-11-12 00:08:30 -05:00
|
|
|
self.installer.enhance(dom, enhancement, options)
|
2015-11-24 20:56:49 -05:00
|
|
|
except errors.PluginEnhancementAlreadyPresent:
|
|
|
|
|
logger.warn("Enhancement %s was already set.",
|
|
|
|
|
enhancement)
|
2015-09-24 19:23:40 -04:00
|
|
|
except errors.PluginError:
|
2015-11-11 23:49:31 -05:00
|
|
|
logger.warn("Unable to set enhancement %s for %s",
|
|
|
|
|
enhancement, dom)
|
2015-09-24 19:23:40 -04:00
|
|
|
raise
|
2015-01-15 04:43:54 -05:00
|
|
|
|
2015-11-11 23:49:31 -05:00
|
|
|
self.installer.save("Add enhancement %s" % (enhancement))
|
2015-01-15 04:43:54 -05:00
|
|
|
|
2015-11-10 19:59:22 -05:00
|
|
|
def _recovery_routine_with_msg(self, success_msg):
|
|
|
|
|
"""Calls the installer's recovery routine and prints success_msg
|
|
|
|
|
|
|
|
|
|
:param str success_msg: message to show on successful recovery
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
self.installer.recovery_routine()
|
|
|
|
|
reporter = zope.component.getUtility(interfaces.IReporter)
|
|
|
|
|
reporter.add_message(success_msg, reporter.HIGH_PRIORITY)
|
|
|
|
|
|
|
|
|
|
def _rollback_and_restart(self, success_msg):
|
2015-11-10 19:03:18 -05:00
|
|
|
"""Rollback the most recent checkpoint and restart the webserver
|
|
|
|
|
|
2015-11-10 19:59:22 -05:00
|
|
|
:param str success_msg: message to show on successful rollback
|
2015-11-10 19:03:18 -05:00
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
logger.critical("Rolling back to previous server configuration...")
|
|
|
|
|
reporter = zope.component.getUtility(interfaces.IReporter)
|
|
|
|
|
try:
|
|
|
|
|
self.installer.rollback_checkpoints()
|
2015-09-23 18:02:20 -04:00
|
|
|
self.installer.restart()
|
2015-11-10 19:03:18 -05:00
|
|
|
except:
|
|
|
|
|
# TODO: suggest letshelp-letsencypt here
|
|
|
|
|
reporter.add_message(
|
2015-11-18 16:41:39 -05:00
|
|
|
"An error occurred and we failed to restore your config and "
|
2015-11-10 19:03:18 -05:00
|
|
|
"restart your server. Please submit a bug report to "
|
|
|
|
|
"https://github.com/letsencrypt/letsencrypt",
|
|
|
|
|
reporter.HIGH_PRIORITY)
|
|
|
|
|
raise
|
2015-11-10 19:59:22 -05:00
|
|
|
reporter.add_message(success_msg, reporter.HIGH_PRIORITY)
|
2015-01-15 04:43:54 -05:00
|
|
|
|
2014-11-23 13:52:57 -05:00
|
|
|
|
2015-01-15 04:43:54 -05:00
|
|
|
def validate_key_csr(privkey, csr=None):
|
|
|
|
|
"""Validate Key and CSR files.
|
2014-11-23 13:52:57 -05:00
|
|
|
|
2014-12-22 03:29:33 -05:00
|
|
|
Verifies that the client key and csr arguments are valid and correspond to
|
2015-01-15 04:43:54 -05:00
|
|
|
one another. This does not currently check the names in the CSR due to
|
|
|
|
|
the inability to read SANs from CSRs in python crypto libraries.
|
|
|
|
|
|
|
|
|
|
If csr is left as None, only the key will be validated.
|
2014-11-23 13:52:57 -05:00
|
|
|
|
2014-12-22 03:29:33 -05:00
|
|
|
:param privkey: Key associated with CSR
|
2015-05-10 08:25:29 -04:00
|
|
|
:type privkey: :class:`letsencrypt.le_util.Key`
|
2014-11-24 07:45:15 -05:00
|
|
|
|
2015-06-15 06:17:17 -04:00
|
|
|
:param .le_util.CSR csr: CSR
|
2014-11-30 05:31:44 -05:00
|
|
|
|
2015-06-12 10:45:28 -04:00
|
|
|
:raises .errors.Error: when validation fails
|
2013-05-15 17:30:00 -04:00
|
|
|
|
2014-12-17 09:27:21 -05:00
|
|
|
"""
|
|
|
|
|
# TODO: Handle all of these problems appropriately
|
|
|
|
|
# The client can eventually do things like prompt the user
|
|
|
|
|
# and allow the user to take more appropriate actions
|
|
|
|
|
|
2015-01-15 04:43:54 -05:00
|
|
|
# Key must be readable and valid.
|
2014-12-17 09:27:21 -05:00
|
|
|
if privkey.pem and not crypto_util.valid_privkey(privkey.pem):
|
2015-06-12 10:45:28 -04:00
|
|
|
raise errors.Error("The provided key is not a valid key")
|
2014-12-17 09:27:21 -05:00
|
|
|
|
2015-01-15 04:43:54 -05:00
|
|
|
if csr:
|
|
|
|
|
if csr.form == "der":
|
2015-07-05 18:43:47 -04:00
|
|
|
csr_obj = OpenSSL.crypto.load_certificate_request(
|
|
|
|
|
OpenSSL.crypto.FILETYPE_ASN1, csr.data)
|
|
|
|
|
csr = le_util.CSR(csr.file, OpenSSL.crypto.dump_certificate(
|
|
|
|
|
OpenSSL.crypto.FILETYPE_PEM, csr_obj), "pem")
|
2015-01-15 04:43:54 -05:00
|
|
|
|
|
|
|
|
# If CSR is provided, it must be readable and valid.
|
|
|
|
|
if csr.data and not crypto_util.valid_csr(csr.data):
|
2015-06-12 10:45:28 -04:00
|
|
|
raise errors.Error("The provided CSR is not a valid CSR")
|
2015-01-15 04:43:54 -05:00
|
|
|
|
|
|
|
|
# If both CSR and key are provided, the key must be the same key used
|
|
|
|
|
# in the CSR.
|
|
|
|
|
if csr.data and privkey.pem:
|
|
|
|
|
if not crypto_util.csr_matches_pubkey(
|
|
|
|
|
csr.data, privkey.pem):
|
2015-06-12 10:45:28 -04:00
|
|
|
raise errors.Error("The key and CSR do not match")
|
2013-05-15 17:30:00 -04:00
|
|
|
|
|
|
|
|
|
2015-05-02 09:14:03 -04:00
|
|
|
def rollback(default_installer, checkpoints, config, plugins):
|
2015-01-25 07:24:05 -05:00
|
|
|
"""Revert configuration the specified number of checkpoints.
|
|
|
|
|
|
|
|
|
|
:param int checkpoints: Number of checkpoints to revert.
|
|
|
|
|
|
2015-01-30 21:48:14 -05:00
|
|
|
:param config: Configuration.
|
2015-05-10 08:25:29 -04:00
|
|
|
:type config: :class:`letsencrypt.interfaces.IConfig`
|
2015-01-30 21:48:14 -05:00
|
|
|
|
2015-01-25 07:24:05 -05:00
|
|
|
"""
|
|
|
|
|
# Misconfigurations are only a slight problems... allow the user to rollback
|
2016-03-11 18:24:57 -05:00
|
|
|
installer = plugin_selection.pick_installer(
|
2015-05-02 09:14:03 -04:00
|
|
|
config, default_installer, plugins, question="Which installer "
|
|
|
|
|
"should be used for rollback?")
|
2015-01-25 07:24:05 -05:00
|
|
|
|
|
|
|
|
# No Errors occurred during init... proceed normally
|
|
|
|
|
# If installer is None... couldn't find an installer... there shouldn't be
|
|
|
|
|
# anything to rollback
|
|
|
|
|
if installer is not None:
|
|
|
|
|
installer.rollback_checkpoints(checkpoints)
|
|
|
|
|
installer.restart()
|
|
|
|
|
|
|
|
|
|
|
2016-02-17 21:34:37 -05:00
|
|
|
def view_config_changes(config, num=None):
|
2015-01-25 07:24:05 -05:00
|
|
|
"""View checkpoints and associated configuration changes.
|
|
|
|
|
|
|
|
|
|
.. note:: This assumes that the installation is using a Reverter object.
|
|
|
|
|
|
2015-01-30 21:48:14 -05:00
|
|
|
:param config: Configuration.
|
2015-05-10 08:25:29 -04:00
|
|
|
:type config: :class:`letsencrypt.interfaces.IConfig`
|
2015-01-30 21:48:14 -05:00
|
|
|
|
2015-01-25 07:24:05 -05:00
|
|
|
"""
|
2015-01-30 21:48:14 -05:00
|
|
|
rev = reverter.Reverter(config)
|
2015-01-25 07:24:05 -05:00
|
|
|
rev.recovery_routine()
|
2016-02-17 21:34:37 -05:00
|
|
|
rev.view_config_changes(num)
|
2015-10-22 03:35:52 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def _save_chain(chain_pem, chain_path):
|
|
|
|
|
"""Saves chain_pem at a unique path based on chain_path.
|
|
|
|
|
|
|
|
|
|
:param str chain_pem: certificate chain in PEM format
|
|
|
|
|
:param str chain_path: candidate path for the cert chain
|
|
|
|
|
|
|
|
|
|
:returns: absolute path to saved cert chain
|
|
|
|
|
:rtype: str
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
chain_file, act_chain_path = le_util.unique_file(chain_path, 0o644)
|
|
|
|
|
try:
|
|
|
|
|
chain_file.write(chain_pem)
|
|
|
|
|
finally:
|
|
|
|
|
chain_file.close()
|
|
|
|
|
|
|
|
|
|
logger.info("Cert chain written to %s", act_chain_path)
|
|
|
|
|
|
|
|
|
|
# This expects a valid chain file
|
|
|
|
|
return os.path.abspath(act_chain_path)
|