Compare commits
18 Commits
test-pytho
...
handle_key
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c71f383502 | ||
|
|
198f5a99bc | ||
|
|
47c1045f6d | ||
|
|
e570e8ad32 | ||
|
|
df138d0027 | ||
|
|
9567352002 | ||
|
|
6c7b99f7e0 | ||
|
|
3673ca77a5 | ||
|
|
bb45c9aa41 | ||
|
|
4c347f5576 | ||
|
|
bf07ec20b0 | ||
|
|
fc864543a7 | ||
|
|
4fa1df3075 | ||
|
|
cfd0a6ff1f | ||
|
|
00ed56afd6 | ||
|
|
b6e3a3ad02 | ||
|
|
c250957ab0 | ||
|
|
4eb0b560c5 |
@@ -31,6 +31,25 @@ jobs:
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
artifact: docker_$(DOCKER_ARCH)
|
||||
displayName: Store Docker artifact
|
||||
- job: docker_run
|
||||
dependsOn: docker_build
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: docker_amd64
|
||||
path: $(Build.SourcesDirectory)
|
||||
displayName: Retrieve Docker images
|
||||
- bash: set -e && docker load --input $(Build.SourcesDirectory)/images.tar
|
||||
displayName: Load Docker images
|
||||
- bash: |
|
||||
set -ex
|
||||
DOCKER_IMAGES=$(docker images --filter reference='*/certbot' --filter reference='*/dns-*' --format '{{.Repository}}:{{.Tag}}')
|
||||
for DOCKER_IMAGE in ${DOCKER_IMAGES}
|
||||
do docker run --rm "${DOCKER_IMAGE}" plugins --prepare
|
||||
done
|
||||
displayName: Run integration tests for Docker images
|
||||
- job: installer_build
|
||||
pool:
|
||||
vmImage: vs2017-win2016
|
||||
@@ -84,7 +103,7 @@ jobs:
|
||||
# a recent version of pip, but we also to disable the isolated feature as described in
|
||||
# https://github.com/certbot/certbot/issues/8256
|
||||
- script: |
|
||||
py -3 -m venv venv
|
||||
python -m venv venv
|
||||
venv\Scripts\python -m pip install pip==20.2.3 setuptools==50.3.0 wheel==0.35.1
|
||||
venv\Scripts\python tools\pip_install.py -e certbot-ci
|
||||
env:
|
||||
|
||||
12
.envrc
Normal file
12
.envrc
Normal file
@@ -0,0 +1,12 @@
|
||||
# This file is just a nicety for developers who use direnv. When you cd under
|
||||
# the Certbot repo, Certbot's virtual environment will be automatically
|
||||
# activated and then deactivated when you cd elsewhere. Developers have to have
|
||||
# direnv set up and run `direnv allow` to allow this file to execute on their
|
||||
# system. You can find more information at https://direnv.net/.
|
||||
. venv3/bin/activate
|
||||
# direnv doesn't support modifying PS1 so we unset it to squelch the error
|
||||
# it'll otherwise print about this being done in the activate script. See
|
||||
# https://github.com/direnv/direnv/wiki/PS1. If you would like your shell
|
||||
# prompt to change like it normally does, see
|
||||
# https://github.com/direnv/direnv/wiki/Python#restoring-the-ps1.
|
||||
unset PS1
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -64,3 +64,4 @@ certbot-dns*/certbot-dns*_amd64*.txt
|
||||
certbot-dns*/certbot-dns*_arm*.txt
|
||||
/certbot_amd64*.txt
|
||||
/certbot_arm*.txt
|
||||
certbot-dns*/snap
|
||||
|
||||
@@ -154,6 +154,7 @@ Authors
|
||||
* [Luca Olivetti](https://github.com/olivluca)
|
||||
* [Luke Rogers](https://github.com/lukeroge)
|
||||
* [Maarten](https://github.com/mrtndwrd)
|
||||
* [Mads Jensen](https://github.com/atombrella)
|
||||
* [Maikel Martens](https://github.com/krukas)
|
||||
* [Malte Janduda](https://github.com/MalteJ)
|
||||
* [Mantas Mikulėnas](https://github.com/grawity)
|
||||
@@ -213,6 +214,7 @@ Authors
|
||||
* [Richard Barnes](https://github.com/r-barnes)
|
||||
* [Richard Panek](https://github.com/kernelpanek)
|
||||
* [Robert Buchholz](https://github.com/rbu)
|
||||
* [Robert Dailey](https://github.com/pahrohfit)
|
||||
* [Robert Habermann](https://github.com/frennkie)
|
||||
* [Robert Xiao](https://github.com/nneonneo)
|
||||
* [Roland Shoemaker](https://github.com/rolandshoemaker)
|
||||
|
||||
@@ -52,7 +52,7 @@ function Cleanup() {
|
||||
# if our environment asks us to enable modules, do our best!
|
||||
if [ "$1" = --debian-modules ] ; then
|
||||
sudo apt-get install -y apache2
|
||||
sudo apt-get install -y libapache2-mod-wsgi
|
||||
sudo apt-get install -y libapache2-mod-wsgi-py3
|
||||
sudo apt-get install -y libapache2-mod-macro
|
||||
|
||||
for mod in ssl rewrite macro wsgi deflate userdir version mime setenvif ; do
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
This directory contains your keys and certificates.
|
||||
|
||||
`privkey.pem` : the private key for your certificate.
|
||||
`fullchain.pem`: the certificate file used in most server software.
|
||||
`chain.pem` : used for OCSP stapling in Nginx >=1.3.7.
|
||||
`cert.pem` : will break many server configurations, and should not be used
|
||||
without reading further documentation (see link below).
|
||||
|
||||
WARNING: DO NOT MOVE OR RENAME THESE FILES!
|
||||
Certbot expects these files to remain in this location in order
|
||||
to function properly!
|
||||
|
||||
We recommend not moving these files. For more information, see the Certbot
|
||||
User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates.
|
||||
@@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC2zCCAcOgAwIBAgIIBvrEnbPRYu8wDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE
|
||||
AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxMjZjNGIwHhcNMjAxMDEyMjEwNzQw
|
||||
WhcNMjUxMDEyMjEwNzQwWjAjMSEwHwYDVQQDExhjLmVuY3J5cHRpb24tZXhhbXBs
|
||||
ZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARjMhuW0ENPPC33PjB5XsYU
|
||||
CRw640kPQENIDatcTJaENZIZdqKd6rI6jc+lpbmXot7Zi52clJlSJS+V6oDAt2Lh
|
||||
o4HYMIHVMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
|
||||
BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUj7Kd3ENqxlPf8B2bIGhsjydX
|
||||
mPswHwYDVR0jBBgwFoAUEiGxlkRsi+VvcogH5dVD3h1laAcwMQYIKwYBBQUHAQEE
|
||||
JTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAuMC4xOjQwMDIwIwYDVR0RBBww
|
||||
GoIYYy5lbmNyeXB0aW9uLWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQCl
|
||||
k0JXsa8y7fg41WWMDhw60bPW77O0FtOmTcnhdI5daYNemQVk+Q5EMaBLQ/oGjgXd
|
||||
9QXFzXH1PL904YEnSLt+iTpXn++7rQSNzQsdYqw0neWk4f5pEBiN+WORpb6mwobV
|
||||
ifMtBOkNEHvrJ2Pkci9U1lLwtKD/DSew6QtJU5DSkmH1XdGuMJiubygEIvELtvgq
|
||||
cP9S368ZvPmPGmKaJQXBiuaR8MTjY/Bkr79aXQMjKbf+mpn7h0POCcePk1DY/rm6
|
||||
Da+X16lf0hHyQhSUa7Vgyim6rK1/hlw+Z00i+sQCKD9Ih7kXuuGqfSDC33cfO8Tj
|
||||
o/MXO8lcxkrem5zU5QWP
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDUDCCAjigAwIBAgIIbi787yVrcMAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
|
||||
AxMVUGViYmxlIFJvb3QgQ0EgMGM1MjI1MCAXDTIwMTAxMjIwMjI0NloYDzIwNTAx
|
||||
MDEyMjEyMjQ2WjAoMSYwJAYDVQQDEx1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDEy
|
||||
NmM0YjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGeVk1BMJraeqRq
|
||||
mJ2+hgso8VOAv2s2CVxUJjIVcn7f2adE8NyTsSQ1brlsnKCUYUw7yLTQH0izLQRB
|
||||
qKVIDFkUqo5/FuTJ2QlfA2EwBL8J7s/7L7vj3L0DiVpwgxPSyFEwdl/Y5y7ofsX5
|
||||
CIhCFcaMAmTIuKLiSfCJjGwkbEMuolm+lO8Mikxxc/JtDVUC479ugU7PU9O09bMH
|
||||
nm+sD6Bgd+KMoPkCCCoeShJS9X3Ziq9HGc7Z6nhM/zirFARt2XkonEdAZ8br01zY
|
||||
MRiY9txhlWQ7mUkOtzOSoEuYJNoUbvMUf0+tNzto26WRyF7dJmh7lTBsYrvAwUTx
|
||||
PzNyst0CAwEAAaOBgzCBgDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBIhsZZE
|
||||
bIvlb3KIB+XVQ94dZWgHMB8GA1UdIwQYMBaAFOaKTaXg37vKgRt7d79YOjAoAtJT
|
||||
MA0GCSqGSIb3DQEBCwUAA4IBAQAU2mZii7PH2pkw2lNM0QqPbcW/UYyvFoUeM8Aq
|
||||
uCtsI2s+oxCJTqzfLsA0N8NY4nHLQ5wAlNJfJekngni8hbmJTKU4JFTMe7kLQO8P
|
||||
fJbk0pTzhhHVQw7CVwB6Pwq3u2m/JV+d6xDIDc+AVkuEl19ZJU0rTWyooClfFLZV
|
||||
EdZmEiUtA3PGlxoYwYhoGHYlhFxsoFONhCsBEdN7k7FKtFGVxN7oc5SKmKp0YZTW
|
||||
fcrEtrdNThATO4ymhCC2zh33NI/MT1O74fpaAc2k6LcTl57MKiLfTYX4LTL6v9JG
|
||||
9tlNqjFVRRmzEbtXTPcCb+w9g1VqoOGok7mGXYLTYtShCuvE
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,38 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC2zCCAcOgAwIBAgIILlmGtZhUFEwwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE
|
||||
AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxMjZjNGIwHhcNMjAxMDEyMjA1MDM0
|
||||
WhcNMjUxMDEyMjA1MDM0WjAjMSEwHwYDVQQDExhjLmVuY3J5cHRpb24tZXhhbXBs
|
||||
ZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARHEzR8JPWrEmpmgM+F2bk5
|
||||
9mT0u6CjzmJG0QpbaqprLiG5NGpW84VQ5TFCrmC4KxYfigCfMhfHRNfFYvNUK3V/
|
||||
o4HYMIHVMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
|
||||
BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU1CsVL+bPnzaxxQ5jUENmQJIO
|
||||
lKwwHwYDVR0jBBgwFoAUEiGxlkRsi+VvcogH5dVD3h1laAcwMQYIKwYBBQUHAQEE
|
||||
JTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAuMC4xOjQwMDIwIwYDVR0RBBww
|
||||
GoIYYy5lbmNyeXB0aW9uLWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBn
|
||||
2D8loC7pfk28JYpFLr5lmFKJWWmtLGlpsWDj61fVjtTfGKLziJz+MM6il4Y3hIz5
|
||||
58qiFK0ue0M63dIBJ33N+XxSEXon4Q0gy/zRWfH9jtPJ3FwfjkU/RT9PAUClYi0G
|
||||
ptNWnTmgQkNzousbcAtRNXuuShH3856vhUnwkX+xM+cbIDi1JVmFjcGrEEQJ0rUF
|
||||
mv2ZTyfbWbUs3v4rReETi2NVzr1Ql6J+ByNcMvHODzFy3t0L6yelAw2ca1I+c9HU
|
||||
+Z0tnp/ykR7eXNuVLivok8UBf5OC413lh8ZO5g+Bgzh/LdtkUuavg1MYtEX0H6mX
|
||||
9U7y3nVI8WEbPGf+HDeu
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDUDCCAjigAwIBAgIIbi787yVrcMAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
|
||||
AxMVUGViYmxlIFJvb3QgQ0EgMGM1MjI1MCAXDTIwMTAxMjIwMjI0NloYDzIwNTAx
|
||||
MDEyMjEyMjQ2WjAoMSYwJAYDVQQDEx1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDEy
|
||||
NmM0YjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGeVk1BMJraeqRq
|
||||
mJ2+hgso8VOAv2s2CVxUJjIVcn7f2adE8NyTsSQ1brlsnKCUYUw7yLTQH0izLQRB
|
||||
qKVIDFkUqo5/FuTJ2QlfA2EwBL8J7s/7L7vj3L0DiVpwgxPSyFEwdl/Y5y7ofsX5
|
||||
CIhCFcaMAmTIuKLiSfCJjGwkbEMuolm+lO8Mikxxc/JtDVUC479ugU7PU9O09bMH
|
||||
nm+sD6Bgd+KMoPkCCCoeShJS9X3Ziq9HGc7Z6nhM/zirFARt2XkonEdAZ8br01zY
|
||||
MRiY9txhlWQ7mUkOtzOSoEuYJNoUbvMUf0+tNzto26WRyF7dJmh7lTBsYrvAwUTx
|
||||
PzNyst0CAwEAAaOBgzCBgDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBIhsZZE
|
||||
bIvlb3KIB+XVQ94dZWgHMB8GA1UdIwQYMBaAFOaKTaXg37vKgRt7d79YOjAoAtJT
|
||||
MA0GCSqGSIb3DQEBCwUAA4IBAQAU2mZii7PH2pkw2lNM0QqPbcW/UYyvFoUeM8Aq
|
||||
uCtsI2s+oxCJTqzfLsA0N8NY4nHLQ5wAlNJfJekngni8hbmJTKU4JFTMe7kLQO8P
|
||||
fJbk0pTzhhHVQw7CVwB6Pwq3u2m/JV+d6xDIDc+AVkuEl19ZJU0rTWyooClfFLZV
|
||||
EdZmEiUtA3PGlxoYwYhoGHYlhFxsoFONhCsBEdN7k7FKtFGVxN7oc5SKmKp0YZTW
|
||||
fcrEtrdNThATO4ymhCC2zh33NI/MT1O74fpaAc2k6LcTl57MKiLfTYX4LTL6v9JG
|
||||
9tlNqjFVRRmzEbtXTPcCb+w9g1VqoOGok7mGXYLTYtShCuvE
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNgefv2dad4U1VYEi
|
||||
0WkdHuqywi5QXAe30OwNTTGjhbihRANCAARHEzR8JPWrEmpmgM+F2bk59mT0u6Cj
|
||||
zmJG0QpbaqprLiG5NGpW84VQ5TFCrmC4KxYfigCfMhfHRNfFYvNUK3V/
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -0,0 +1,14 @@
|
||||
This directory contains your keys and certificates.
|
||||
|
||||
`privkey.pem` : the private key for your certificate.
|
||||
`fullchain.pem`: the certificate file used in most server software.
|
||||
`chain.pem` : used for OCSP stapling in Nginx >=1.3.7.
|
||||
`cert.pem` : will break many server configurations, and should not be used
|
||||
without reading further documentation (see link below).
|
||||
|
||||
WARNING: DO NOT MOVE OR RENAME THESE FILES!
|
||||
Certbot expects these files to remain in this location in order
|
||||
to function properly!
|
||||
|
||||
We recommend not moving these files. For more information, see the Certbot
|
||||
User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates.
|
||||
@@ -0,0 +1 @@
|
||||
../../archive/c.encryption-example.com/cert.pem
|
||||
@@ -0,0 +1 @@
|
||||
../../archive/c.encryption-example.com/chain.pem
|
||||
@@ -0,0 +1 @@
|
||||
../../archive/c.encryption-example.com/fullchain.pem
|
||||
@@ -0,0 +1 @@
|
||||
../../archive/c.encryption-example.com/privkey.pem
|
||||
@@ -0,0 +1,17 @@
|
||||
# renew_before_expiry = 30 days
|
||||
version = 1.10.0.dev0
|
||||
archive_dir = sample-config/archive/c.encryption-example.com
|
||||
cert = sample-config/live/c.encryption-example.com/cert.pem
|
||||
privkey = sample-config/live/c.encryption-example.com/privkey.pem
|
||||
chain = sample-config/live/c.encryption-example.com/chain.pem
|
||||
fullchain = sample-config/live/c.encryption-example.com/fullchain.pem
|
||||
|
||||
# Options used in the renewal process
|
||||
[renewalparams]
|
||||
authenticator = apache
|
||||
installer = apache
|
||||
account = 48d6b9e8d767eccf7e4d877d6ffa81e3
|
||||
key_type = ecdsa
|
||||
config_dir = sample-config-ec
|
||||
elliptic_curve = secp256r1
|
||||
manual_public_ip_logging_ok = True
|
||||
@@ -2,6 +2,10 @@
|
||||
import io
|
||||
import os
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey
|
||||
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||
|
||||
try:
|
||||
import grp
|
||||
POSIX_MODE = True
|
||||
@@ -16,6 +20,16 @@ SYSTEM_SID = 'S-1-5-18'
|
||||
ADMINS_SID = 'S-1-5-32-544'
|
||||
|
||||
|
||||
def assert_elliptic_key(key, curve):
|
||||
with open(key, 'rb') as file:
|
||||
privkey1 = file.read()
|
||||
|
||||
key = load_pem_private_key(data=privkey1, password=None, backend=default_backend())
|
||||
|
||||
assert isinstance(key, EllipticCurvePrivateKey)
|
||||
assert isinstance(key.curve, curve)
|
||||
|
||||
|
||||
def assert_hook_execution(probe_path, probe_content):
|
||||
"""
|
||||
Assert that a certbot hook has been executed
|
||||
|
||||
@@ -9,12 +9,17 @@ import shutil
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1, SECP384R1
|
||||
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
|
||||
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||
from cryptography.x509 import NameOID
|
||||
|
||||
import pytest
|
||||
|
||||
from certbot_integration_tests.certbot_tests import context as certbot_context
|
||||
from certbot_integration_tests.certbot_tests.assertions import assert_cert_count_for_lineage
|
||||
from certbot_integration_tests.certbot_tests.assertions import assert_elliptic_key
|
||||
from certbot_integration_tests.certbot_tests.assertions import assert_equals_group_owner
|
||||
from certbot_integration_tests.certbot_tests.assertions import assert_equals_group_permissions
|
||||
from certbot_integration_tests.certbot_tests.assertions import assert_equals_world_read_permissions
|
||||
@@ -289,7 +294,7 @@ def test_renew_with_changed_private_key_complexity(context):
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||
|
||||
context.certbot(['renew'])
|
||||
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
||||
key2 = join(context.config_dir, 'archive', certname, 'privkey2.pem')
|
||||
assert os.stat(key2).st_size > 3000
|
||||
@@ -421,20 +426,90 @@ def test_reuse_key(context):
|
||||
assert len({cert1, cert2, cert3}) == 3
|
||||
|
||||
|
||||
def test_incorrect_key_type(context):
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
context.certbot(['--key-type="failwhale"'])
|
||||
|
||||
|
||||
def test_ecdsa(context):
|
||||
"""Test certificate issuance with ECDSA key."""
|
||||
"""Test issuance for ECDSA CSR based request (legacy supported mode)."""
|
||||
key_path = join(context.workspace, 'privkey-p384.pem')
|
||||
csr_path = join(context.workspace, 'csr-p384.der')
|
||||
cert_path = join(context.workspace, 'cert-p384.pem')
|
||||
chain_path = join(context.workspace, 'chain-p384.pem')
|
||||
|
||||
misc.generate_csr([context.get_domain('ecdsa')], key_path, csr_path, key_type=misc.ECDSA_KEY_TYPE)
|
||||
context.certbot(['auth', '--csr', csr_path, '--cert-path', cert_path, '--chain-path', chain_path])
|
||||
misc.generate_csr(
|
||||
[context.get_domain('ecdsa')],
|
||||
key_path, csr_path,
|
||||
key_type=misc.ECDSA_KEY_TYPE
|
||||
)
|
||||
context.certbot([
|
||||
'auth', '--csr', csr_path, '--cert-path', cert_path,
|
||||
'--chain-path', chain_path,
|
||||
])
|
||||
|
||||
certificate = misc.read_certificate(cert_path)
|
||||
assert 'ASN1 OID: secp384r1' in certificate
|
||||
|
||||
|
||||
def test_default_key_type(context):
|
||||
"""Test default key type is RSA"""
|
||||
certname = context.get_domain('renew')
|
||||
context.certbot([
|
||||
'certonly',
|
||||
'--cert-name', certname, '-d', certname
|
||||
])
|
||||
filename = join(context.config_dir, 'archive/{0}/privkey1.pem').format(certname)
|
||||
with open(filename, 'rb') as file:
|
||||
privkey1 = file.read()
|
||||
|
||||
key = load_pem_private_key(data=privkey1, password=None, backend=default_backend())
|
||||
assert isinstance(key, RSAPrivateKey)
|
||||
|
||||
|
||||
def test_default_curve_type(context):
|
||||
"""test that the curve used when not specifying any is secp256r1"""
|
||||
certname = context.get_domain('renew')
|
||||
context.certbot([
|
||||
'--key-type', 'ecdsa', '--cert-name', certname, '-d', certname
|
||||
])
|
||||
key1 = join(context.config_dir, 'archive/{0}/privkey1.pem'.format(certname))
|
||||
assert_elliptic_key(key1, SECP256R1)
|
||||
|
||||
|
||||
def test_renew_with_ec_keys(context):
|
||||
"""Test proper renew with updated private key complexity."""
|
||||
certname = context.get_domain('renew')
|
||||
context.certbot([
|
||||
'certonly',
|
||||
'--cert-name', certname,
|
||||
'--key-type', 'ecdsa', '--elliptic-curve', 'secp256r1',
|
||||
'--force-renewal', '-d', certname,
|
||||
])
|
||||
|
||||
key1 = join(context.config_dir, "archive", certname, 'privkey1.pem')
|
||||
assert 200 < os.stat(key1).st_size < 250 # ec keys of 256 bits are ~225 bytes
|
||||
assert_elliptic_key(key1, SECP256R1)
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||
|
||||
context.certbot(['renew', '--elliptic-curve', 'secp384r1'])
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
||||
key2 = join(context.config_dir, 'archive', certname, 'privkey2.pem')
|
||||
assert_elliptic_key(key2, SECP384R1)
|
||||
assert 280 < os.stat(key2).st_size < 320 # ec keys of 384 bits are ~310 bytes
|
||||
|
||||
# We expect here that the command will fail because without --key-type specified,
|
||||
# Certbot must errored out to prevent changing an existing certificate key type,
|
||||
# without explicit user consent (by specifying both --cert-name and --key-type).
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
context.certbot([
|
||||
'certonly',
|
||||
'--force-renewal',
|
||||
'-d', certname
|
||||
])
|
||||
|
||||
|
||||
def test_ocsp_must_staple(context):
|
||||
"""Test that OCSP Must-Staple is correctly set in the generated certificate."""
|
||||
if context.acme_server == 'pebble':
|
||||
@@ -657,4 +732,4 @@ def test_preferred_chain(context):
|
||||
|
||||
with open(conf_path, 'r') as f:
|
||||
assert 'preferred_chain = {}'.format(requested) in f.read(), \
|
||||
'Expected preferred_chain to be set in renewal config'
|
||||
'Expected preferred_chain to be set in renewal config'
|
||||
|
||||
@@ -92,7 +92,6 @@ def _prepare_args_env(certbot_args, directory_url, http_01_port, tls_alpn_01_por
|
||||
'--no-verify-ssl',
|
||||
'--http-01-port', str(http_01_port),
|
||||
'--https-port', str(tls_alpn_01_port),
|
||||
'--manual-public-ip-logging-ok',
|
||||
'--config-dir', config_dir,
|
||||
'--work-dir', os.path.join(workspace, 'work'),
|
||||
'--logs-dir', os.path.join(workspace, 'logs'),
|
||||
|
||||
@@ -280,7 +280,11 @@ def load_sample_data_path(workspace):
|
||||
|
||||
if os.name == 'nt':
|
||||
# Fix the symlinks on Windows if GIT is not configured to create them upon checkout
|
||||
for lineage in ['a.encryption-example.com', 'b.encryption-example.com']:
|
||||
for lineage in [
|
||||
'a.encryption-example.com',
|
||||
'b.encryption-example.com',
|
||||
'c.encryption-example.com',
|
||||
]:
|
||||
current_live = os.path.join(copied, 'live', lineage)
|
||||
for name in os.listdir(current_live):
|
||||
if name != 'README':
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-cloudflare
|
||||
summary: Cloudflare DNS Authenticator plugin for Certbot
|
||||
description: Cloudflare DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-cloudflare
|
||||
|
||||
parts:
|
||||
certbot-dns-cloudflare:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-cloudxns
|
||||
summary: CloudXNS DNS Authenticator plugin for Certbot
|
||||
description: CloudXNS DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-cloudxns
|
||||
|
||||
parts:
|
||||
certbot-dns-cloudxns:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-digitalocean
|
||||
summary: DigitalOcean DNS Authenticator plugin for Certbot
|
||||
description: DigitalOcean DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-digitalocean
|
||||
|
||||
parts:
|
||||
certbot-dns-digitalocean:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-dnsimple
|
||||
summary: DNSimple DNS Authenticator plugin for Certbot
|
||||
description: DNSimple DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-dnsimple
|
||||
|
||||
parts:
|
||||
certbot-dns-dnsimple:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-dnsmadeeasy
|
||||
summary: DNS Made Easy DNS Authenticator plugin for Certbot
|
||||
description: DNS Made Easy DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-dnsmadeeasy
|
||||
|
||||
parts:
|
||||
certbot-dns-dnsmadeeasy:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-gehirn
|
||||
summary: Gehirn Infrastructure Service DNS Authenticator plugin for Certbot
|
||||
description: Gehirn Infrastructure Service DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-gehirn
|
||||
|
||||
parts:
|
||||
certbot-dns-gehirn:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-google
|
||||
summary: Google Cloud DNS Authenticator plugin for Certbot
|
||||
description: Google Cloud DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-google
|
||||
|
||||
parts:
|
||||
certbot-dns-google:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-linode
|
||||
summary: Linode DNS Authenticator plugin for Certbot
|
||||
description: Linode DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-linode
|
||||
|
||||
parts:
|
||||
certbot-dns-linode:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-luadns
|
||||
summary: LuaDNS Authenticator plugin for Certbot
|
||||
description: LuaDNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-luadns
|
||||
|
||||
parts:
|
||||
certbot-dns-luadns:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-nsone
|
||||
summary: NS1 DNS Authenticator plugin for Certbot
|
||||
description: NS1 DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-nsone
|
||||
|
||||
parts:
|
||||
certbot-dns-nsone:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-ovh
|
||||
summary: OVH DNS Authenticator plugin for Certbot
|
||||
description: OVH DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-ovh
|
||||
|
||||
parts:
|
||||
certbot-dns-ovh:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-rfc2136
|
||||
summary: RFC 2136 DNS Authenticator plugin for Certbot
|
||||
description: RFC 2136 DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-rfc2136
|
||||
|
||||
parts:
|
||||
certbot-dns-rfc2136:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-route53
|
||||
summary: Route53 DNS Authenticator plugin for Certbot
|
||||
description: Route53 DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-route53
|
||||
|
||||
parts:
|
||||
certbot-dns-route53:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog"
|
||||
exit 0
|
||||
fi
|
||||
cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt)
|
||||
|
||||
# get required certbot version for plugin. certbot version must be at least the plugin's
|
||||
# version. note that this is not the required version in setup.py, but the version number itself.
|
||||
cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py)
|
||||
|
||||
|
||||
$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$?
|
||||
if [ "$exit_code" -eq 1 ]; then
|
||||
echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \
|
||||
"this plugin can be updated; will try again on next refresh."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
name: certbot-dns-sakuracloud
|
||||
summary: Sakura Cloud DNS Authenticator plugin for Certbot
|
||||
description: Sakura Cloud DNS Authenticator plugin for Certbot
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core20
|
||||
adopt-info: certbot-dns-sakuracloud
|
||||
|
||||
parts:
|
||||
certbot-dns-sakuracloud:
|
||||
plugin: python
|
||||
source: .
|
||||
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
|
||||
build-environment:
|
||||
- SNAP_BUILD: "True"
|
||||
# To build cryptography and cffi if needed
|
||||
build-packages: [gcc, libffi-dev, libssl-dev, python3-dev]
|
||||
certbot-metadata:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage: [setup.py, certbot-shared]
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared
|
||||
|
||||
slots:
|
||||
certbot:
|
||||
interface: content
|
||||
content: certbot-1
|
||||
read:
|
||||
- $SNAP/lib/python3.8/site-packages
|
||||
|
||||
plugs:
|
||||
certbot-metadata:
|
||||
interface: content
|
||||
content: metadata-1
|
||||
target: $SNAP/certbot-shared
|
||||
@@ -8,11 +8,19 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
* Added timeout to DNS query function calls for dns-rfc2136 plugin.
|
||||
* Confirmation when deleting certificates
|
||||
*
|
||||
* CLI flag `--key-type` has been added to specify 'rsa' or 'ecdsa' (default 'rsa').
|
||||
Only accepts a single value at this time.
|
||||
* CLI flag `--elliptic-curve` has been added which takes an NIST/SECG elliptic curve. Either of
|
||||
`secp256r1`, `secp284r1` and `secp521r1` are accepted values.
|
||||
* The command `certbot certficates` lists the which type of the private key that was used
|
||||
for the private key.
|
||||
|
||||
### Changed
|
||||
|
||||
* certbot-auto was deprecated on Debian based systems.
|
||||
* CLI flag `--manual-public-ip-logging-ok` is now a no-op, generates a
|
||||
deprecation warning, and will be removed in a future release.
|
||||
*
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -52,7 +60,7 @@ More details about these changes can be found on our GitHub repo.
|
||||
|
||||
### Added
|
||||
|
||||
* Added the ability to remove email and phone contact information from an account
|
||||
* Added the ability to remove email and phone contact information from an account
|
||||
using `update_account --register-unsafely-without-email`
|
||||
|
||||
### Changed
|
||||
@@ -64,7 +72,7 @@ More details about these changes can be found on our GitHub repo.
|
||||
* The problem causing the Apache plugin in the Certbot snap on ARM systems to
|
||||
fail to load the Augeas library it depends on has been fixed.
|
||||
* The `acme` library can now tell the ACME server to clear contact information by passing an empty
|
||||
`tuple` to the `contact` field of a `Registration` message.
|
||||
`tuple` to the `contact` field of a `Registration` message.
|
||||
* Fixed the `*** stack smashing detected ***` error in the Certbot snap on some systems.
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
@@ -106,6 +106,8 @@ Current Features
|
||||
* Can get domain-validated (DV) certificates.
|
||||
* Can revoke certificates.
|
||||
* Adjustable RSA key bit-length (2048 (default), 4096, ...).
|
||||
* Adjustable [EC](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography)
|
||||
key (`secp256r1` (default), `secp384r1`, `secp521r1`).
|
||||
* Can optionally install a http -> https redirect, so your site effectively
|
||||
runs https only (Apache only)
|
||||
* Fully automated.
|
||||
|
||||
@@ -11,7 +11,6 @@ import josepy as jose
|
||||
import pyrfc3339
|
||||
import pytz
|
||||
import six
|
||||
import zope.component
|
||||
|
||||
from acme import fields as acme_fields
|
||||
from acme import messages
|
||||
@@ -94,21 +93,6 @@ class Account(object):
|
||||
self.meta == other.meta)
|
||||
|
||||
|
||||
def report_new_account(config):
|
||||
"""Informs the user about their new ACME account."""
|
||||
reporter = zope.component.queryUtility(interfaces.IReporter)
|
||||
if reporter is None:
|
||||
return
|
||||
reporter.add_message(
|
||||
"Your account credentials have been saved in your Certbot "
|
||||
"configuration directory at {0}. You should make a secure backup "
|
||||
"of this folder now. This configuration directory will also "
|
||||
"contain certificates and private keys obtained by Certbot "
|
||||
"so making regular backups of this folder is ideal.".format(
|
||||
config.config_dir),
|
||||
reporter.MEDIUM_PRIORITY)
|
||||
|
||||
|
||||
class AccountMemoryStorage(interfaces.AccountStorage):
|
||||
"""In-memory account storage."""
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ def rename_lineage(config):
|
||||
disp.notification("Successfully renamed {0} to {1}."
|
||||
.format(certname, new_certname), pause=False)
|
||||
|
||||
|
||||
def certificates(config):
|
||||
"""Display information about certs configured with Certbot
|
||||
|
||||
@@ -87,6 +88,7 @@ def certificates(config):
|
||||
# Describe all the certs
|
||||
_describe_certs(config, parsed_certs, parse_failures)
|
||||
|
||||
|
||||
def delete(config):
|
||||
"""Delete Certbot files associated with a certificate lineage."""
|
||||
certnames = get_certnames(config, "delete", allow_multiple=True)
|
||||
@@ -123,11 +125,13 @@ def lineage_for_certname(cli_config, certname):
|
||||
logger.debug("Traceback was:\n%s", traceback.format_exc())
|
||||
return None
|
||||
|
||||
|
||||
def domains_for_certname(config, certname):
|
||||
"""Find the domains in the cert with name certname."""
|
||||
lineage = lineage_for_certname(config, certname)
|
||||
return lineage.names() if lineage else None
|
||||
|
||||
|
||||
def find_duplicative_certs(config, domains):
|
||||
"""Find existing certs that match the given domain names.
|
||||
|
||||
@@ -172,6 +176,7 @@ def find_duplicative_certs(config, domains):
|
||||
|
||||
return _search_lineages(config, update_certs_for_domain_matches, (None, None))
|
||||
|
||||
|
||||
def _archive_files(candidate_lineage, filetype):
|
||||
""" In order to match things like:
|
||||
/etc/letsencrypt/archive/example.com/chain1.pem.
|
||||
@@ -193,6 +198,7 @@ def _archive_files(candidate_lineage, filetype):
|
||||
return pattern
|
||||
return None
|
||||
|
||||
|
||||
def _acceptable_matches():
|
||||
""" Generates the list that's passed to match_and_check_overlaps. Is its own function to
|
||||
make unit testing easier.
|
||||
@@ -203,6 +209,7 @@ def _acceptable_matches():
|
||||
return [lambda x: x.fullchain_path, lambda x: x.cert_path,
|
||||
lambda x: _archive_files(x, "cert"), lambda x: _archive_files(x, "fullchain")]
|
||||
|
||||
|
||||
def cert_path_to_lineage(cli_config):
|
||||
""" If config.cert_path is defined, try to find an appropriate value for config.certname.
|
||||
|
||||
@@ -219,6 +226,7 @@ def cert_path_to_lineage(cli_config):
|
||||
lambda x: cli_config.cert_path[0], lambda x: x.lineagename)
|
||||
return match[0]
|
||||
|
||||
|
||||
def match_and_check_overlaps(cli_config, acceptable_matches, match_func, rv_func):
|
||||
""" Searches through all lineages for a match, and checks for duplicates.
|
||||
If a duplicate is found, an error is raised, as performing operations on lineages
|
||||
@@ -284,20 +292,23 @@ def human_readable_cert_info(config, cert, skip_filter_checks=False):
|
||||
|
||||
valid_string = "{0} ({1})".format(cert.target_expiry, status)
|
||||
serial = format(crypto_util.get_serial_from_cert(cert.cert_path), 'x')
|
||||
certinfo.append(" Certificate Name: {0}\n"
|
||||
" Serial Number: {1}\n"
|
||||
" Domains: {2}\n"
|
||||
" Expiry Date: {3}\n"
|
||||
" Certificate Path: {4}\n"
|
||||
" Private Key Path: {5}".format(
|
||||
certinfo.append(" Certificate Name: {}\n"
|
||||
" Serial Number: {}\n"
|
||||
" Key Type: {}\n"
|
||||
" Domains: {}\n"
|
||||
" Expiry Date: {}\n"
|
||||
" Certificate Path: {}\n"
|
||||
" Private Key Path: {}".format(
|
||||
cert.lineagename,
|
||||
serial,
|
||||
cert.private_key_type,
|
||||
" ".join(cert.names()),
|
||||
valid_string,
|
||||
cert.fullchain,
|
||||
cert.privkey))
|
||||
return "".join(certinfo)
|
||||
|
||||
|
||||
def get_certnames(config, verb, allow_multiple=False, custom_prompt=None):
|
||||
"""Get certname from flag, interactively, or error out.
|
||||
"""
|
||||
@@ -337,10 +348,12 @@ def get_certnames(config, verb, allow_multiple=False, custom_prompt=None):
|
||||
# Private Helpers
|
||||
###################
|
||||
|
||||
|
||||
def _report_lines(msgs):
|
||||
"""Format a results report for a category of single-line renewal outcomes"""
|
||||
return " " + "\n ".join(str(msg) for msg in msgs)
|
||||
|
||||
|
||||
def _report_human_readable(config, parsed_certs):
|
||||
"""Format a results report for a parsed cert"""
|
||||
certinfo = []
|
||||
@@ -348,6 +361,7 @@ def _report_human_readable(config, parsed_certs):
|
||||
certinfo.append(human_readable_cert_info(config, cert))
|
||||
return "\n".join(certinfo)
|
||||
|
||||
|
||||
def _describe_certs(config, parsed_certs, parse_failures):
|
||||
"""Print information about the certs we know about"""
|
||||
out = [] # type: List[str]
|
||||
@@ -369,6 +383,7 @@ def _describe_certs(config, parsed_certs, parse_failures):
|
||||
disp = zope.component.getUtility(interfaces.IDisplay)
|
||||
disp.notification("\n".join(out), pause=False, wrap=False)
|
||||
|
||||
|
||||
def _search_lineages(cli_config, func, initial_rv, *args):
|
||||
"""Iterate func over unbroken lineages, allowing custom return conditions.
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ from certbot._internal.cli.cli_utils import (
|
||||
)
|
||||
|
||||
# These imports depend on cli_constants and cli_utils.
|
||||
from certbot._internal.cli.report_config_interaction import report_config_interaction
|
||||
from certbot._internal.cli.verb_help import VERB_HELP, VERB_HELP_MAP
|
||||
from certbot._internal.cli.group_adder import _add_all_groups
|
||||
from certbot._internal.cli.subparsers import _create_subparsers
|
||||
@@ -314,6 +313,16 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False):
|
||||
helpful.add(
|
||||
"security", "--rsa-key-size", type=int, metavar="N",
|
||||
default=flag_default("rsa_key_size"), help=config_help("rsa_key_size"))
|
||||
helpful.add(
|
||||
"security", "--key-type", choices=['rsa', 'ecdsa'], type=str,
|
||||
default=flag_default("key_type"), help=config_help("key_type"))
|
||||
helpful.add(
|
||||
"security", "--elliptic-curve", type=str, choices=[
|
||||
'secp256r1',
|
||||
'secp384r1',
|
||||
'secp521r1',
|
||||
], metavar="N",
|
||||
default=flag_default("elliptic_curve"), help=config_help("elliptic_curve"))
|
||||
helpful.add(
|
||||
"security", "--must-staple", action="store_true",
|
||||
dest="must_staple", default=flag_default("must_staple"),
|
||||
|
||||
@@ -230,6 +230,10 @@ class HelpfulArgumentParser(object):
|
||||
raise errors.Error(
|
||||
"Parameters --hsts and --auto-hsts cannot be used simultaneously.")
|
||||
|
||||
if isinstance(parsed_args.key_type, list) and len(parsed_args.key_type) > 1:
|
||||
raise errors.Error(
|
||||
"Only *one* --key-type type may be provided at this time.")
|
||||
|
||||
return parsed_args
|
||||
|
||||
def set_test_server(self, parsed_args):
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
"""This is a module that reports config option interaction that should be
|
||||
checked by set_by_cli"""
|
||||
import six
|
||||
|
||||
from certbot._internal.cli import VAR_MODIFIERS
|
||||
|
||||
|
||||
def report_config_interaction(modified, modifiers):
|
||||
"""Registers config option interaction to be checked by set_by_cli.
|
||||
|
||||
This function can be called by during the __init__ or
|
||||
add_parser_arguments methods of plugins to register interactions
|
||||
between config options.
|
||||
|
||||
:param modified: config options that can be modified by modifiers
|
||||
:type modified: iterable or str (string_types)
|
||||
:param modifiers: config options that modify modified
|
||||
:type modifiers: iterable or str (string_types)
|
||||
|
||||
"""
|
||||
if isinstance(modified, six.string_types):
|
||||
modified = (modified,)
|
||||
if isinstance(modifiers, six.string_types):
|
||||
modifiers = (modifiers,)
|
||||
|
||||
for var in modified:
|
||||
VAR_MODIFIERS.setdefault(var, set()).update(modifiers)
|
||||
@@ -158,7 +158,7 @@ def register(config, account_storage, tos_cb=None):
|
||||
logger.warning(msg)
|
||||
raise errors.Error(msg)
|
||||
if not config.dry_run:
|
||||
logger.info("Registering without email!")
|
||||
logger.debug("Registering without email!")
|
||||
|
||||
# If --dry-run is used, and there is no staging account, create one with no email.
|
||||
if config.dry_run:
|
||||
@@ -175,7 +175,6 @@ def register(config, account_storage, tos_cb=None):
|
||||
regr = perform_registration(acme, config, tos_cb)
|
||||
|
||||
acc = account.Account(regr, key)
|
||||
account.report_new_account(config)
|
||||
account_storage.save(acc, acme)
|
||||
|
||||
eff.prepare_subscription(config, acc)
|
||||
@@ -313,7 +312,6 @@ class Client(object):
|
||||
:rtype: tuple
|
||||
|
||||
"""
|
||||
|
||||
# We need to determine the key path, key PEM data, CSR path,
|
||||
# and CSR PEM data. For a dry run, the paths are None because
|
||||
# they aren't permanently saved to disk. For a lineage with
|
||||
@@ -336,16 +334,41 @@ class Client(object):
|
||||
# The key is set to None here but will be created below.
|
||||
key = None
|
||||
|
||||
key_size = self.config.rsa_key_size
|
||||
elliptic_curve = None
|
||||
|
||||
# key-type defaults to a list, but we are only handling 1 currently
|
||||
if isinstance(self.config.key_type, list):
|
||||
self.config.key_type = self.config.key_type[0]
|
||||
if self.config.elliptic_curve and self.config.key_type == 'ecdsa':
|
||||
elliptic_curve = self.config.elliptic_curve
|
||||
self.config.auth_chain_path = "./chain-ecdsa.pem"
|
||||
self.config.auth_cert_path = "./cert-ecdsa.pem"
|
||||
self.config.key_path = "./key-ecdsa.pem"
|
||||
elif self.config.rsa_key_size and self.config.key_type.lower() == 'rsa':
|
||||
key_size = self.config.rsa_key_size
|
||||
|
||||
# Create CSR from names
|
||||
if self.config.dry_run:
|
||||
key = key or util.Key(file=None,
|
||||
pem=crypto_util.make_key(self.config.rsa_key_size))
|
||||
key = key or util.Key(
|
||||
file=None,
|
||||
pem=crypto_util.make_key(
|
||||
bits=key_size,
|
||||
elliptic_curve=elliptic_curve,
|
||||
key_type=self.config.key_type,
|
||||
|
||||
),
|
||||
)
|
||||
csr = util.CSR(file=None, form="pem",
|
||||
data=acme_crypto_util.make_csr(
|
||||
key.pem, domains, self.config.must_staple))
|
||||
else:
|
||||
key = key or crypto_util.init_save_key(self.config.rsa_key_size,
|
||||
self.config.key_dir)
|
||||
key = key or crypto_util.init_save_key(
|
||||
key_size=key_size,
|
||||
key_dir=self.config.key_dir,
|
||||
key_type=self.config.key_type,
|
||||
elliptic_curve=elliptic_curve,
|
||||
)
|
||||
csr = crypto_util.init_save_csr(key, domains, self.config.csr_dir)
|
||||
|
||||
orderr = self._get_order_and_authorizations(csr.data, self.config.allow_subset_of_names)
|
||||
|
||||
@@ -57,6 +57,8 @@ CLI_DEFAULTS = dict(
|
||||
https_port=443,
|
||||
break_my_certs=False,
|
||||
rsa_key_size=2048,
|
||||
elliptic_curve="secp256r1",
|
||||
key_type="rsa",
|
||||
must_staple=False,
|
||||
redirect=None,
|
||||
auto_hsts=False,
|
||||
|
||||
@@ -11,7 +11,7 @@ import josepy as jose
|
||||
import zope.component
|
||||
|
||||
from acme import errors as acme_errors
|
||||
from acme.magic_typing import Union, Iterable, Optional # pylint: disable=unused-import
|
||||
from acme.magic_typing import Union, Iterable, Optional, List, Tuple # pylint: disable=unused-import
|
||||
import certbot
|
||||
from certbot import crypto_util
|
||||
from certbot import errors
|
||||
@@ -130,7 +130,37 @@ def _get_and_save_cert(le_client, config, domains=None, certname=None, lineage=N
|
||||
return lineage
|
||||
|
||||
|
||||
def _handle_subset_cert_request(config, domains, cert):
|
||||
def _handle_unexpected_key_type_migration(config, cert):
|
||||
# type: (configuration.NamespaceConfig, storage.RenewableCert) -> None
|
||||
"""
|
||||
This function ensures that the user will not implicitly migrate an existing key
|
||||
from one type to another in the situation where a certificate for that lineage
|
||||
already exist and they have not provided explicitly --key-type and --cert-name.
|
||||
:param config: Current configuration provided by the client
|
||||
:param cert: Matching certificate that could be renewed
|
||||
"""
|
||||
if (config.verb in ["certonly", "run"]
|
||||
and (not cli.set_by_cli("key_type") or not cli.set_by_cli("certname"))):
|
||||
|
||||
new_key_type = config.key_type.upper()
|
||||
cur_key_type = cert.private_key_type.upper()
|
||||
|
||||
if new_key_type != cur_key_type:
|
||||
logger.error("A certificate already exists for that name, the list of provided "
|
||||
"domains or a subset of this list. This certificate uses a key of %s "
|
||||
"type, and you have not provided the --key-type flag. By default in this "
|
||||
"case Certbot would generate a new certificate with a key of %s type. "
|
||||
"Please confirm that you really want to change the type of the key by "
|
||||
"setting both --cert-name and --key-type CLI flags.",
|
||||
cur_key_type, new_key_type)
|
||||
raise errors.Error("Command canceled.")
|
||||
|
||||
|
||||
def _handle_subset_cert_request(config, # type: configuration.NamespaceConfig
|
||||
domains, # type: List[str]
|
||||
cert # type: storage.RenewableCert
|
||||
):
|
||||
# type: (...) -> Tuple[str, Optional[storage.RenewableCert]]
|
||||
"""Figure out what to do if a previous cert had a subset of the names now requested
|
||||
|
||||
:param config: Configuration object
|
||||
@@ -147,6 +177,8 @@ def _handle_subset_cert_request(config, domains, cert):
|
||||
:rtype: `tuple` of `str`
|
||||
|
||||
"""
|
||||
_handle_unexpected_key_type_migration(config, cert)
|
||||
|
||||
existing = ", ".join(cert.names())
|
||||
question = (
|
||||
"You have an existing certificate that contains a portion of "
|
||||
@@ -177,7 +209,10 @@ def _handle_subset_cert_request(config, domains, cert):
|
||||
raise errors.Error(USER_CANCELLED)
|
||||
|
||||
|
||||
def _handle_identical_cert_request(config, lineage):
|
||||
def _handle_identical_cert_request(config, # type: configuration.NamespaceConfig
|
||||
lineage, # type: storage.RenewableCert
|
||||
):
|
||||
# type: (...) -> Tuple[str, Optional[storage.RenewableCert]]
|
||||
"""Figure out what to do if a lineage has the same names as a previously obtained one
|
||||
|
||||
:param config: Configuration object
|
||||
@@ -191,6 +226,8 @@ def _handle_identical_cert_request(config, lineage):
|
||||
:rtype: `tuple` of `str`
|
||||
|
||||
"""
|
||||
_handle_unexpected_key_type_migration(config, lineage)
|
||||
|
||||
if not lineage.ensure_deployed():
|
||||
return "reinstall", lineage
|
||||
if renewal.should_renew(config, lineage):
|
||||
@@ -266,6 +303,7 @@ def _find_lineage_for_domains(config, domains):
|
||||
return _handle_subset_cert_request(config, domains, subset_names_cert)
|
||||
return None, None
|
||||
|
||||
|
||||
def _find_cert(config, domains, certname):
|
||||
"""Finds an existing certificate object given domains and/or a certificate name.
|
||||
|
||||
@@ -289,7 +327,12 @@ def _find_cert(config, domains, certname):
|
||||
logger.info("Keeping the existing certificate")
|
||||
return (action != "reinstall"), lineage
|
||||
|
||||
def _find_lineage_for_domains_and_certname(config, domains, certname):
|
||||
|
||||
def _find_lineage_for_domains_and_certname(config, # type: configuration.NamespaceConfig
|
||||
domains, # type: List[str]
|
||||
certname # type: str
|
||||
):
|
||||
# type: (...) -> Tuple[str, Optional[storage.RenewableCert]]
|
||||
"""Find appropriate lineage based on given domains and/or certname.
|
||||
|
||||
:param config: Configuration object
|
||||
@@ -316,8 +359,9 @@ def _find_lineage_for_domains_and_certname(config, domains, certname):
|
||||
if lineage:
|
||||
if domains:
|
||||
if set(cert_manager.domains_for_certname(config, certname)) != set(domains):
|
||||
_handle_unexpected_key_type_migration(config, lineage)
|
||||
_ask_user_to_confirm_new_names(config, domains, certname,
|
||||
lineage.names()) # raises if no
|
||||
lineage.names()) # raises if no
|
||||
return "renew", lineage
|
||||
# unnecessarily specified domains or no domains specified
|
||||
return _handle_identical_cert_request(config, lineage)
|
||||
@@ -386,6 +430,7 @@ def _ask_user_to_confirm_new_names(config, new_domains, certname, old_domains):
|
||||
if not obj.yesno(msg, "Update cert", "Cancel", default=True):
|
||||
raise errors.ConfigurationError("Specified mismatched cert name and domains.")
|
||||
|
||||
|
||||
def _find_domains_or_certname(config, installer, question=None):
|
||||
"""Retrieve domains and certname from config or user input.
|
||||
|
||||
@@ -490,11 +535,9 @@ def _determine_account(config):
|
||||
return True
|
||||
msg = ("Please read the Terms of Service at {0}. You "
|
||||
"must agree in order to register with the ACME "
|
||||
"server at {1}".format(
|
||||
terms_of_service, config.server))
|
||||
"server. Do you agree?".format(terms_of_service))
|
||||
obj = zope.component.getUtility(interfaces.IDisplay)
|
||||
result = obj.yesno(msg, "Agree", "Cancel",
|
||||
cli_flag="--agree-tos", force_interactive=True)
|
||||
result = obj.yesno(msg, cli_flag="--agree-tos", force_interactive=True)
|
||||
if not result:
|
||||
raise errors.Error(
|
||||
"Registration cannot proceed without accepting "
|
||||
@@ -518,6 +561,7 @@ def _determine_account(config):
|
||||
try:
|
||||
acc, acme = client.register(
|
||||
config, account_storage, tos_cb=_tos_cb)
|
||||
logger.info("Account registered.")
|
||||
except errors.MissingCommandlineFlag:
|
||||
raise
|
||||
except errors.Error:
|
||||
@@ -1010,6 +1054,7 @@ def delete(config, unused_plugins):
|
||||
"""
|
||||
cert_manager.delete(config)
|
||||
|
||||
|
||||
def certificates(config, unused_plugins):
|
||||
"""Display information about certs configured with Certbot
|
||||
|
||||
@@ -1025,6 +1070,7 @@ def certificates(config, unused_plugins):
|
||||
"""
|
||||
cert_manager.certificates(config)
|
||||
|
||||
|
||||
# TODO: coop with renewal config
|
||||
def revoke(config, unused_plugins):
|
||||
"""Revoke a previously obtained certificate.
|
||||
@@ -1110,7 +1156,9 @@ def run(config, plugins):
|
||||
cert_path = new_lineage.cert_path if new_lineage else None
|
||||
fullchain_path = new_lineage.fullchain_path if new_lineage else None
|
||||
key_path = new_lineage.key_path if new_lineage else None
|
||||
_report_new_cert(config, cert_path, fullchain_path, key_path)
|
||||
|
||||
if should_get_cert:
|
||||
_report_new_cert(config, cert_path, fullchain_path, key_path)
|
||||
|
||||
_install_cert(config, le_client, domains, new_lineage)
|
||||
|
||||
@@ -1155,6 +1203,7 @@ def _csr_get_and_save_cert(config, le_client):
|
||||
os.path.normpath(config.chain_path), os.path.normpath(config.fullchain_path))
|
||||
return cert_path, fullchain_path
|
||||
|
||||
|
||||
def renew_cert(config, plugins, lineage):
|
||||
"""Renew & save an existing cert. Do not install it.
|
||||
|
||||
|
||||
@@ -84,8 +84,7 @@ permitted by DNS standards.)
|
||||
help='Path or command to execute for the authentication script')
|
||||
add('cleanup-hook',
|
||||
help='Path or command to execute for the cleanup script')
|
||||
add('public-ip-logging-ok', action='store_true',
|
||||
help='Automatically allows public IP logging (default: Ask)')
|
||||
util.add_deprecated_argument(add, 'public-ip-logging-ok', 0)
|
||||
|
||||
def prepare(self): # pylint: disable=missing-function-docstring
|
||||
if self.config.noninteractive_mode and not self.conf('auth-hook'):
|
||||
@@ -114,8 +113,6 @@ permitted by DNS standards.)
|
||||
return [challenges.HTTP01, challenges.DNS01]
|
||||
|
||||
def perform(self, achalls): # pylint: disable=missing-function-docstring
|
||||
self._verify_ip_logging_ok()
|
||||
|
||||
responses = []
|
||||
for achall in achalls:
|
||||
if self.conf('auth-hook'):
|
||||
@@ -125,20 +122,6 @@ permitted by DNS standards.)
|
||||
responses.append(achall.response(achall.account_key))
|
||||
return responses
|
||||
|
||||
def _verify_ip_logging_ok(self):
|
||||
if not self.conf('public-ip-logging-ok'):
|
||||
cli_flag = '--{0}'.format(self.option_name('public-ip-logging-ok'))
|
||||
msg = ('NOTE: The IP of this machine will be publicly logged as '
|
||||
"having requested this certificate. If you're running "
|
||||
'certbot in manual mode on a machine that is not your '
|
||||
"server, please ensure you're okay with that.\n\n"
|
||||
'Are you OK with your IP being logged?')
|
||||
display = zope.component.getUtility(interfaces.IDisplay)
|
||||
if display.yesno(msg, cli_flag=cli_flag, force_interactive=True):
|
||||
setattr(self.config, self.dest('public-ip-logging-ok'), True)
|
||||
else:
|
||||
raise errors.PluginError('Must agree to IP logging to proceed')
|
||||
|
||||
def _perform_achall_with_script(self, achall, achalls):
|
||||
env = dict(CERTBOT_DOMAIN=achall.domain,
|
||||
CERTBOT_VALIDATION=achall.validation(achall.account_key),
|
||||
|
||||
@@ -10,7 +10,7 @@ import time
|
||||
import traceback
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.primitives.asymmetric import ec, rsa
|
||||
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||
import OpenSSL
|
||||
import six
|
||||
@@ -40,7 +40,7 @@ logger = logging.getLogger(__name__)
|
||||
STR_CONFIG_ITEMS = ["config_dir", "logs_dir", "work_dir", "user_agent",
|
||||
"server", "account", "authenticator", "installer",
|
||||
"renew_hook", "pre_hook", "post_hook", "http01_address",
|
||||
"preferred_chain"]
|
||||
"preferred_chain", "key_type", "elliptic_curve"]
|
||||
INT_CONFIG_ITEMS = ["rsa_key_size", "http01_port"]
|
||||
BOOL_CONFIG_ITEMS = ["must_staple", "allow_subset_of_names", "reuse_key",
|
||||
"autorenew"]
|
||||
@@ -506,6 +506,10 @@ def _update_renewal_params_from_key(key_path, config):
|
||||
with open(key_path, 'rb') as file_h:
|
||||
key = load_pem_private_key(file_h.read(), password=None, backend=default_backend())
|
||||
if isinstance(key, rsa.RSAPrivateKey):
|
||||
config.key_type = 'rsa'
|
||||
config.rsa_key_size = key.key_size
|
||||
elif isinstance(key, ec.EllipticCurvePrivateKey):
|
||||
config.key_type = 'ecdsa'
|
||||
config.elliptic_curve = key.curve.name
|
||||
else:
|
||||
raise errors.Error('Key at {0} is of an unsupported type: {1}.'.format(key_path, type(key)))
|
||||
|
||||
@@ -10,6 +10,9 @@ import configobj
|
||||
import parsedatetime
|
||||
import pytz
|
||||
import six
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
|
||||
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||
|
||||
import certbot
|
||||
from certbot import crypto_util
|
||||
@@ -46,6 +49,7 @@ def renewal_conf_files(config):
|
||||
result.sort()
|
||||
return result
|
||||
|
||||
|
||||
def renewal_file_for_certname(config, certname):
|
||||
"""Return /path/to/certname.conf in the renewal conf directory"""
|
||||
path = os.path.join(config.renewal_configs_dir, "{0}.conf".format(certname))
|
||||
@@ -1055,6 +1059,23 @@ class RenewableCert(interfaces.RenewableCert):
|
||||
target, values)
|
||||
return cls(new_config.filename, cli_config)
|
||||
|
||||
@property
|
||||
def private_key_type(self):
|
||||
"""
|
||||
:returns: The type of algorithm for the private, RSA or ECDSA
|
||||
:rtype: str
|
||||
"""
|
||||
with open(self.configuration["privkey"], "rb") as priv_key_file:
|
||||
key = load_pem_private_key(
|
||||
data=priv_key_file.read(),
|
||||
password=None,
|
||||
backend=default_backend()
|
||||
)
|
||||
if isinstance(key, RSAPrivateKey):
|
||||
return "RSA"
|
||||
else:
|
||||
return "ECDSA"
|
||||
|
||||
def save_successor(self, prior_version, new_cert,
|
||||
new_privkey, new_chain, cli_config):
|
||||
"""Save new cert and chain as a successor of a prior version.
|
||||
|
||||
@@ -11,14 +11,16 @@ import warnings
|
||||
import re
|
||||
# See https://github.com/pyca/cryptography/issues/4275
|
||||
from cryptography import x509 # type: ignore
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import ECDSA
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import ECDSA, EllipticCurvePublicKey
|
||||
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
|
||||
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
|
||||
from cryptography.hazmat.primitives.serialization import Encoding, NoEncryption, PrivateFormat
|
||||
from OpenSSL import crypto
|
||||
from OpenSSL import SSL # type: ignore
|
||||
|
||||
import pyrfc3339
|
||||
import six
|
||||
import zope.component
|
||||
@@ -34,7 +36,9 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# High level functions
|
||||
def init_save_key(key_size, key_dir, keyname="key-certbot.pem"):
|
||||
def init_save_key(
|
||||
key_size, key_dir, key_type="rsa", elliptic_curve="secp256r1", keyname="key-certbot.pem"
|
||||
):
|
||||
"""Initializes and saves a privkey.
|
||||
|
||||
Inits key and saves it in PEM format on the filesystem.
|
||||
@@ -42,8 +46,10 @@ def init_save_key(key_size, key_dir, keyname="key-certbot.pem"):
|
||||
.. note:: keyname is the attempted filename, it may be different if a file
|
||||
already exists at the path.
|
||||
|
||||
:param int key_size: RSA key size in bits
|
||||
:param int key_size: key size in bits if key size is rsa.
|
||||
:param str key_dir: Key save directory.
|
||||
:param str key_type: Key Type [rsa, ecdsa]
|
||||
:param str elliptic_curve: Name of the elliptic curve if key type is ecdsa.
|
||||
:param str keyname: Filename of key
|
||||
|
||||
:returns: Key
|
||||
@@ -53,7 +59,9 @@ def init_save_key(key_size, key_dir, keyname="key-certbot.pem"):
|
||||
|
||||
"""
|
||||
try:
|
||||
key_pem = make_key(key_size)
|
||||
key_pem = make_key(
|
||||
bits=key_size, elliptic_curve=elliptic_curve or "secp256r1", key_type=key_type,
|
||||
)
|
||||
except ValueError as err:
|
||||
logger.error("", exc_info=True)
|
||||
raise err
|
||||
@@ -65,7 +73,10 @@ def init_save_key(key_size, key_dir, keyname="key-certbot.pem"):
|
||||
os.path.join(key_dir, keyname), 0o600, "wb")
|
||||
with key_f:
|
||||
key_f.write(key_pem)
|
||||
logger.debug("Generating key (%d bits): %s", key_size, key_path)
|
||||
if key_type == 'rsa':
|
||||
logger.debug("Generating RSA key (%d bits): %s", key_size, key_path)
|
||||
else:
|
||||
logger.debug("Generating ECDSA key (%d bits): %s", key_size, key_path)
|
||||
|
||||
return util.Key(key_path, key_pem)
|
||||
|
||||
@@ -174,18 +185,45 @@ def import_csr_file(csrfile, data):
|
||||
return PEM, util.CSR(file=csrfile, data=data_pem, form="pem"), domains
|
||||
|
||||
|
||||
def make_key(bits):
|
||||
"""Generate PEM encoded RSA key.
|
||||
def make_key(bits=1024, key_type="rsa", elliptic_curve=None):
|
||||
"""Generate PEM encoded RSA|EC key.
|
||||
|
||||
:param int bits: Number of bits, at least 1024.
|
||||
:param int bits: Number of bits if key_type=rsa. At least 1024 for RSA.
|
||||
|
||||
:returns: new RSA key in PEM form with specified number of bits
|
||||
:param str ec_curve: The elliptic curve to use.
|
||||
|
||||
:returns: new RSA or ECDSA key in PEM form with specified number of bits
|
||||
or of type ec_curve when key_type ecdsa is used.
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
assert bits >= 1024 # XXX
|
||||
key = crypto.PKey()
|
||||
key.generate_key(crypto.TYPE_RSA, bits)
|
||||
if key_type == 'rsa':
|
||||
if bits < 1024:
|
||||
raise errors.Error("Unsupported RSA key length: {}".format(bits))
|
||||
|
||||
key = crypto.PKey()
|
||||
key.generate_key(crypto.TYPE_RSA, bits)
|
||||
elif key_type == 'ecdsa':
|
||||
try:
|
||||
name = elliptic_curve.upper()
|
||||
if name in ('SECP256R1', 'SECP384R1', 'SECP512R1'):
|
||||
_key = ec.generate_private_key(
|
||||
curve=getattr(ec, elliptic_curve.upper(), None)(),
|
||||
backend=default_backend()
|
||||
)
|
||||
else:
|
||||
raise errors.Error("Unsupported elliptic curve: {}".format(elliptic_curve))
|
||||
except TypeError:
|
||||
raise errors.Error("Unsupported elliptic curve: {}".format(elliptic_curve))
|
||||
except UnsupportedAlgorithm as e:
|
||||
raise six.raise_from(e, errors.Error(str(e)))
|
||||
_key_pem = _key.private_bytes(
|
||||
encoding=Encoding.PEM,
|
||||
format=PrivateFormat.TraditionalOpenSSL,
|
||||
encryption_algorithm=NoEncryption()
|
||||
)
|
||||
key = crypto.load_privatekey(crypto.FILETYPE_PEM, _key_pem)
|
||||
else:
|
||||
raise errors.Error("Invalid key_type specified: {}. Use [rsa|ecdsa]".format(key_type))
|
||||
return crypto.dump_privatekey(crypto.FILETYPE_PEM, key)
|
||||
|
||||
|
||||
|
||||
@@ -198,6 +198,13 @@ class IConfig(zope.interface.Interface):
|
||||
"register multiple emails, ex: u1@example.com,u2@example.com. "
|
||||
"(default: Ask).")
|
||||
rsa_key_size = zope.interface.Attribute("Size of the RSA key.")
|
||||
elliptic_curve = zope.interface.Attribute(
|
||||
"The SECG elliptic curve name to use. Please see RFC 8446 "
|
||||
"for supported values."
|
||||
)
|
||||
key_type = zope.interface.Attribute(
|
||||
"Type of generated private key"
|
||||
"(Only *ONE* per invocation can be provided at this time)")
|
||||
must_staple = zope.interface.Attribute(
|
||||
"Adds the OCSP Must Staple extension to the certificate. "
|
||||
"Autoconfigures OCSP Stapling for supported setups "
|
||||
@@ -260,6 +267,7 @@ class IConfig(zope.interface.Interface):
|
||||
"offered chain will be used."
|
||||
)
|
||||
|
||||
|
||||
class IInstaller(IPlugin):
|
||||
"""Generic Certbot Installer Interface.
|
||||
|
||||
|
||||
@@ -55,10 +55,6 @@ class Plugin(object):
|
||||
def add_parser_arguments(cls, add):
|
||||
"""Add plugin arguments to the CLI argument parser.
|
||||
|
||||
NOTE: If some of your flags interact with others, you can
|
||||
use cli.report_config_interaction to register this to ensure
|
||||
values are correctly saved/overridable during renewal.
|
||||
|
||||
:param callable add: Function that proxies calls to
|
||||
`argparse.ArgumentParser.add_argument` prepending options
|
||||
with unique plugin name prefix.
|
||||
|
||||
8
certbot/certbot/tests/testdata/README
vendored
8
certbot/certbot/tests/testdata/README
vendored
@@ -2,10 +2,16 @@ The following command has been used to generate test keys:
|
||||
|
||||
for x in 256 512 2048; do openssl genrsa -out rsa${k}_key.pem $k; done
|
||||
|
||||
For the elliptic curve private keys, this command was used:
|
||||
|
||||
for k in "prime256v1" "secp384r1" "secp521r1" do
|
||||
openssl genpkey -algorithm ${k} -out ec_${k}_key.pem
|
||||
done
|
||||
|
||||
and for the CSR PEM (Certificate Signing Request):
|
||||
|
||||
openssl req -new -out csr-Xsans_X.pem -key rsa512_key.pem [-config csr-Xsans_X.conf | -subj '/CN=example.com'] [-outform DER > csr_X.der]
|
||||
|
||||
and for the certificate:
|
||||
|
||||
openssl req -new -out cert_X.pem -key rsaX_key.pem -subj '/CN=example.com' -x509 [-outform DER > cert_X.der]
|
||||
openssl req -new -out cert_X.pem -key rsaX_key.pem -subj '/CN=example.com' -x509 [-outform DER > cert_X.der]
|
||||
|
||||
8
certbot/certbot/tests/testdata/ec_prime256v1_key.pem
vendored
Normal file
8
certbot/certbot/tests/testdata/ec_prime256v1_key.pem
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
-----BEGIN EC PARAMETERS-----
|
||||
BggqhkjOPQMBBw==
|
||||
-----END EC PARAMETERS-----
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIDqQPQl69kuh+DrecC8SFPt21f0F/HHDP3T4/Lf0zIVFoAoGCCqGSM49
|
||||
AwEHoUQDQgAEHou50Ee9u+8Vial6VbUHExlzsiCHtORlW0X0pKo5RspIKB0QyKwo
|
||||
dUXvBbv95I9yCO5+MlGkKjwLHtIEze0Hww==
|
||||
-----END EC PRIVATE KEY-----
|
||||
9
certbot/certbot/tests/testdata/ec_secp384r1_key.pem
vendored
Normal file
9
certbot/certbot/tests/testdata/ec_secp384r1_key.pem
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN EC PARAMETERS-----
|
||||
BgUrgQQAIg==
|
||||
-----END EC PARAMETERS-----
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIGkAgEBBDAgvZGw5C7Mp26N0cXA+vIg5K/J5MJw+MVGYfGF4ZutuCLeYMrWT68R
|
||||
A0h6hJvDtMSgBwYFK4EEACKhZANiAAR1uQYZeU5Kml5o53Q8/PCdwUbqdgCSkV0C
|
||||
J5a6bhDRMp20fdp2T/mbkdxuVEl81lqfKPZhsd4CZsLaVIU3RUoGgIT1R3QKawpJ
|
||||
SuXq37yWFX2hqlgt+lsBufZ8RD5QnZc=
|
||||
-----END EC PRIVATE KEY-----
|
||||
10
certbot/certbot/tests/testdata/ec_secp521r1_key.pem
vendored
Normal file
10
certbot/certbot/tests/testdata/ec_secp521r1_key.pem
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
-----BEGIN EC PARAMETERS-----
|
||||
BgUrgQQAIw==
|
||||
-----END EC PARAMETERS-----
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIHcAgEBBEIACWWVKm1qAIejZ6qmqk9D69wQW5FAe3Er0IxWAMkonTEhu8EH5Q2i
|
||||
2vT2bESm730zhGTe2Pn11b85H6UI9hxhCHygBwYFK4EEACOhgYkDgYYABAEQi1WF
|
||||
m3suHjPyWACyOJYGUn1Kx6rfBo0PjC7X2TU9jr8umLkIpaaF5UsBuMBmdz1IHL0U
|
||||
k0gQtoOQ0Qu8N74GuAGzGR0S3RYIv6gfYVz3dS1K4n4b307Lx62bnvtlNxcIvt3w
|
||||
hmS5OdvQ1Kdxh6oqbSVhhbQmJcgab78Txx3R2QeCxw==
|
||||
-----END EC PRIVATE KEY-----
|
||||
18
certbot/certbot/tests/testdata/sample-archive-ec/cert1.pem
vendored
Normal file
18
certbot/certbot/tests/testdata/sample-archive-ec/cert1.pem
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC2zCCAcOgAwIBAgIIBvrEnbPRYu8wDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE
|
||||
AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxMjZjNGIwHhcNMjAxMDEyMjEwNzQw
|
||||
WhcNMjUxMDEyMjEwNzQwWjAjMSEwHwYDVQQDExhjLmVuY3J5cHRpb24tZXhhbXBs
|
||||
ZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARjMhuW0ENPPC33PjB5XsYU
|
||||
CRw640kPQENIDatcTJaENZIZdqKd6rI6jc+lpbmXot7Zi52clJlSJS+V6oDAt2Lh
|
||||
o4HYMIHVMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
|
||||
BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUj7Kd3ENqxlPf8B2bIGhsjydX
|
||||
mPswHwYDVR0jBBgwFoAUEiGxlkRsi+VvcogH5dVD3h1laAcwMQYIKwYBBQUHAQEE
|
||||
JTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAuMC4xOjQwMDIwIwYDVR0RBBww
|
||||
GoIYYy5lbmNyeXB0aW9uLWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQCl
|
||||
k0JXsa8y7fg41WWMDhw60bPW77O0FtOmTcnhdI5daYNemQVk+Q5EMaBLQ/oGjgXd
|
||||
9QXFzXH1PL904YEnSLt+iTpXn++7rQSNzQsdYqw0neWk4f5pEBiN+WORpb6mwobV
|
||||
ifMtBOkNEHvrJ2Pkci9U1lLwtKD/DSew6QtJU5DSkmH1XdGuMJiubygEIvELtvgq
|
||||
cP9S368ZvPmPGmKaJQXBiuaR8MTjY/Bkr79aXQMjKbf+mpn7h0POCcePk1DY/rm6
|
||||
Da+X16lf0hHyQhSUa7Vgyim6rK1/hlw+Z00i+sQCKD9Ih7kXuuGqfSDC33cfO8Tj
|
||||
o/MXO8lcxkrem5zU5QWP
|
||||
-----END CERTIFICATE-----
|
||||
20
certbot/certbot/tests/testdata/sample-archive-ec/chain1.pem
vendored
Normal file
20
certbot/certbot/tests/testdata/sample-archive-ec/chain1.pem
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDUDCCAjigAwIBAgIIbi787yVrcMAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
|
||||
AxMVUGViYmxlIFJvb3QgQ0EgMGM1MjI1MCAXDTIwMTAxMjIwMjI0NloYDzIwNTAx
|
||||
MDEyMjEyMjQ2WjAoMSYwJAYDVQQDEx1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDEy
|
||||
NmM0YjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGeVk1BMJraeqRq
|
||||
mJ2+hgso8VOAv2s2CVxUJjIVcn7f2adE8NyTsSQ1brlsnKCUYUw7yLTQH0izLQRB
|
||||
qKVIDFkUqo5/FuTJ2QlfA2EwBL8J7s/7L7vj3L0DiVpwgxPSyFEwdl/Y5y7ofsX5
|
||||
CIhCFcaMAmTIuKLiSfCJjGwkbEMuolm+lO8Mikxxc/JtDVUC479ugU7PU9O09bMH
|
||||
nm+sD6Bgd+KMoPkCCCoeShJS9X3Ziq9HGc7Z6nhM/zirFARt2XkonEdAZ8br01zY
|
||||
MRiY9txhlWQ7mUkOtzOSoEuYJNoUbvMUf0+tNzto26WRyF7dJmh7lTBsYrvAwUTx
|
||||
PzNyst0CAwEAAaOBgzCBgDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBIhsZZE
|
||||
bIvlb3KIB+XVQ94dZWgHMB8GA1UdIwQYMBaAFOaKTaXg37vKgRt7d79YOjAoAtJT
|
||||
MA0GCSqGSIb3DQEBCwUAA4IBAQAU2mZii7PH2pkw2lNM0QqPbcW/UYyvFoUeM8Aq
|
||||
uCtsI2s+oxCJTqzfLsA0N8NY4nHLQ5wAlNJfJekngni8hbmJTKU4JFTMe7kLQO8P
|
||||
fJbk0pTzhhHVQw7CVwB6Pwq3u2m/JV+d6xDIDc+AVkuEl19ZJU0rTWyooClfFLZV
|
||||
EdZmEiUtA3PGlxoYwYhoGHYlhFxsoFONhCsBEdN7k7FKtFGVxN7oc5SKmKp0YZTW
|
||||
fcrEtrdNThATO4ymhCC2zh33NI/MT1O74fpaAc2k6LcTl57MKiLfTYX4LTL6v9JG
|
||||
9tlNqjFVRRmzEbtXTPcCb+w9g1VqoOGok7mGXYLTYtShCuvE
|
||||
-----END CERTIFICATE-----
|
||||
38
certbot/certbot/tests/testdata/sample-archive-ec/fullchain1.pem
vendored
Normal file
38
certbot/certbot/tests/testdata/sample-archive-ec/fullchain1.pem
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC2zCCAcOgAwIBAgIILlmGtZhUFEwwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE
|
||||
AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxMjZjNGIwHhcNMjAxMDEyMjA1MDM0
|
||||
WhcNMjUxMDEyMjA1MDM0WjAjMSEwHwYDVQQDExhjLmVuY3J5cHRpb24tZXhhbXBs
|
||||
ZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARHEzR8JPWrEmpmgM+F2bk5
|
||||
9mT0u6CjzmJG0QpbaqprLiG5NGpW84VQ5TFCrmC4KxYfigCfMhfHRNfFYvNUK3V/
|
||||
o4HYMIHVMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
|
||||
BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU1CsVL+bPnzaxxQ5jUENmQJIO
|
||||
lKwwHwYDVR0jBBgwFoAUEiGxlkRsi+VvcogH5dVD3h1laAcwMQYIKwYBBQUHAQEE
|
||||
JTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAuMC4xOjQwMDIwIwYDVR0RBBww
|
||||
GoIYYy5lbmNyeXB0aW9uLWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBn
|
||||
2D8loC7pfk28JYpFLr5lmFKJWWmtLGlpsWDj61fVjtTfGKLziJz+MM6il4Y3hIz5
|
||||
58qiFK0ue0M63dIBJ33N+XxSEXon4Q0gy/zRWfH9jtPJ3FwfjkU/RT9PAUClYi0G
|
||||
ptNWnTmgQkNzousbcAtRNXuuShH3856vhUnwkX+xM+cbIDi1JVmFjcGrEEQJ0rUF
|
||||
mv2ZTyfbWbUs3v4rReETi2NVzr1Ql6J+ByNcMvHODzFy3t0L6yelAw2ca1I+c9HU
|
||||
+Z0tnp/ykR7eXNuVLivok8UBf5OC413lh8ZO5g+Bgzh/LdtkUuavg1MYtEX0H6mX
|
||||
9U7y3nVI8WEbPGf+HDeu
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDUDCCAjigAwIBAgIIbi787yVrcMAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
|
||||
AxMVUGViYmxlIFJvb3QgQ0EgMGM1MjI1MCAXDTIwMTAxMjIwMjI0NloYDzIwNTAx
|
||||
MDEyMjEyMjQ2WjAoMSYwJAYDVQQDEx1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDEy
|
||||
NmM0YjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGeVk1BMJraeqRq
|
||||
mJ2+hgso8VOAv2s2CVxUJjIVcn7f2adE8NyTsSQ1brlsnKCUYUw7yLTQH0izLQRB
|
||||
qKVIDFkUqo5/FuTJ2QlfA2EwBL8J7s/7L7vj3L0DiVpwgxPSyFEwdl/Y5y7ofsX5
|
||||
CIhCFcaMAmTIuKLiSfCJjGwkbEMuolm+lO8Mikxxc/JtDVUC479ugU7PU9O09bMH
|
||||
nm+sD6Bgd+KMoPkCCCoeShJS9X3Ziq9HGc7Z6nhM/zirFARt2XkonEdAZ8br01zY
|
||||
MRiY9txhlWQ7mUkOtzOSoEuYJNoUbvMUf0+tNzto26WRyF7dJmh7lTBsYrvAwUTx
|
||||
PzNyst0CAwEAAaOBgzCBgDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBIhsZZE
|
||||
bIvlb3KIB+XVQ94dZWgHMB8GA1UdIwQYMBaAFOaKTaXg37vKgRt7d79YOjAoAtJT
|
||||
MA0GCSqGSIb3DQEBCwUAA4IBAQAU2mZii7PH2pkw2lNM0QqPbcW/UYyvFoUeM8Aq
|
||||
uCtsI2s+oxCJTqzfLsA0N8NY4nHLQ5wAlNJfJekngni8hbmJTKU4JFTMe7kLQO8P
|
||||
fJbk0pTzhhHVQw7CVwB6Pwq3u2m/JV+d6xDIDc+AVkuEl19ZJU0rTWyooClfFLZV
|
||||
EdZmEiUtA3PGlxoYwYhoGHYlhFxsoFONhCsBEdN7k7FKtFGVxN7oc5SKmKp0YZTW
|
||||
fcrEtrdNThATO4ymhCC2zh33NI/MT1O74fpaAc2k6LcTl57MKiLfTYX4LTL6v9JG
|
||||
9tlNqjFVRRmzEbtXTPcCb+w9g1VqoOGok7mGXYLTYtShCuvE
|
||||
-----END CERTIFICATE-----
|
||||
5
certbot/certbot/tests/testdata/sample-archive-ec/privkey1.pem
vendored
Normal file
5
certbot/certbot/tests/testdata/sample-archive-ec/privkey1.pem
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNgefv2dad4U1VYEi
|
||||
0WkdHuqywi5QXAe30OwNTTGjhbihRANCAARHEzR8JPWrEmpmgM+F2bk59mT0u6Cj
|
||||
zmJG0QpbaqprLiG5NGpW84VQ5TFCrmC4KxYfigCfMhfHRNfFYvNUK3V/
|
||||
-----END PRIVATE KEY-----
|
||||
79
certbot/certbot/tests/testdata/sample-renewal-ec.conf
vendored
Normal file
79
certbot/certbot/tests/testdata/sample-renewal-ec.conf
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
# add some stuff here
|
||||
# assets/integration_tests
|
||||
|
||||
cert = MAGICDIR/live/sample-renewal-ec/cert.pem
|
||||
privkey = MAGICDIR/live/sample-renewal-ec/privkey.pem
|
||||
chain = MAGICDIR/live/sample-renewal-ec/chain.pem
|
||||
fullchain = MAGICDIR/live/sample-renewal-ec/fullchain.pem
|
||||
renew_before_expiry = 4 years
|
||||
|
||||
# Options and defaults used in the renewal process
|
||||
[renewalparams]
|
||||
no_self_upgrade = False
|
||||
apache_enmod = a2enmod
|
||||
no_verify_ssl = False
|
||||
ifaces = None
|
||||
apache_dismod = a2dismod
|
||||
register_unsafely_without_email = False
|
||||
apache_handle_modules = True
|
||||
uir = None
|
||||
installer = None
|
||||
nginx_ctl = nginx
|
||||
config_dir = MAGICDIR
|
||||
text_mode = False
|
||||
func = <function obtain_cert at 0x7f093a163c08>
|
||||
staging = True
|
||||
prepare = False
|
||||
work_dir = /var/lib/letsencrypt
|
||||
tos = False
|
||||
init = False
|
||||
http01_port = 80
|
||||
duplicate = False
|
||||
noninteractive_mode = True
|
||||
key_path = None
|
||||
nginx = False
|
||||
nginx_server_root = /etc/nginx
|
||||
fullchain_path = /home/ubuntu/letsencrypt/chain.pem
|
||||
email = None
|
||||
csr = None
|
||||
agree_dev_preview = None
|
||||
redirect = None
|
||||
verb = certonly
|
||||
verbose_count = -3
|
||||
config_file = None
|
||||
renew_by_default = False
|
||||
hsts = False
|
||||
apache_handle_sites = True
|
||||
authenticator = standalone
|
||||
domains = isnot.org,
|
||||
key_type = ecdsa
|
||||
elliptic_curve = secp256r1
|
||||
apache_challenge_location = /etc/apache2
|
||||
checkpoints = 1
|
||||
manual_test_mode = False
|
||||
apache = False
|
||||
cert_path = /home/ubuntu/letsencrypt/cert.pem
|
||||
webroot_path = None
|
||||
reinstall = False
|
||||
expand = False
|
||||
strict_permissions = False
|
||||
apache_server_root = /etc/apache2
|
||||
account = None
|
||||
dry_run = False
|
||||
manual_public_ip_logging_ok = False
|
||||
chain_path = /home/ubuntu/letsencrypt/chain.pem
|
||||
break_my_certs = False
|
||||
standalone = True
|
||||
manual = False
|
||||
server = https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
webroot = False
|
||||
os_packages_only = False
|
||||
apache_init_script = None
|
||||
user_agent = None
|
||||
apache_le_vhost_ext = -le-ssl.conf
|
||||
debug = False
|
||||
logs_dir = /var/log/letsencrypt
|
||||
apache_vhost_root = /etc/apache2/sites-available
|
||||
configurator = None
|
||||
must_staple = True
|
||||
[[webroot_map]]
|
||||
@@ -44,6 +44,7 @@ apache_handle_sites = True
|
||||
authenticator = standalone
|
||||
domains = isnot.org,
|
||||
rsa_key_size = 2048
|
||||
elliptic_curve = secp256r1
|
||||
apache_challenge_location = /etc/apache2
|
||||
checkpoints = 1
|
||||
manual_test_mode = False
|
||||
|
||||
@@ -93,7 +93,7 @@ def load_pyopenssl_private_key(*names):
|
||||
return OpenSSL.crypto.load_privatekey(loader, load_vector(*names))
|
||||
|
||||
|
||||
def make_lineage(config_dir, testfile):
|
||||
def make_lineage(config_dir, testfile, ec=False):
|
||||
"""Creates a lineage defined by testfile.
|
||||
|
||||
This creates the archive, live, and renewal directories if
|
||||
@@ -119,7 +119,7 @@ def make_lineage(config_dir, testfile):
|
||||
if not os.path.exists(directory):
|
||||
filesystem.makedirs(directory)
|
||||
|
||||
sample_archive = vector_path('sample-archive')
|
||||
sample_archive = vector_path('sample-archive{}'.format('-ec' if ec else ''))
|
||||
for kind in os.listdir(sample_archive):
|
||||
shutil.copyfile(os.path.join(sample_archive, kind),
|
||||
os.path.join(archive_dir, kind))
|
||||
|
||||
@@ -80,8 +80,8 @@ its preferences in accordance with its own policy or its administrators'
|
||||
preferences, and use different cryptographic mechanisms or parameters,
|
||||
or a different priority order, than the defaults provided by Certbot.
|
||||
|
||||
If you don't use Certbot to configure your server directly, because the
|
||||
client doesn't integrate with your server software or because you chose
|
||||
If you don't use Certbot to configure your server directly, because the
|
||||
client doesn't integrate with your server software or because you chose
|
||||
not to use this integration, then the cryptographic defaults haven't been
|
||||
modified, and the cryptography chosen by the server will still be whatever
|
||||
the default for your software was. For example, if you obtain a
|
||||
@@ -254,7 +254,7 @@ https://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-secur
|
||||
U.S. Government 18F
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The 18F site (https://18f.gsa.gov/) is using
|
||||
The 18F site (https://18f.gsa.gov/) is using
|
||||
|
||||
::
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
usage:
|
||||
usage:
|
||||
certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...
|
||||
|
||||
Certbot can obtain and install HTTPS/TLS/SSL certificates. By default,
|
||||
@@ -188,6 +188,12 @@ security:
|
||||
Security parameters & server settings
|
||||
|
||||
--rsa-key-size N Size of the RSA key. (default: 2048)
|
||||
--key-type type The type of algorithm to use for the the private key.
|
||||
Either ``rsa`` or ``ecdsa``. (default: ``rsa``).
|
||||
--elliptic-curve The elliptic curve to use when choosing ``ecdsa`` as the key
|
||||
type. Accepted values are SECG curve names as defined by
|
||||
the cryptography library. ``secp256r1``, ``secp384r1``,
|
||||
``secp521r1``. (default: secp256r1).
|
||||
--must-staple Adds the OCSP Must Staple extension to the
|
||||
certificate. Autoconfigures OCSP Stapling for
|
||||
supported setups (Apache version >= 2.3.3 ). (default:
|
||||
|
||||
@@ -375,6 +375,9 @@ The script used to generate the snapcraft.yaml files for our own externally
|
||||
snapped plugins can be found at
|
||||
https://github.com/certbot/certbot/blob/master/tools/snap/generate_dnsplugins_snapcraft.sh.
|
||||
|
||||
For more information on building externally snapped plugins, see the section on
|
||||
:ref:`Building snaps`.
|
||||
|
||||
Once you have created your own snap, if you have the snap file locally,
|
||||
it can be installed for use with Certbot by running:
|
||||
|
||||
@@ -534,6 +537,15 @@ Use of EFFOSCCP is subject to the `EFF Code of Conduct
|
||||
<https://www.eff.org/pages/eppcode>`_. When investigating an alleged Code of
|
||||
Conduct violation, EFF may review discussion channels or direct messages.
|
||||
|
||||
.. _Building snaps:
|
||||
|
||||
Building the Certbot and DNS plugin snaps
|
||||
=========================================
|
||||
|
||||
Instructions for how to manually build and run the Certbot snap and the externally
|
||||
snapped DNS plugins that the Certbot project supplies are located in the README
|
||||
file at https://github.com/certbot/certbot/tree/master/tools/snap.
|
||||
|
||||
Updating certbot-auto and letsencrypt-auto
|
||||
==========================================
|
||||
|
||||
|
||||
@@ -191,6 +191,7 @@ Once installed, you can find documentation on how to use each plugin at:
|
||||
* `certbot-dns-digitalocean <https://certbot-dns-digitalocean.readthedocs.io>`_
|
||||
* `certbot-dns-dnsimple <https://certbot-dns-dnsimple.readthedocs.io>`_
|
||||
* `certbot-dns-dnsmadeeasy <https://certbot-dns-dnsmadeeasy.readthedocs.io>`_
|
||||
* `certbot-dns-gehirn <https://certbot-dns-gehirn.readthedocs.io>`_
|
||||
* `certbot-dns-google <https://certbot-dns-google.readthedocs.io>`_
|
||||
* `certbot-dns-linode <https://certbot-dns-linode.readthedocs.io>`_
|
||||
* `certbot-dns-luadns <https://certbot-dns-luadns.readthedocs.io>`_
|
||||
@@ -198,6 +199,7 @@ Once installed, you can find documentation on how to use each plugin at:
|
||||
* `certbot-dns-ovh <https://certbot-dns-ovh.readthedocs.io>`_
|
||||
* `certbot-dns-rfc2136 <https://certbot-dns-rfc2136.readthedocs.io>`_
|
||||
* `certbot-dns-route53 <https://certbot-dns-route53.readthedocs.io>`_
|
||||
* `certbot-dns-sakuracloud <https://certbot-dns-sakuracloud.readthedocs.io>`_
|
||||
|
||||
Manual
|
||||
------
|
||||
@@ -317,6 +319,7 @@ This returns information in the following format::
|
||||
Domains: example.com, www.example.com
|
||||
Expiry Date: 2017-02-19 19:53:00+00:00 (VALID: 30 days)
|
||||
Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
|
||||
Key Type: RSA
|
||||
Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem
|
||||
|
||||
``Certificate Name`` shows the name of the certificate. Pass this name
|
||||
@@ -344,7 +347,6 @@ control Certbot's behavior when re-creating
|
||||
a certificate with the same name as an existing certificate.
|
||||
If you don't specify a requested behavior, Certbot may ask you what you intended.
|
||||
|
||||
|
||||
``--force-renewal`` tells Certbot to request a new certificate
|
||||
with the same domains as an existing certificate. Each domain
|
||||
must be explicitly specified via ``-d``. If successful, this certificate
|
||||
@@ -378,7 +380,6 @@ If you prefer, you can specify the domains individually like this:
|
||||
Consider using ``--cert-name`` instead of ``--expand``, as it gives more control
|
||||
over which certificate is modified and it lets you remove domains as well as adding them.
|
||||
|
||||
|
||||
``--allow-subset-of-names`` tells Certbot to continue with certificate generation if
|
||||
only some of the specified domain authorizations can be obtained. This may
|
||||
be useful if some domains specified in a certificate no longer point at this
|
||||
@@ -409,6 +410,19 @@ replace that set entirely::
|
||||
certbot certonly --cert-name example.com -d example.org,www.example.org
|
||||
|
||||
|
||||
Migrating to certificates based on ECDSA keys
|
||||
---------------------------------------------
|
||||
|
||||
As of version 1.10, Certbot supports two types of private key algorithms:
|
||||
``rsa`` and ``ecdsa``. You may freely upgrade an existing certificate with a
|
||||
new private key. This requires issuing a new command, or changing the renewal
|
||||
file for the certificates so it will happen on the next renewal. The two
|
||||
options that you need for the renewal command are ``--key-type`` and
|
||||
``--elliptic-curve <name>`` in case you either want to be explicit or want to
|
||||
use something else than the default curve ``secp256r1``::
|
||||
|
||||
certbot renew --key-type ecdsa --cert-name example.com -d example.org,www.example.org
|
||||
|
||||
Revoking certificates
|
||||
---------------------
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
# certificate on a system with several certificates should not be placed
|
||||
# here.
|
||||
|
||||
# Use ECC for the private key
|
||||
key-type = ecdsa
|
||||
elliptic-curve = secp384r1
|
||||
|
||||
# Use a 4096 bit RSA key instead of 2048
|
||||
rsa-key-size = 4096
|
||||
|
||||
|
||||
@@ -83,24 +83,6 @@ class MetaTest(unittest.TestCase):
|
||||
self.assertIsNotNone(meta.creation_host)
|
||||
self.assertIsNotNone(meta.register_to_eff)
|
||||
|
||||
class ReportNewAccountTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot._internal.account.report_new_account."""
|
||||
|
||||
def _call(self):
|
||||
from certbot._internal.account import report_new_account
|
||||
report_new_account(self.config)
|
||||
|
||||
@mock.patch("certbot._internal.account.zope.component.queryUtility")
|
||||
def test_no_reporter(self, mock_zope):
|
||||
mock_zope.return_value = None
|
||||
self._call()
|
||||
|
||||
@mock.patch("certbot._internal.account.zope.component.queryUtility")
|
||||
def test_it(self, mock_zope):
|
||||
self._call()
|
||||
call_list = mock_zope().add_message.call_args_list
|
||||
self.assertTrue(self.config.config_dir in call_list[0][0][0])
|
||||
|
||||
|
||||
class AccountMemoryStorageTest(unittest.TestCase):
|
||||
"""Tests for certbot._internal.account.AccountMemoryStorage."""
|
||||
|
||||
@@ -359,6 +359,21 @@ class ParseTest(unittest.TestCase):
|
||||
self.assertFalse(cli.option_was_set(
|
||||
'authenticator', cli.flag_default('authenticator')))
|
||||
|
||||
def test_ecdsa_key_option(self):
|
||||
elliptic_curve_option = 'elliptic_curve'
|
||||
elliptic_curve_option_value = cli.flag_default(elliptic_curve_option)
|
||||
self.parse('--elliptic-curve {0}'.format(elliptic_curve_option_value).split())
|
||||
self.assertIs(cli.option_was_set(elliptic_curve_option, elliptic_curve_option_value), True)
|
||||
|
||||
def test_invalid_key_type(self):
|
||||
key_type_option = 'key_type'
|
||||
key_type_value = cli.flag_default(key_type_option)
|
||||
self.parse('--key-type {0}'.format(key_type_value).split())
|
||||
self.assertIs(cli.option_was_set(key_type_option, key_type_value), True)
|
||||
|
||||
with self.assertRaises(SystemExit):
|
||||
self.parse("--key-type foo")
|
||||
|
||||
def test_encode_revocation_reason(self):
|
||||
for reason, code in constants.REVOCATION_REASONS.items():
|
||||
namespace = self.parse(['--reason', reason])
|
||||
@@ -505,43 +520,6 @@ class SetByCliTest(unittest.TestCase):
|
||||
verb = 'renew'
|
||||
self.assertTrue(_call_set_by_cli('webroot_map', args, verb))
|
||||
|
||||
def test_report_config_interaction_str(self):
|
||||
cli.report_config_interaction('manual_public_ip_logging_ok',
|
||||
'manual_auth_hook')
|
||||
cli.report_config_interaction('manual_auth_hook', 'manual')
|
||||
|
||||
self._test_report_config_interaction_common()
|
||||
|
||||
def test_report_config_interaction_iterable(self):
|
||||
cli.report_config_interaction(('manual_public_ip_logging_ok',),
|
||||
('manual_auth_hook',))
|
||||
cli.report_config_interaction(('manual_auth_hook',), ('manual',))
|
||||
|
||||
self._test_report_config_interaction_common()
|
||||
|
||||
def _test_report_config_interaction_common(self):
|
||||
"""Tests implied interaction between manual flags.
|
||||
|
||||
--manual implies --manual-auth-hook which implies
|
||||
--manual-public-ip-logging-ok. These interactions don't actually
|
||||
exist in the client, but are used here for testing purposes.
|
||||
|
||||
"""
|
||||
|
||||
args = ['--manual']
|
||||
verb = 'renew'
|
||||
for v in ('manual', 'manual_auth_hook', 'manual_public_ip_logging_ok'):
|
||||
self.assertTrue(_call_set_by_cli(v, args, verb))
|
||||
|
||||
# https://github.com/python/mypy/issues/2087
|
||||
cli.set_by_cli.detector = None # type: ignore
|
||||
|
||||
args = ['--manual-auth-hook', 'command']
|
||||
for v in ('manual_auth_hook', 'manual_public_ip_logging_ok'):
|
||||
self.assertTrue(_call_set_by_cli(v, args, verb))
|
||||
|
||||
self.assertFalse(_call_set_by_cli('manual', args, verb))
|
||||
|
||||
|
||||
def _call_set_by_cli(var, args, verb):
|
||||
with mock.patch('certbot._internal.cli.helpful_parser') as mock_parser:
|
||||
|
||||
@@ -93,25 +93,22 @@ class RegisterTest(test_util.ConfigTestCase):
|
||||
mock_client.new_account_and_tos().terms_of_service = "http://tos"
|
||||
mock_client().external_account_required.side_effect = self._false_mock
|
||||
with mock.patch("certbot._internal.eff.prepare_subscription") as mock_prepare:
|
||||
with mock.patch("certbot._internal.account.report_new_account"):
|
||||
mock_client().new_account_and_tos.side_effect = errors.Error
|
||||
self.assertRaises(errors.Error, self._call)
|
||||
self.assertFalse(mock_prepare.called)
|
||||
mock_client().new_account_and_tos.side_effect = errors.Error
|
||||
self.assertRaises(errors.Error, self._call)
|
||||
self.assertFalse(mock_prepare.called)
|
||||
|
||||
mock_client().new_account_and_tos.side_effect = None
|
||||
self._call()
|
||||
self.assertTrue(mock_prepare.called)
|
||||
mock_client().new_account_and_tos.side_effect = None
|
||||
self._call()
|
||||
self.assertTrue(mock_prepare.called)
|
||||
|
||||
def test_it(self):
|
||||
with mock.patch("certbot._internal.client.acme_client.BackwardsCompatibleClientV2") as mock_client:
|
||||
mock_client().external_account_required.side_effect = self._false_mock
|
||||
with mock.patch("certbot._internal.account.report_new_account"):
|
||||
with mock.patch("certbot._internal.eff.handle_subscription"):
|
||||
self._call()
|
||||
with mock.patch("certbot._internal.eff.handle_subscription"):
|
||||
self._call()
|
||||
|
||||
@mock.patch("certbot._internal.account.report_new_account")
|
||||
@mock.patch("certbot._internal.client.display_ops.get_email")
|
||||
def test_email_retry(self, _rep, mock_get_email):
|
||||
def test_email_retry(self, mock_get_email):
|
||||
from acme import messages
|
||||
self.config.noninteractive_mode = False
|
||||
msg = "DNS problem: NXDOMAIN looking up MX for example.com"
|
||||
@@ -124,8 +121,7 @@ class RegisterTest(test_util.ConfigTestCase):
|
||||
self.assertEqual(mock_get_email.call_count, 1)
|
||||
self.assertTrue(mock_prepare.called)
|
||||
|
||||
@mock.patch("certbot._internal.account.report_new_account")
|
||||
def test_email_invalid_noninteractive(self, _rep):
|
||||
def test_email_invalid_noninteractive(self):
|
||||
from acme import messages
|
||||
self.config.noninteractive_mode = True
|
||||
msg = "DNS problem: NXDOMAIN looking up MX for example.com"
|
||||
@@ -145,28 +141,25 @@ class RegisterTest(test_util.ConfigTestCase):
|
||||
with mock.patch("certbot._internal.eff.prepare_subscription") as mock_prepare:
|
||||
with mock.patch("certbot._internal.client.acme_client.BackwardsCompatibleClientV2") as mock_clnt:
|
||||
mock_clnt().external_account_required.side_effect = self._false_mock
|
||||
with mock.patch("certbot._internal.account.report_new_account"):
|
||||
self.config.email = None
|
||||
self.config.register_unsafely_without_email = True
|
||||
self.config.dry_run = False
|
||||
self._call()
|
||||
mock_logger.info.assert_called_once_with(mock.ANY)
|
||||
self.assertTrue(mock_prepare.called)
|
||||
self.config.email = None
|
||||
self.config.register_unsafely_without_email = True
|
||||
self.config.dry_run = False
|
||||
self._call()
|
||||
mock_logger.debug.assert_called_once_with(mock.ANY)
|
||||
self.assertTrue(mock_prepare.called)
|
||||
|
||||
@mock.patch("certbot._internal.account.report_new_account")
|
||||
@mock.patch("certbot._internal.client.display_ops.get_email")
|
||||
def test_dry_run_no_staging_account(self, _rep, mock_get_email):
|
||||
def test_dry_run_no_staging_account(self, mock_get_email):
|
||||
"""Tests dry-run for no staging account, expect account created with no email"""
|
||||
with mock.patch("certbot._internal.client.acme_client.BackwardsCompatibleClientV2") as mock_client:
|
||||
mock_client().external_account_required.side_effect = self._false_mock
|
||||
with mock.patch("certbot._internal.eff.handle_subscription"):
|
||||
with mock.patch("certbot._internal.account.report_new_account"):
|
||||
self.config.dry_run = True
|
||||
self._call()
|
||||
# check Certbot did not ask the user to provide an email
|
||||
self.assertFalse(mock_get_email.called)
|
||||
# check Certbot created an account with no email. Contact should return empty
|
||||
self.assertFalse(mock_client().new_account_and_tos.call_args[0][0].contact)
|
||||
self.config.dry_run = True
|
||||
self._call()
|
||||
# check Certbot did not ask the user to provide an email
|
||||
self.assertFalse(mock_get_email.called)
|
||||
# check Certbot created an account with no email. Contact should return empty
|
||||
self.assertFalse(mock_client().new_account_and_tos.call_args[0][0].contact)
|
||||
|
||||
def test_with_eab_arguments(self):
|
||||
with mock.patch("certbot._internal.client.acme_client.BackwardsCompatibleClientV2") as mock_client:
|
||||
@@ -336,7 +329,11 @@ class ClientTest(ClientTestCommon):
|
||||
self._test_obtain_certificate_common(mock.sentinel.key, csr)
|
||||
|
||||
mock_crypto_util.init_save_key.assert_called_once_with(
|
||||
self.config.rsa_key_size, self.config.key_dir)
|
||||
key_size=self.config.rsa_key_size,
|
||||
key_dir=self.config.key_dir,
|
||||
key_type=self.config.key_type,
|
||||
elliptic_curve=None, # elliptic curve is not set
|
||||
)
|
||||
mock_crypto_util.init_save_csr.assert_called_once_with(
|
||||
mock.sentinel.key, self.eg_domains, self.config.csr_dir)
|
||||
mock_crypto_util.cert_and_chain_from_fullchain.assert_called_once_with(
|
||||
@@ -372,7 +369,11 @@ class ClientTest(ClientTestCommon):
|
||||
self.client.config.dry_run = True
|
||||
self._test_obtain_certificate_common(key, csr)
|
||||
|
||||
mock_crypto.make_key.assert_called_once_with(self.config.rsa_key_size)
|
||||
mock_crypto.make_key.assert_called_once_with(
|
||||
bits=self.config.rsa_key_size,
|
||||
elliptic_curve=None, # not making an elliptic private key
|
||||
key_type=self.config.key_type,
|
||||
)
|
||||
mock_acme_crypto.make_csr.assert_called_once_with(
|
||||
mock.sentinel.key_pem, self.eg_domains, self.config.must_staple)
|
||||
mock_crypto.init_save_key.assert_not_called()
|
||||
|
||||
@@ -4,7 +4,7 @@ import unittest
|
||||
|
||||
try:
|
||||
import mock
|
||||
except ImportError: # pragma: no cover
|
||||
except ImportError: # pragma: no cover
|
||||
from unittest import mock
|
||||
import OpenSSL
|
||||
import zope.component
|
||||
@@ -32,6 +32,7 @@ CERT_LEAF = test_util.load_vector('cert_leaf.pem')
|
||||
CERT_ISSUER = test_util.load_vector('cert_intermediate_1.pem')
|
||||
CERT_ALT_ISSUER = test_util.load_vector('cert_intermediate_2.pem')
|
||||
|
||||
|
||||
class InitSaveKeyTest(test_util.TempDirTestCase):
|
||||
"""Tests for certbot.crypto_util.init_save_key."""
|
||||
def setUp(self):
|
||||
@@ -174,11 +175,54 @@ class ImportCSRFileTest(unittest.TestCase):
|
||||
class MakeKeyTest(unittest.TestCase):
|
||||
"""Tests for certbot.crypto_util.make_key."""
|
||||
|
||||
def test_it(self): # pylint: disable=no-self-use
|
||||
def test_rsa(self): # pylint: disable=no-self-use
|
||||
# RSA Key Type Test
|
||||
from certbot.crypto_util import make_key
|
||||
# Do not test larger keys as it takes too long.
|
||||
OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, make_key(1024))
|
||||
|
||||
def test_ec(self): # pylint: disable=no-self-use
|
||||
# ECDSA Key Type Tests
|
||||
from certbot.crypto_util import make_key
|
||||
# Do not test larger keys as it takes too long.
|
||||
|
||||
# Try a good key size for ECDSA
|
||||
OpenSSL.crypto.load_privatekey(
|
||||
OpenSSL.crypto.FILETYPE_PEM, make_key(1024))
|
||||
OpenSSL.crypto.FILETYPE_PEM, make_key(elliptic_curve="secp256r1", key_type='ecdsa'))
|
||||
|
||||
def test_bad_key_sizes(self):
|
||||
from certbot.crypto_util import make_key
|
||||
# Try a bad key size for RSA and ECDSA
|
||||
with self.assertRaises(errors.Error) as e:
|
||||
make_key(bits=512, key_type='rsa')
|
||||
self.assertEqual(
|
||||
"Unsupported RSA key length: 512",
|
||||
str(e.exception),
|
||||
"Unsupported RSA key length: 512"
|
||||
)
|
||||
|
||||
def test_bad_elliptic_curve_name(self):
|
||||
from certbot.crypto_util import make_key
|
||||
with self.assertRaises(errors.Error) as e:
|
||||
make_key(elliptic_curve="nothere", key_type='ecdsa')
|
||||
self.assertEqual(
|
||||
"Unsupported elliptic curve: nothere",
|
||||
str(e.exception),
|
||||
"Unsupported elliptic curve: nothere"
|
||||
)
|
||||
|
||||
def test_bad_key_type(self):
|
||||
from certbot.crypto_util import make_key
|
||||
|
||||
# Try a bad --key-type
|
||||
with self.assertRaises(errors.Error) as e:
|
||||
OpenSSL.crypto.load_privatekey(
|
||||
OpenSSL.crypto.FILETYPE_PEM, make_key(1024, key_type='unf'))
|
||||
self.assertEqual(
|
||||
"Invalid key_type specified: unf. Use [rsa|ecdsa]",
|
||||
str(e.exception),
|
||||
"Invalid key_type specified: unf. Use [rsa|ecdsa]",
|
||||
)
|
||||
|
||||
|
||||
class VerifyCertSetup(unittest.TestCase):
|
||||
|
||||
@@ -49,14 +49,47 @@ RSA2048_KEY_PATH = test_util.vector_path('rsa2048_key.pem')
|
||||
SS_CERT_PATH = test_util.vector_path('cert_2048.pem')
|
||||
|
||||
|
||||
class TestHandleIdenticalCerts(unittest.TestCase):
|
||||
"""Test for certbot._internal.main._handle_identical_cert_request"""
|
||||
def test_handle_identical_cert_request_pending(self):
|
||||
class TestHandleCerts(unittest.TestCase):
|
||||
"""Test for certbot._internal.main._handle_* methods"""
|
||||
@mock.patch("certbot._internal.main._handle_unexpected_key_type_migration")
|
||||
def test_handle_identical_cert_request_pending(self, mock_handle_migration):
|
||||
mock_lineage = mock.Mock()
|
||||
mock_lineage.ensure_deployed.return_value = False
|
||||
# pylint: disable=protected-access
|
||||
ret = main._handle_identical_cert_request(mock.Mock(), mock_lineage)
|
||||
self.assertEqual(ret, ("reinstall", mock_lineage))
|
||||
self.assertTrue(mock_handle_migration.called)
|
||||
|
||||
@mock.patch("certbot._internal.main._handle_unexpected_key_type_migration")
|
||||
def test_handle_subset_cert_request(self, mock_handle_migration):
|
||||
mock_config = mock.Mock()
|
||||
mock_config.expand = True
|
||||
mock_lineage = mock.Mock()
|
||||
mock_lineage.names.return_value = ["dummy1", "dummy2"]
|
||||
ret = main._handle_subset_cert_request(mock_config, ["dummy1"], mock_lineage)
|
||||
self.assertEqual(ret, ("renew", mock_lineage))
|
||||
self.assertTrue(mock_handle_migration.called)
|
||||
|
||||
@mock.patch("certbot._internal.main.cli.set_by_cli")
|
||||
def test_handle_unexpected_key_type_migration(self, mock_set):
|
||||
config = mock.Mock()
|
||||
config.verb = "certonly"
|
||||
config.key_type = "rsa"
|
||||
cert = mock.Mock()
|
||||
cert.private_key_type = "ecdsa"
|
||||
|
||||
mock_set.return_value = True
|
||||
main._handle_unexpected_key_type_migration(config, cert)
|
||||
|
||||
mock_set.return_value = False
|
||||
with self.assertRaises(errors.Error) as raised:
|
||||
main._handle_unexpected_key_type_migration(config, cert)
|
||||
self.assertTrue("Command canceled." in str(raised.exception))
|
||||
|
||||
mock_set.side_effect = lambda var: var != "key_type"
|
||||
with self.assertRaises(errors.Error) as raised:
|
||||
main._handle_unexpected_key_type_migration(config, cert)
|
||||
self.assertTrue("Command canceled." in str(raised.exception))
|
||||
|
||||
|
||||
class RunTest(test_util.ConfigTestCase):
|
||||
@@ -163,9 +196,10 @@ class CertonlyTest(unittest.TestCase):
|
||||
@mock.patch('certbot._internal.cert_manager.lineage_for_certname')
|
||||
@mock.patch('certbot._internal.cert_manager.domains_for_certname')
|
||||
@mock.patch('certbot._internal.renewal.renew_cert')
|
||||
@mock.patch('certbot._internal.main._handle_unexpected_key_type_migration')
|
||||
@mock.patch('certbot._internal.main._report_new_cert')
|
||||
def test_find_lineage_for_domains_and_certname(self, mock_report_cert,
|
||||
mock_renew_cert, mock_domains, mock_lineage):
|
||||
mock_handle_type, mock_renew_cert, mock_domains, mock_lineage):
|
||||
domains = ['example.com', 'test.org']
|
||||
mock_domains.return_value = domains
|
||||
mock_lineage.names.return_value = domains
|
||||
@@ -175,6 +209,7 @@ class CertonlyTest(unittest.TestCase):
|
||||
self.assertTrue(mock_domains.call_count == 1)
|
||||
self.assertTrue(mock_renew_cert.call_count == 1)
|
||||
self.assertTrue(mock_report_cert.call_count == 1)
|
||||
self.assertTrue(mock_handle_type.call_count == 1)
|
||||
|
||||
# user confirms updating lineage with new domains
|
||||
self._call(('certonly --webroot -d example.com -d test.com '
|
||||
@@ -183,11 +218,12 @@ class CertonlyTest(unittest.TestCase):
|
||||
self.assertTrue(mock_domains.call_count == 2)
|
||||
self.assertTrue(mock_renew_cert.call_count == 2)
|
||||
self.assertTrue(mock_report_cert.call_count == 2)
|
||||
self.assertTrue(mock_handle_type.call_count == 2)
|
||||
|
||||
# error in _ask_user_to_confirm_new_names
|
||||
self.mock_get_utility().yesno.return_value = False
|
||||
self.assertRaises(errors.ConfigurationError, self._call,
|
||||
('certonly --webroot -d example.com -d test.com --cert-name example.com').split())
|
||||
'certonly --webroot -d example.com -d test.com --cert-name example.com'.split())
|
||||
|
||||
@mock.patch('certbot._internal.cert_manager.domains_for_certname')
|
||||
@mock.patch('certbot.display.ops.choose_names')
|
||||
@@ -481,7 +517,8 @@ class DetermineAccountTest(test_util.ConfigTestCase):
|
||||
self.assertTrue(self.config.email is None)
|
||||
|
||||
@mock.patch('certbot._internal.client.display_ops.get_email')
|
||||
def test_no_accounts_no_email(self, mock_get_email):
|
||||
@mock.patch('certbot._internal.main.logger')
|
||||
def test_no_accounts_no_email(self, mock_logger, mock_get_email):
|
||||
mock_get_email.return_value = 'foo@bar.baz'
|
||||
|
||||
with mock.patch('certbot._internal.main.client') as client:
|
||||
@@ -493,6 +530,7 @@ class DetermineAccountTest(test_util.ConfigTestCase):
|
||||
|
||||
self.assertEqual(self.accs[0].id, self.config.account)
|
||||
self.assertEqual('foo@bar.baz', self.config.email)
|
||||
mock_logger.info.assert_called_once_with('Account registered.')
|
||||
|
||||
def test_no_accounts_email(self):
|
||||
self.config.email = 'other email'
|
||||
@@ -980,6 +1018,7 @@ class MainTest(test_util.ConfigTestCase):
|
||||
mock_lineage.should_autorenew.return_value = due_for_renewal
|
||||
mock_lineage.has_pending_deployment.return_value = False
|
||||
mock_lineage.names.return_value = ['isnot.org']
|
||||
mock_lineage.private_key_type = 'RSA'
|
||||
mock_certr = mock.MagicMock()
|
||||
mock_key = mock.MagicMock(pem='pem_key')
|
||||
mock_client = mock.MagicMock()
|
||||
@@ -1279,13 +1318,16 @@ class MainTest(test_util.ConfigTestCase):
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch('certbot._internal.main._find_lineage_for_domains_and_certname')
|
||||
@mock.patch('certbot._internal.main._init_le_client')
|
||||
def test_certonly_reinstall(self, mock_init, mock_renewal, mock_get_utility):
|
||||
@mock.patch('certbot._internal.main._report_new_cert')
|
||||
def test_certonly_reinstall(self, mock_report_new_cert, mock_init,
|
||||
mock_renewal, mock_get_utility):
|
||||
mock_renewal.return_value = ('reinstall', mock.MagicMock())
|
||||
mock_init.return_value = mock_client = mock.MagicMock()
|
||||
self._call(['-d', 'foo.bar', '-a', 'standalone', 'certonly'])
|
||||
self.assertFalse(mock_client.obtain_certificate.called)
|
||||
self.assertFalse(mock_client.obtain_and_enroll_certificate.called)
|
||||
self.assertEqual(mock_get_utility().add_message.call_count, 0)
|
||||
mock_report_new_cert.assert_not_called()
|
||||
#self.assertTrue('donate' not in mock_get_utility().add_message.call_args[0][0])
|
||||
|
||||
def _test_certonly_csr_common(self, extra_args=None):
|
||||
|
||||
@@ -32,8 +32,7 @@ class AuthenticatorTest(test_util.TempDirTestCase):
|
||||
# initialization.
|
||||
self.config = mock.MagicMock(
|
||||
http01_port=0, manual_auth_hook=None, manual_cleanup_hook=None,
|
||||
manual_public_ip_logging_ok=False, noninteractive_mode=False,
|
||||
validate_hooks=False,
|
||||
noninteractive_mode=False, validate_hooks=False,
|
||||
config_dir=os.path.join(self.tempdir, "config_dir"),
|
||||
work_dir=os.path.join(self.tempdir, "work_dir"),
|
||||
backup_dir=os.path.join(self.tempdir, "backup_dir"),
|
||||
@@ -60,19 +59,7 @@ class AuthenticatorTest(test_util.TempDirTestCase):
|
||||
self.assertEqual(self.auth.get_chall_pref('example.org'),
|
||||
[challenges.HTTP01, challenges.DNS01])
|
||||
|
||||
@test_util.patch_get_utility()
|
||||
def test_ip_logging_not_ok(self, mock_get_utility):
|
||||
mock_get_utility().yesno.return_value = False
|
||||
self.assertRaises(errors.PluginError, self.auth.perform, [])
|
||||
|
||||
@test_util.patch_get_utility()
|
||||
def test_ip_logging_ok(self, mock_get_utility):
|
||||
mock_get_utility().yesno.return_value = True
|
||||
self.auth.perform([])
|
||||
self.assertTrue(self.config.manual_public_ip_logging_ok)
|
||||
|
||||
def test_script_perform(self):
|
||||
self.config.manual_public_ip_logging_ok = True
|
||||
self.config.manual_auth_hook = (
|
||||
'{0} -c "from __future__ import print_function;'
|
||||
'from certbot.compat import os;'
|
||||
@@ -105,7 +92,6 @@ class AuthenticatorTest(test_util.TempDirTestCase):
|
||||
|
||||
@test_util.patch_get_utility()
|
||||
def test_manual_perform(self, mock_get_utility):
|
||||
self.config.manual_public_ip_logging_ok = True
|
||||
self.assertEqual(
|
||||
self.auth.perform(self.achalls),
|
||||
[achall.response(achall.account_key) for achall in self.achalls])
|
||||
@@ -116,7 +102,6 @@ class AuthenticatorTest(test_util.TempDirTestCase):
|
||||
self.assertFalse(kwargs['wrap'])
|
||||
|
||||
def test_cleanup(self):
|
||||
self.config.manual_public_ip_logging_ok = True
|
||||
self.config.manual_auth_hook = ('{0} -c "import sys; sys.stdout.write(\'foo\')"'
|
||||
.format(sys.executable))
|
||||
self.config.manual_cleanup_hook = '# cleanup'
|
||||
|
||||
@@ -74,6 +74,30 @@ class RenewalTest(test_util.ConfigTestCase):
|
||||
|
||||
assert self.config.rsa_key_size == 2048
|
||||
|
||||
def test_reuse_ec_key_renewal_params(self):
|
||||
self.config.elliptic_curve = 'INVALID_CURVE'
|
||||
self.config.reuse_key = True
|
||||
self.config.dry_run = True
|
||||
self.config.key_type = 'ecdsa'
|
||||
config = configuration.NamespaceConfig(self.config)
|
||||
|
||||
rc_path = test_util.make_lineage(
|
||||
self.config.config_dir,
|
||||
'sample-renewal-ec.conf',
|
||||
ec=True,
|
||||
)
|
||||
lineage = storage.RenewableCert(rc_path, config)
|
||||
|
||||
le_client = mock.MagicMock()
|
||||
le_client.obtain_certificate.return_value = (None, None, None, None)
|
||||
|
||||
from certbot._internal import renewal
|
||||
|
||||
with mock.patch('certbot._internal.renewal.hooks.renew_hook'):
|
||||
renewal.renew_cert(self.config, None, le_client, lineage)
|
||||
|
||||
assert self.config.elliptic_curve == 'secp256r1'
|
||||
|
||||
|
||||
class RestoreRequiredConfigElementsTest(test_util.ConfigTestCase):
|
||||
"""Tests for certbot._internal.renewal.restore_required_config_elements."""
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
targets:
|
||||
#-----------------------------------------------------------------------------
|
||||
#Ubuntu
|
||||
- ami: ami-0f2e2c076f4c2f941
|
||||
name: ubuntu20.10
|
||||
type: ubuntu
|
||||
virt: hvm
|
||||
user: ubuntu
|
||||
- ami: ami-0758470213bdd23b1
|
||||
name: ubuntu20.04
|
||||
type: ubuntu
|
||||
@@ -37,18 +42,6 @@ targets:
|
||||
virt: hvm
|
||||
user: admin
|
||||
#-----------------------------------------------------------------------------
|
||||
# Fedora
|
||||
- ami: ami-0fcbe88944a53b4c8
|
||||
name: fedora31
|
||||
type: centos
|
||||
virt: hvm
|
||||
user: fedora
|
||||
- ami: ami-00bbc6858140f19ed
|
||||
name: fedora30
|
||||
type: centos
|
||||
virt: hvm
|
||||
user: fedora
|
||||
#-----------------------------------------------------------------------------
|
||||
# CentOS
|
||||
- ami: ami-9887c6e7
|
||||
name: centos7
|
||||
|
||||
@@ -47,16 +47,6 @@ targets:
|
||||
type: centos
|
||||
virt: hvm
|
||||
user: ec2-user
|
||||
- ami: ami-0fcbe88944a53b4c8
|
||||
name: fedora31
|
||||
type: centos
|
||||
virt: hvm
|
||||
user: fedora
|
||||
- ami: ami-00bbc6858140f19ed
|
||||
name: fedora30
|
||||
type: centos
|
||||
virt: hvm
|
||||
user: fedora
|
||||
#-----------------------------------------------------------------------------
|
||||
# CentOS
|
||||
# These Marketplace AMIs must, irritatingly, have their terms manually
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
targets:
|
||||
#-----------------------------------------------------------------------------
|
||||
#Ubuntu
|
||||
- ami: ami-0f2e2c076f4c2f941
|
||||
name: ubuntu20.10
|
||||
type: ubuntu
|
||||
virt: hvm
|
||||
user: ubuntu
|
||||
- ami: ami-0758470213bdd23b1
|
||||
name: ubuntu20.04
|
||||
type: ubuntu
|
||||
@@ -38,16 +43,6 @@ targets:
|
||||
type: centos
|
||||
virt: hvm
|
||||
user: ec2-user
|
||||
- ami: ami-0fcbe88944a53b4c8
|
||||
name: fedora31
|
||||
type: centos
|
||||
virt: hvm
|
||||
user: fedora
|
||||
- ami: ami-00bbc6858140f19ed
|
||||
name: fedora30
|
||||
type: centos
|
||||
virt: hvm
|
||||
user: fedora
|
||||
#-----------------------------------------------------------------------------
|
||||
# CentOS
|
||||
# These Marketplace AMIs must, irritatingly, have their terms manually
|
||||
|
||||
@@ -12,19 +12,6 @@ IFS=$'\n\t'
|
||||
# given value is only the base of the tag because the things like the CPU
|
||||
# architecture are also added to the full tag.
|
||||
|
||||
# As of writing this, runs of this script consistently fail in Azure
|
||||
# Pipelines, but they are fixed by using Docker BuildKit. A log of the failures
|
||||
# that were occurring can be seen at
|
||||
# https://gist.github.com/2227a05622299ce17bff9b0da714a1ff. Since using
|
||||
# BuildKit is supposed to offer benefits anyway (see
|
||||
# https://docs.docker.com/develop/develop-images/build_enhancements/ for more
|
||||
# information), let's use it.
|
||||
#
|
||||
# This variable is set inside the script itself rather than in something like
|
||||
# the CI config to have a consistent experience when this script is run
|
||||
# locally.
|
||||
export DOCKER_BUILDKIT=1
|
||||
|
||||
WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
REPO_ROOT="$(dirname "$(dirname "${WORK_DIR}")")"
|
||||
source "$WORK_DIR/lib/common"
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
# Certbot Snaps
|
||||
# Building Certbot Snaps
|
||||
|
||||
## Local Testing and Development
|
||||
|
||||
These instructions are recommended when testing anything about the snap setup for ease of debugging.
|
||||
The architecture of the built snap is limited to the architecture of the system it is built on.
|
||||
|
||||
### Initial VM Set Up
|
||||
|
||||
These steps need to be done once to set up your VM and do not need to be run again to rebuild the snap.
|
||||
@@ -9,37 +12,89 @@ These steps need to be done once to set up your VM and do not need to be run aga
|
||||
1. Start with a Focal VM. You need a full virtual machine using something like DigitalOcean, EC2, or VirtualBox. Docker won't work. Another version of Ubuntu can probably be used, but Focal was used when writing these instructions.
|
||||
2. Set up a user other than root with sudo privileges for use with snapcraft and run all of the following commands with it. A command to do this for a user named certbot looks like `adduser certbot && usermod -aG sudo certbot && su - certbot`.
|
||||
3. Install git and python with `sudo apt update && sudo apt install -y git python`.
|
||||
4. Set up lxd for use with snapcraft by running `sudo snap install lxd && sudo /snap/bin/lxd.migrate -yes && sudo /snap/bin/lxd waitready && sudo /snap/bin/lxd init --auto` (errors here are ok; it may already
|
||||
4. Set up lxd for use with snapcraft by running `sudo snap install lxd && sudo /snap/bin/lxd.migrate -yes; sudo /snap/bin/lxd waitready && sudo /snap/bin/lxd init --auto` (errors here are ok; it may already
|
||||
have been installed on your system).
|
||||
5. Add your current user to the lxd group and update your shell to have the new assignment by running `sudo usermod -a -G lxd ${USER} && newgrp lxd`.
|
||||
6. Install snapcraft with `sudo snap install --classic snapcraft`.
|
||||
7. `cd ~` (or any other directory where you want our source files to be)
|
||||
8. Run `git clone git://github.com/certbot/certbot`
|
||||
9. `cd certbot`
|
||||
9. `cd certbot` (All further instructions are relative to this directory.)
|
||||
|
||||
### Build the Snaps
|
||||
### Certbot Snap
|
||||
|
||||
These are the steps to build and install the snaps. If you have run these steps before, you may want to run the commands in the section below to clean things up before building the snap again.
|
||||
#### Reset the Environment
|
||||
|
||||
If the snap has been built before, the instructions below clean up the build environment so it can reliably be used again.
|
||||
|
||||
1. `snapcraft clean --use-lxd`
|
||||
2. [Optional] `mv certbot_*_amd64.snap certbot_amd64.snap.bak`
|
||||
|
||||
#### Build the Certbot Snap
|
||||
|
||||
These are the steps to build and install the Certbot snap. If you have run these steps before, you may want to run the commands in the section above to clean things up or save a previous build before building the snap again (running `snapcraft` again will overwrite the previous snap).
|
||||
|
||||
1. Run `snapcraft --use-lxd`.
|
||||
2. Install the generated snap with `sudo snap install --dangerous --classic certbot_*_amd64.snap`. You can transfer the snap to a different machine to run it there instead if you prefer.
|
||||
3. Run `tools/merge_requirements.py tools/dev_constraints.txt <(tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt) > certbot-dns-dnsimple/snap-constraints.txt` (this is a workaround for https://github.com/certbot/certbot/issues/8100).
|
||||
4. `cd certbot-dns-dnsimple`
|
||||
5. `snapcraft --use-lxd`
|
||||
6. Run `sudo snap set certbot trust-plugin-with-root=ok`.
|
||||
7. Install the generated snap with `sudo snap install --dangerous certbot-dns-dnsimple_*_amd64.snap`. Again, you can transfer the snap to a different machine to run it there instead if you prefer.
|
||||
8. Connect the plugin with `sudo snap connect certbot:plugin certbot-dns-dnsimple`.
|
||||
9. Connect the plugin metadata with `sudo snap connect certbot-dns-dnsimple:certbot-metadata certbot:certbot-metadata`. Install the plugin again to test refresh; logs are at `/var/snap/certbot-dns-dnsimple/current/debuglog`.
|
||||
10. Now you can run Certbot as normal. For example, `certbot plugins` should display the DNSimple plugin as installed.
|
||||
|
||||
### Reset the Environment
|
||||
#### Run
|
||||
|
||||
The instructions below clean up the build environment so it can reliably be used again.
|
||||
Run Certbot as normal. For example, `certbot plugins` should display the Apache and Nginx plugins.
|
||||
|
||||
1. `cd ~/certbot` (or to an alternate path where you put our source files)
|
||||
2. `snapcraft clean --use-lxd`
|
||||
3. `rm certbot_*_amd64.snap`
|
||||
4. `cd certbot-dns-dnsimple`
|
||||
5. `rm certbot-dns-dnsimple_*_amd64.snap`
|
||||
6. `snapcraft clean --use-lxd`
|
||||
7. `cd ..`
|
||||
### Certbot Plugin Snaps
|
||||
|
||||
These instructions use the `certbot-dns-dnsimple` plugin as an example, but all of Certbot's other plugin snaps can be built in the same way.
|
||||
|
||||
#### Reset the Environment
|
||||
|
||||
If the plugin snap has been built before, the instructions below clean up the build environment so it can reliably be used again.
|
||||
|
||||
1. `cd certbot-dns-dnsimple`
|
||||
2. `snapcraft clean --use-lxd`
|
||||
3. [Optional] `mv certbot-dns-dnsimple_*_amd64.snap certbot-dns-simple_amd64.snap.bak`
|
||||
4. `cd ..`
|
||||
|
||||
#### Build a Certbot Plugin Snap
|
||||
|
||||
These are the steps to build and install the Certbot DNSimple plugin snap. If you have run these steps before, you may want to run the commands in the section above to clean things up or save a previous build before building the snap again (running `snapcraft` again will overwrite the previous snap).
|
||||
|
||||
1. Run `tools/snap/generate_dnsplugins_all.sh` to generate all necessary files for all plugin snaps.
|
||||
2. `cd certbot-dns-dnsimple`
|
||||
3. `snapcraft --use-lxd`
|
||||
4. Run `sudo snap set certbot trust-plugin-with-root=ok`.
|
||||
5. Install the generated snap with `sudo snap install --dangerous certbot-dns-dnsimple_*_amd64.snap`. Again, you can transfer the snap to a different machine to run it there instead if you prefer.
|
||||
6. Connect the plugin with `sudo snap connect certbot:plugin certbot-dns-dnsimple`.
|
||||
7. Connect the plugin metadata with `sudo snap connect certbot-dns-dnsimple:certbot-metadata certbot:certbot-metadata`. Install the plugin again to test refresh; if the plugin's hook creates any logs, they are at `/var/snap/certbot-dns-dnsimple/current/debuglog`.
|
||||
|
||||
#### Run
|
||||
|
||||
Run Certbot as normal. For example, `certbot plugins` should display the DNSimple plugin as installed.
|
||||
|
||||
## Building for Other Architectures
|
||||
|
||||
To build for an unavailable architecture or for multiple architectures simultaneously, we recommend using snapcraft's remote build feature.
|
||||
It is easiest to run this from a local machine.
|
||||
|
||||
### Initial Local Setup
|
||||
|
||||
1. Create or log into an Ubuntu One account [here](https://login.launchpad.net/).
|
||||
2. Install git and python with `sudo apt update && sudo apt install -y git python`.
|
||||
3. Install snapcraft with `sudo snap install --classic snapcraft`.
|
||||
4. `cd ~` (or any other directory where you want our source files to be)
|
||||
5. Run `git clone git://github.com/certbot/certbot`
|
||||
6. `cd certbot` (All further instructions are relative to this directory.)
|
||||
7. To trigger `snapcraft` to request access to your Launchpad account, run
|
||||
`snapcraft remote-build --launchpad-accept-public-upload --status`. A URL where you need
|
||||
to grant this access will be printed to your terminal and automatically open in your browser
|
||||
if one is available.
|
||||
|
||||
### Build Snaps Remotely
|
||||
|
||||
Certbot provides a wrapper around snapcraft's remote build to make building all of our plugins easier. To see all available
|
||||
options, run `python3 tools/snap/build_remote.py --help`.
|
||||
|
||||
For example, to build all available snaps for all architectures, run `python3 tools/snap/build_remote.py ALL --archs amd64 arm64 armhf`.
|
||||
|
||||
To build only the certbot snap on only amd64, run `python3 tools/snap/build_remote.py certbot --archs armhf`.
|
||||
|
||||
The command will upload the entire contents of the working directory, so if the remote build
|
||||
appears to hang, try using a clean clone of the `certbot` repository.
|
||||
|
||||
@@ -34,15 +34,6 @@ def _build_snap(target, archs, status, lock):
|
||||
workspace = CERTBOT_DIR
|
||||
else:
|
||||
workspace = join(CERTBOT_DIR, target)
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
subprocess.check_output(
|
||||
('"{0}" tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt '
|
||||
'| grep -v python-augeas > "{1}"').format(sys.executable, f.name),
|
||||
shell=True, cwd=CERTBOT_DIR)
|
||||
subprocess.check_output(
|
||||
('"{0}" tools/merge_requirements.py tools/dev_constraints.txt '
|
||||
'"{1}" > "{2}/snap-constraints.txt"').format(sys.executable, f.name, workspace),
|
||||
shell=True, cwd=CERTBOT_DIR)
|
||||
|
||||
retry = 3
|
||||
while retry:
|
||||
@@ -165,6 +156,12 @@ def main():
|
||||
targets.remove('DNS_PLUGINS')
|
||||
targets.update(PLUGINS)
|
||||
|
||||
# If we're building anything other than just Certbot, we need to
|
||||
# generate the snapcraft files for the DNS plugins.
|
||||
if targets != set(('certbot',)):
|
||||
subprocess.run(['tools/snap/generate_dnsplugins_all.sh'],
|
||||
check=True, cwd=CERTBOT_DIR)
|
||||
|
||||
print('Start remote snap builds...')
|
||||
print(f' - archs: {", ".join(archs)}')
|
||||
print(f' - projects: {", ".join(sorted(targets))}')
|
||||
|
||||
15
tools/snap/generate_dnsplugins_all.sh
Executable file
15
tools/snap/generate_dnsplugins_all.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
# Generate all necessary files for building snaps for all DNS plugins
|
||||
set -eu
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
CERTBOT_DIR="$(dirname "$(dirname "${DIR}")")"
|
||||
|
||||
for PLUGIN_PATH in "${CERTBOT_DIR}"/certbot-dns-*; do
|
||||
bash "${CERTBOT_DIR}"/tools/snap/generate_dnsplugins_snapcraft.sh $PLUGIN_PATH
|
||||
bash "${CERTBOT_DIR}"/tools/snap/generate_dnsplugins_postrefreshhook.sh $PLUGIN_PATH
|
||||
# Create constraints file
|
||||
"${CERTBOT_DIR}"/tools/merge_requirements.py tools/dev_constraints.txt \
|
||||
<("${CERTBOT_DIR}"/tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt) \
|
||||
> "${PLUGIN_PATH}"/snap-constraints.txt
|
||||
done
|
||||
@@ -1,15 +1,15 @@
|
||||
#!/bin/bash
|
||||
# Generate the hooks/post-refresh file for all DNS plugins
|
||||
# Generate the hooks/post-refresh file for a DNS plugin
|
||||
# Usage: bash generate_dnsplugins_postrefreshhook.sh path/to/dns/plugin
|
||||
# For example, from the certbot home directory:
|
||||
# tools/snap/generate_dnsplugins_postrefreshhook.sh certbot-dns-dnsimple
|
||||
set -eu
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
CERTBOT_DIR="$(dirname "$(dirname "${DIR}")")"
|
||||
|
||||
for PLUGIN_PATH in "${CERTBOT_DIR}"/certbot-dns-*; do
|
||||
mkdir -p "${PLUGIN_PATH}/snap/hooks"
|
||||
cat <<EOF > "${PLUGIN_PATH}/snap/hooks/post-refresh"
|
||||
PLUGIN_PATH=$1
|
||||
mkdir -p "${PLUGIN_PATH}/snap/hooks"
|
||||
cat <<EOF > "${PLUGIN_PATH}/snap/hooks/post-refresh"
|
||||
#!/bin/sh -e
|
||||
# This file is generated by tools/generate_dnsplugins_postrefreshhook.sh and should not be edited manually.
|
||||
# This file is generated automatically and should not be edited manually.
|
||||
|
||||
# get certbot version
|
||||
if [ ! -f "\$SNAP/certbot-shared/certbot-version.txt" ]; then
|
||||
@@ -31,4 +31,3 @@ if [ "\$exit_code" -eq 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
EOF
|
||||
done
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#!/bin/bash
|
||||
# Generate the snapcraft.yaml file for all DNS plugins
|
||||
# Generate the snapcraft.yaml file for a DNS plugins
|
||||
# Usage: bash generate_dnsplugins_snapcraft.sh path/to/dns/plugin
|
||||
# For example, from the certbot home directory:
|
||||
# tools/snap/generate_dnsplugins_snapcraft.sh certbot-dns-dnsimple
|
||||
set -e
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
CERTBOT_DIR="$(dirname "$(dirname "${DIR}")")"
|
||||
|
||||
for PLUGIN_PATH in "${CERTBOT_DIR}"/certbot-dns-*; do
|
||||
PLUGIN=$(basename "${PLUGIN_PATH}")
|
||||
DESCRIPTION=$(grep description "${PLUGIN_PATH}/setup.py" | sed -E 's|\s+description="(.*)",|\1|g')
|
||||
mkdir -p "${PLUGIN_PATH}/snap"
|
||||
cat <<EOF > "${PLUGIN_PATH}/snap/snapcraft.yaml"
|
||||
# This file is generated by tools/generate_dnsplugins_snapcraft.sh and should not be edited manually.
|
||||
PLUGIN_PATH=$1
|
||||
PLUGIN=$(basename "${PLUGIN_PATH}")
|
||||
DESCRIPTION=$(grep description "${PLUGIN_PATH}/setup.py" | sed -E 's|\s+description="(.*)",|\1|g')
|
||||
mkdir -p "${PLUGIN_PATH}/snap"
|
||||
cat <<EOF > "${PLUGIN_PATH}/snap/snapcraft.yaml"
|
||||
# This file is generated automatically and should not be edited manually.
|
||||
name: ${PLUGIN}
|
||||
summary: ${DESCRIPTION}
|
||||
description: ${DESCRIPTION}
|
||||
@@ -52,4 +52,3 @@ plugs:
|
||||
content: metadata-1
|
||||
target: \$SNAP/certbot-shared
|
||||
EOF
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user