Ensuring that acme and cryptography respect different key types (#554)

This commit is contained in:
kevgliss 2016-12-02 10:54:18 -08:00 committed by GitHub
parent 0f5e925a1a
commit 7f823a04cd
8 changed files with 89 additions and 55 deletions

View File

@ -13,12 +13,12 @@ from flask import current_app
from cryptography import x509 from cryptography import x509
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from lemur import database from lemur import database
from lemur.extensions import metrics from lemur.extensions import metrics
from lemur.plugins.base import plugins from lemur.plugins.base import plugins
from lemur.certificates.models import Certificate from lemur.certificates.models import Certificate
from lemur.common.utils import generate_private_key
from lemur.destinations.models import Destination from lemur.destinations.models import Destination
from lemur.notifications.models import Notification from lemur.notifications.models import Notification
@ -317,13 +317,7 @@ def create_csr(**csr_config):
:param csr_config: :param csr_config:
""" """
if 'RSA' in csr_config.get('key_type'): private_key = generate_private_key(csr_config.get('key_type'))
key_size = int(csr_config.get('key_type')[3:])
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=key_size,
backend=default_backend()
)
# TODO When we figure out a better way to validate these options they should be parsed as str # TODO When we figure out a better way to validate these options they should be parsed as str
builder = x509.CertificateSigningRequestBuilder() builder = x509.CertificateSigningRequestBuilder()

View File

@ -11,6 +11,7 @@ import random
from cryptography import x509 from cryptography import x509
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from flask_restful.reqparse import RequestParser from flask_restful.reqparse import RequestParser
@ -37,12 +38,44 @@ def get_psuedo_random_string():
def parse_certificate(body): def parse_certificate(body):
"""
Helper function that parses a PEM certificate.
:param body:
:return:
"""
if isinstance(body, str): if isinstance(body, str):
body = body.encode('utf-8') body = body.encode('utf-8')
return x509.load_pem_x509_certificate(body, default_backend()) return x509.load_pem_x509_certificate(body, default_backend())
def generate_private_key(key_type):
"""
Generates a new private key based on key_type.
Valid key types: RSA2048, RSA4096
:param key_type:
:return:
"""
valid_key_types = ['RSA2048', 'RSA4096']
if key_type not in valid_key_types:
raise Exception("Invalid key type: {key_type}. Supported key types: {choices}".format(
key_type=key_type,
choices=",".join(valid_key_types)
))
if 'RSA' in key_type:
key_size = int(key_type[3:])
return rsa.generate_private_key(
public_exponent=65537,
key_size=key_size,
backend=default_backend()
)
def is_weekend(date): def is_weekend(date):
""" """
Determines if a given date is on a weekend. Determines if a given date is on a weekend.

View File

