From efaec60e6b42e026bbee35478eb5162752f476fc Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 18 Nov 2014 08:13:06 -0800 Subject: [PATCH 1/3] Switched from using urllib2 to requests. urllib2 is a security hazzard, it does not perform certificate checks against a trust root by default, nor does it perform service_identity checks. Also, requests has a prettier API. --- letsencrypt/client/client.py | 15 +++++++-------- letsencrypt/client/recovery_contact_challenge.py | 7 ++++--- setup.py | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/letsencrypt/client/client.py b/letsencrypt/client/client.py index 6f17a42a8..894861b7c 100755 --- a/letsencrypt/client/client.py +++ b/letsencrypt/client/client.py @@ -1,10 +1,7 @@ #!/usr/bin/env python import M2Crypto -import urllib2, json -# XXX TODO: per https://docs.google.com/document/pub? -#id=1roBIeSJsYq3Ntpf6N0PIeeAAvu4ddn7mGo6Qb7aL7ew -# urllib2 is unsafe (!) and must be replaced +import json import os, grp, pwd, sys, time, random, sys, shutil # This line suppresses the no logging found for module 'jose' warning @@ -22,6 +19,8 @@ from Crypto.PublicKey import RSA from Crypto.Signature import PKCS1_v1_5 from Crypto.Hash import SHA256 +import requests + from letsencrypt.client.acme import acme_object_validate from letsencrypt.client.sni_challenge import SNI_Challenge from letsencrypt.client.payment_challenge import Payment_Challenge @@ -478,10 +477,10 @@ class Client(object): def send(self, json_obj): try: acme_object_validate(json.dumps(json_obj)) - response = urllib2.urlopen( - self.server_url, json.dumps(json_obj)).read() - acme_object_validate(response) - return json.loads(response) + response = requests.get(self.server_url, json=json_obj) + body = response.content + acme_object_validate(body) + return response.json() except: logger.fatal("Send() failed... may have lost connection to server") sys.exit(8) diff --git a/letsencrypt/client/recovery_contact_challenge.py b/letsencrypt/client/recovery_contact_challenge.py index 18a0d2816..d3160fd2e 100644 --- a/letsencrypt/client/recovery_contact_challenge.py +++ b/letsencrypt/client/recovery_contact_challenge.py @@ -1,8 +1,9 @@ +import requests + from letsencrypt.client.challenge import Challenge from letsencrypt.client import logger from letsencrypt.client.CONFIG import RECOVERY_TOKEN_EXT -# TODO: Replace urllib2 because of lack of certificate validation checks -import dialog, urllib2 +import dialog class RecoveryContact(Challenge): @@ -48,7 +49,7 @@ class RecoveryContact(Challenge): def poll(self, rounds = 10, quiet = True): for i in range(rounds): - if urllib2.urlopen(self.successURL).getcode() != 200: + if requests.get(self.successURL).status_code != 200: time.sleep(self.poll_delay) else: return True diff --git a/setup.py b/setup.py index 2bc387f63..23584522f 100644 --- a/setup.py +++ b/setup.py @@ -71,6 +71,7 @@ setup( ], install_requires=[ #'dialog', + 'requests>=2.4.3', 'protobuf', 'python-augeas', 'pycrypto', From a9e0028007847048a7afa00e3968b022440124db Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 18 Nov 2014 09:09:56 -0800 Subject: [PATCH 2/3] Use the older requests API --- letsencrypt/client/client.py | 5 +++-- setup.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/letsencrypt/client/client.py b/letsencrypt/client/client.py index 894861b7c..47c6328a9 100755 --- a/letsencrypt/client/client.py +++ b/letsencrypt/client/client.py @@ -476,8 +476,9 @@ class Client(object): def send(self, json_obj): try: - acme_object_validate(json.dumps(json_obj)) - response = requests.get(self.server_url, json=json_obj) + json_encoded = json.dumps(json_obj) + acme_object_validate(json_encoded) + response = requests.get(self.server_url, data=json_encoded) body = response.content acme_object_validate(body) return response.json() diff --git a/setup.py b/setup.py index 23584522f..cb71e09d0 100644 --- a/setup.py +++ b/setup.py @@ -71,7 +71,7 @@ setup( ], install_requires=[ #'dialog', - 'requests>=2.4.3', + 'requests', 'protobuf', 'python-augeas', 'pycrypto', From bcda03d94899cb2e90a40d51dc964043cf2421fc Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 18 Nov 2014 09:15:36 -0800 Subject: [PATCH 3/3] Set the content-type header and use POST, which the ACME spec requires --- letsencrypt/client/client.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/letsencrypt/client/client.py b/letsencrypt/client/client.py index 47c6328a9..09dd9b1ab 100755 --- a/letsencrypt/client/client.py +++ b/letsencrypt/client/client.py @@ -478,7 +478,11 @@ class Client(object): try: json_encoded = json.dumps(json_obj) acme_object_validate(json_encoded) - response = requests.get(self.server_url, data=json_encoded) + response = requests.post( + self.server_url, + data=json_encoded, + headers={"Content-Type": "application/json"}, + ) body = response.content acme_object_validate(body) return response.json()