SSL Connection Using .pem Certificate With Python

流过昼夜 提交于 2020-02-20 06:10:59

问题


I'm trying to establish successful communication over an HTTPS connection using authentication. I'm using Python 2.7 w/ Django 1.4 on Ubuntu 12.04.

The API documentation I'm following has specific requirements for authentication. Including the Authentication header you'll find below and sending certificate information.

This is the code:

import httplib
import base64

HOST = 'some.host.com'
API_URL = '/some/api/path'

username = '1234'
password = '5678'

auth_value = base64.b64encode('WS{0}._.1:{1}'.format(username, password))
path = os.path.join(os.path.dirname(__file__), 'keys/')
pem_file = '{0}WS{1}._.1.pem'.format(path, username)

xml_string = '<some><xml></xml><stuff></stuff></some>'

headers = { 'User-Agent'     : 'Rico',
            'Content-type'   : 'text/xml',
            'Authorization'  : 'Basic {0}'.format(auth_value),
          }



conn = httplib.HTTPSConnection(HOST, cert_file = pem_file)
conn.putrequest("POST", API_URL, xml_string, headers)
response = conn.getresponse()

I'm getting the following error:

Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py" in wrapped_view
  77.         return view_func(*args, **kwargs)
File "/home/tokeniz/tokeniz/gateway_interface/views.py" in processPayment
  37.         processCreditCard = ProcessCreditCard(token, postHandling)
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in __init__
  75.             self.processGateway()
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in processGateway
  95.         gateway = Gateway(self)
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in __init__
  37.         self.postInfo()
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in postInfo
  245.         response = conn.getresponse()
File "/usr/lib/python2.7/httplib.py" in getresponse
  1018.             raise ResponseNotReady()

Exception Type: ResponseNotReady at /processPayment/
Exception Value: 

Why am I getting this error?

UPDATE 1: I've been using the .pem file they gave me (Link Point Gateway) but have read that the certificate file should contain both the certificate and the RSA private key. Is that correct? I tried to send a .pem file containing both and received the following error:

    Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py" in wrapped_view
  77.         return view_func(*args, **kwargs)
File "/home/tokeniz/tokeniz/gateway_interface/views.py" in processPayment
  37.         processCreditCard = ProcessCreditCard(token, postHandling)
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in __init__
  75.             self.processGateway()
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in processGateway
  95.         gateway = Gateway(self)
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in __init__
  37.         self.postInfo()
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in postInfo
  251.         conn.request('POST', self.API_URL, self.xml_string, headers)
File "/usr/lib/python2.7/httplib.py" in request
  958.         self._send_request(method, url, body, headers)
File "/usr/lib/python2.7/httplib.py" in _send_request
  992.         self.endheaders(body)
File "/usr/lib/python2.7/httplib.py" in endheaders
  954.         self._send_output(message_body)
File "/usr/lib/python2.7/httplib.py" in _send_output
  814.         self.send(msg)
File "/usr/lib/python2.7/httplib.py" in send
  776.                 self.connect()
File "/usr/lib/python2.7/httplib.py" in connect
  1161.             self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
File "/usr/lib/python2.7/ssl.py" in wrap_socket
  381.                      ciphers=ciphers)
File "/usr/lib/python2.7/ssl.py" in __init__
  141.                                         ciphers)

Exception Type: SSLError at /processPayment/
Exception Value: [Errno 336265225] _ssl.c:351: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib

I can't tell if this is a step forward or backward.

UPDATE 2: I've tried to pass both a certificate file and a key file when creating the connection object.

conn = httplib.HTTPSConnection(HOST, cert_file = pem_file, key_file = key_file)

I get the following error:

Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py" in wrapped_view
  77.         return view_func(*args, **kwargs)
File "/home/tokeniz/tokeniz/gateway_interface/views.py" in processPayment
  37.         processCreditCard = ProcessCreditCard(token, postHandling)
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in __init__
  75.             self.processGateway()
File "/home/tokeniz/tokeniz/gateway_interface/credit_card_handling.py" in processGateway
  95.         gateway = Gateway(self)
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in __init__
  37.         self.postInfo()
File "/home/tokeniz/tokeniz/gateway_interface/first_data.py" in postInfo
  252.         conn.request('POST', self.API_URL, self.xml_string, headers)
File "/usr/lib/python2.7/httplib.py" in request
  958.         self._send_request(method, url, body, headers)
File "/usr/lib/python2.7/httplib.py" in _send_request
  992.         self.endheaders(body)
File "/usr/lib/python2.7/httplib.py" in endheaders
  954.         self._send_output(message_body)
File "/usr/lib/python2.7/httplib.py" in _send_output
  814.         self.send(msg)
File "/usr/lib/python2.7/httplib.py" in send
  776.                 self.connect()
File "/usr/lib/python2.7/httplib.py" in connect
  1161.             self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
File "/usr/lib/python2.7/ssl.py" in wrap_socket
  381.                      ciphers=ciphers)
File "/usr/lib/python2.7/ssl.py" in __init__
  141.                                         ciphers)

Exception Type: SSLError at /processPayment/
Exception Value: [Errno 336265225] _ssl.c:351: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib

If I try and combine the certificate file and key file and send it as the certificate argument I receive the same error.


回答1:


It would seem that some of the "higher level" libraries in Python are not equipped to handle this kind of authentication connection. After many days of attempts I was finally able to come up with a solution going down to the socket level.

host = 'some.host.com'
service = '/some/api/path'
port = 443

# Build the authorization info
username = '1234'
password = '5678'
path = '/path/to/key/files/'
pem_file = '{0}WS{1}._.1.pem'.format(path, username)
key_file = '{0}WS{1}._.1.key'.format(path, username)
auth = base64.b64encode('WS{0}._.1:{1}'.format(username, password))

## Create the header
http_header = "POST {0} HTTP/1.0\nHost: {1}\nContent-Type: text/xml\nAuthorization: Basic {2}\nContent-Length: {3}\n\n"
req = http_header.format(service, host, auth, len(xml_string)) + xml_string

## Create the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn = ssl.wrap_socket(sock, keyfile = key_file, certfile = pem_file)
conn.connect((host, port))
conn.send(req)

response = ''
while True:
    resp = conn.recv()
    response += resp

    if (resp == ''):
        break

I hope someone finds this useful. This particular implementation was to interface with Link Point Gateway with Python (not supported by First Data (Link Point)). Talk about a nightmare this whole project has been. haha

Anyway, for anyone having trouble using Link Point please be advised that the .key file they provide you is not sufficient for creating a connection in Python.

openssl rsa -in orig_file.key -out new_file.key

Then use the new_file.key instead.



来源:https://stackoverflow.com/questions/11586880/ssl-connection-using-pem-certificate-with-python

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!