@ -16,9 +16,10 @@ from acme.client import Client
from acme import jose from acme import jose
from acme import messages from acme import messages
from lemur.common.utils import generate_private_key
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import OpenSSL.crypto import OpenSSL.crypto
@ -101,12 +102,6 @@ def request_certificate(acme_client, authorizations, csr):
return pem_certificate, pem_certificate_chain return pem_certificate, pem_certificate_chain
def generate_rsa_private_key():
return rsa.generate_private_key(
public_exponent=65537, key_size=2048, backend=default_backend()
)
def setup_acme_client(): def setup_acme_client():
key = current_app.config.get('ACME_PRIVATE_KEY').strip() key = current_app.config.get('ACME_PRIVATE_KEY').strip()
acme_email = current_app.config.get('ACME_EMAIL') acme_email = current_app.config.get('ACME_EMAIL')
@ -127,7 +122,7 @@ def acme_client_for_private_key(acme_directory_url, private_key):
def register(email): def register(email):
private_key = generate_rsa_private_key() private_key = generate_private_key('RSA2048')
acme_client = acme_client_for_private_key(current_app.config('ACME_DIRECTORY_URL'), private_key) acme_client = acme_client_for_private_key(current_app.config('ACME_DIRECTORY_URL'), private_key)
registration = acme_client.register( registration = acme_client.register(

View File

@ -13,19 +13,15 @@ from flask import current_app
from cryptography import x509 from cryptography import x509
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from lemur.plugins.bases import IssuerPlugin from lemur.plugins.bases import IssuerPlugin
from lemur.plugins import lemur_cryptography as cryptography_issuer from lemur.plugins import lemur_cryptography as cryptography_issuer
from lemur.common.utils import generate_private_key
def build_root_certificate(options): def build_root_certificate(options):
private_key = rsa.generate_private_key( private_key = generate_private_key(options.get('key_type'))
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
subject = issuer = x509.Name([ subject = issuer = x509.Name([
x509.NameAttribute(x509.OID_COUNTRY_NAME, options['country']), x509.NameAttribute(x509.OID_COUNTRY_NAME, options['country']),

View File

@ -0,0 +1,36 @@
import arrow
def test_build_root_certificate():
from lemur.plugins.lemur_cryptography.plugin import build_root_certificate
options = {
'key_type': 'RSA2048',
'country': 'US',
'state': 'CA',
'location': 'Example place',
'organization': 'Example, Inc.',
'organizational_unit': 'Example Unit',
'common_name': 'Example ROOT',
'validity_start': arrow.get('2016-12-01').datetime,
'validity_end': arrow.get('2016-12-02').datetime,
'first_serial': 1
}
cert_pem, private_key_pem = build_root_certificate(options)
assert cert_pem
assert private_key_pem
def test_issue_certificate(authority):
from lemur.tests.vectors import CSR_STR
from lemur.plugins.lemur_cryptography.plugin import issue_certificate
options = {
'authority': authority,
'validity_start': arrow.get('2016-12-01').datetime,
'validity_end': arrow.get('2016-12-02').datetime
}
cert = issue_certificate(CSR_STR, options)
assert cert

11
lemur/tests/test_utils.py Normal file
View File

@ -0,0 +1,11 @@
import pytest
def test_generate_private_key():
from lemur.common.utils import generate_private_key
assert generate_private_key('RSA2048')
assert generate_private_key('RSA4096')
with pytest.raises(Exception):
generate_private_key('ECC')

View File

@ -269,34 +269,3 @@ zm3Cn4Ul8DO26w9QS4fmZjmnPOZFXYMWoOR6osHzb62PWQ8FBMqXcdToBV2Q9Iw4
PiFAxlc0tVjlLqQ= PiFAxlc0tVjlLqQ=
-----END CERTIFICATE REQUEST----- -----END CERTIFICATE REQUEST-----
""" """
CSR_PEM_STR = """
-----BEGIN RSA PRIVATE KEY-----
MIIEpgIBAAKCAQEAzZ2PgKflffhIPzwLXe26tuw+7Q72y9dAMrDVEms8u4Cch3yc
hN6Il5tvM4xTc0UN+aobAhaVoPDN+haXT/XyBRvbFV1f8nvmDQZGdmkyYkZ2xK2X
MvKnPtjEXdiShPYNKSEqfYQBHhDy08EqBqn+VajmgXoQai+TijVK+yQMVUyB9aFV
PO8P+sYP1rFIsj6OPVl8Rf9w2TT9VDk2In38SIgEYU2/RLZV6beYjpYnN8P7wV+q
rB/vlySLrNlhPgAZQFVEEwr3Om4KbuM43PJ5ZtwpapACnMZ9rmxHXq/hYYWoDGBr
G2BvvyFqymDektAYxNurTTIjpZiHm4poxHRaZwIDAQABAoIBAQCm5MwVBrKtI/ko
colbbVoPngSZkHrcC9SNEKFyON7r5sGm64t0AdjnDgAd3DnkJ1nnm54efMxo/OyD
oRCik6QlZ23VkpwNi2m4iq5o8Iw33rAKhkhizzjXN0V0UxTinYEjMEt348ywZdtj
67c7/4F0cArhb32hYwqjtQwuex0Tofb37Aj5rNPv1n8ytbhz1vriAVZHZEcjdjdn
CSVeblufORQKRzK3wW5nRN721b9gSvEJHfHeNpXQO9X8Yl5tn7UxjoQWXLZK+khv
pawN8BFt7lVLkQR14Nq7bKwuJ6KR1ig698a1Ii8Luyh2BgfIc25ryuzs8fFCioKi
TK/nzMQ5AoGBAPxtbTrkTTNQ03hnfefRVKGwNHPqLhIQpI99FC4yLYYHsUwFmMVR
ccg4aqNUtI0zn1snKC58NICxIPP9c0NuHqBuNuwhuRPINfQfjg/aOpE2QycZcew1
BQxXH5d3zXWKLpN15kIS2s18/MpNgTFx2Z0EGqLezDXs6JaPJkqg04glAoGBANCG
h106B9hbuTPYCAlTwvaoWnbaxLmtlWzRpqYBuiiBPGvLc545faXkJKb5/zd002kK
wblGrPtCnhTvCtHbTg/KuR/R8EsAriPhpWK+N4hCADJ8SLOxMU5S9O24FEK50ltN
Q84LS2Wo9fWXQhojiBrctn/ws5ngRCfUbhQeA3ybAoGBAOW7vWaUswIZ9GwnXDon
lGuXDxXTslw0k2AXyM8GUdIinCSBD3m9Vt2PItZFWBEOQ2DVMUelOK9LBZ+pMkbT
KMJ/rDKZunQbiacFNOiOhzDzfohOKxV7Z33EqPbUTMRFn4ALFCVcPZA4yWRgx0y1
vgSd4JQMSzRkyYWFAKd42SuVAoGBAIG84aWQQGdNkin+Y+mhsrCSSE6giDtaE5jz
y7KHapJe7f/HQnUUIee/zUoSSsbvKcW2CpfCsEdXyFEP9PRidOwAXjO9A7s2fiIW
9zY7UQO2xLakevtJ6HppxLfOitSFFqr1pJUik9N5TyZw6JCowLqtzeJGGQhI7z60
vZRIpDS3AoGBAPYJgNB7EcWj5U39ol+8cofG1kPauoEaildTur5ftzyzjy4DXrOW
sfU/xhUp6EKLGSXEPqeXAWR6ARf1F4U9Ozp6KA93lGSrSY561jKoqhxxOXAf5il2
p7Fzh2CckUeiGd5el+h2WUCOcgtlPlfRyV/Mlvx1H0gFieGucXTP23Ox
-----END RSA PRIVATE KEY-----
"""

View File

@ -1,4 +1,4 @@
[pytest] [tool:pytest]
python_files=test*.py python_files=test*.py
addopts=--tb=native -p no:doctest addopts=--tb=native -p no:doctest
norecursedirs=bin dist docs htmlcov script hooks node_modules .* {args} norecursedirs=bin dist docs htmlcov script hooks node_modules .* {args}