Closed macnotes closed 2 years ago
Identity is the identity of your client, you can use an existing certificate or generate self signed certificate.
Thank you for your assistance. This is very nice of you.
I don't know SCEP very well but I am learning from your code. I had it in my head that the client generates a private key then the client generates a CSR based on the private key. Then the client sends the CSR to the SCEP server and a certificate is returned. Finally, the certificate and private key can be combined into a .p12 to create an "identity". Based on your comment, my understanding is likely wrong.
I am trying your project against my NDES server. I am following the instructions as I understand them, but NDES returns a 500 error.
import logging # Requirements of the examples in the readme from scep import Client from scep.Client import PKIStatus # To call the challenge page... import requests as requests import re # To load env vars from os import getenv
challenge_url = getenv('challenge_url') challenge_user = getenv('challenge_user') challenge_pass = getenv('challenge_pass') scep_url = getenv('scep_url')
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
def get_ndes_challenge_password(): logging.info('GET NDES challenge page') response = requests.get(url=challenge_url, auth=(challenge_user, challenge_pass), timeout=10) html_string = response.text html_status_code = response.status_code logging.debug(html_string) logging.debug(html_status_code) assert html_status_code == 200 assert html_string
regex = r".\*challenge password is: \<B> ([A-Za-z0-9_-]{43}) \</B>.\*"
try:
my_dynamic_challenge = re.search(regex, html_string).group(1)
except AttributeError:
logging.error("dynamic_challenge not found")
my_dynamic_challenge = ''
logging.info(f"Retrieved a dynamic_challenge: \"{my_dynamic_challenge}\"")
# extract ca cert thumbprint
regex = r".\*CA certificate is: \<B> ([A-F0-9]{40}) \</B>.\*"
try:
my_ca_cert_thumbprint = re.search(regex, html_string).group(1)
except AttributeError:
logging.error("ca_cert_thumbprint not found")
my_ca_cert_thumbprint = ''
logging.info(f"Retrieved a ca_cert_thumbprint: \"{my_ca_cert_thumbprint}\"")
assert my_dynamic_challenge
assert my_ca_cert_thumbprint
return my_dynamic_challenge, my_ca_cert_thumbprint
def main(): (dynamic_challenge, ca_cert_thumbprint) = get_ndes_challenge_password()
identity, identity_private_key = Client.SigningRequest.generate_self_signed(
cn=u'PyScep-test',
key_usage={u'digital_signature', u'key_encipherment'}
)
# Signing Request
# def generate_csr(cls, cn, key_usage, password=None, private_key=None):
csr, private_key = Client.SigningRequest.generate_csr(
cn=u'PyScep-test',
key_usage={u'digital_signature', u'key_encipherment'},
password=challenge_pass,
private_key=identity_private_key
)
# Instantiate a Client
client = Client.Client(scep_url)
# Enroll the cert
# def enrol(self, csr, identity, identity_private_key, identifier=None):
# , identifier=ca_cert_thumbprint # An optional identifier how CA Server identifies the CA
res = client.enrol(
csr=csr,
identity=identity,
identity_private_key=identity_private_key
)
if res.status == PKIStatus.FAILURE:
print(res.fail_info)
elif res.status == PKIStatus.PENDING:
print(res.transaction_id)
else:
print(res.certificate)
if name == "main": main()
The regex to get the challenge works well. The 500 happens on the enrol.
DEBUG:Starting new HTTPS connection (1): ...:443
DEBUG:https://...:443 "GET ...?operation=GetCACaps&message= HTTP/1.1" 200 None
DEBUG:Server Capabilities are SHA-256, POSTPKIOperation, SHA-512
DEBUG:Starting new HTTPS connection (1): ...:443
DEBUG:https://...:443 "GET ...?operation=GetCACert&message= HTTP/1.1" 200 2428
DEBUG:Received response with RA certificates
DEBUG:2 certificate(s) attached to signedData
DEBUG:Message Type : 19
DEBUG:Transaction ID : 6bf62cf...
DEBUG:Sender Nonce : b'ta2M...qhAw=='
DEBUG:Starting new HTTPS connection (1): ...:443
DEBUG:https://...:443 "POST ...?operation=PKIOperation&message= HTTP/1.1" 500 1719
Traceback (most recent call last):
File "/Users/admin/PycharmProjects/scep/ndes.py", line 84, in
@macnotes Your understanding is correct, the only thing you were missing was that all the communication is protected using a certificate and the self-signed certificate is for that purpose. You could use an existing certificate as well to protect your communication to your SCEP server.
500 is Server Internal Error
, Could you please check the server logs?
I've tested this package only with EJBCA as I don't have access to an NDES server to try it. Your code posed above looks good to me.
Closing due to no activity
This is so helpful. Thank you!
Client.SigningRequest.generate_csr offers a shortcut that allows a private key to be generated on the fly.
However, client.enrol requires an identity. How is this parameter obtained if the private key is generated via the generate_csr shortcut?
res = client.enrol(
csr=csr,
identity=identity,
identity_private_key=identity_private_key,
identifier=my_ca_cert_thumbprint # An optional identifier how CA Server identifies the CA
)