async def build_csr( priv: key.PrivateKey, subject: Sequence[Tuple[str, Any]], attributes: Optional[List[Mapping[str, Any]]] = None, ) -> bytes: """ Create a PKCS#10 Certificate Signing Request. """ cri = CertificationRequestInfo({ "version": "v1", "subject": RDNSequence([[{ "type": typ, "value": value }] for typ, value in subject]), "subject_pk_info": get_spki(priv.public), "attributes": attributes or [], }) sig = await priv.sign(cri.dump()) return CertificationRequest({ "certification_request_info": cri, "signature_algorithm": get_sig_alg(sig), "signature": get_sig_bytes(sig), }).dump()
def generate_csr(self, private_key, subject_name, extensions=None): common_name = subject_name.get_attributes_for_oid( NameOID.COMMON_NAME)[0].value info = CertificationRequestInfo({ 'version': 0, 'subject': Name.build({ 'country_name': 'US', 'state_or_province_name': 'North Carolina', 'organization_name': 'Hyperledger', 'organizational_unit_name': 'Fabric', 'common_name': common_name }), 'subject_pk_info': PublicKeyInfo.load(encode_ec_public_key(private_key.public_key)), 'attributes': CRIAttributes([]) }) hash = hashlib.sha256(info.dump()).digest() signature = private_key.private_key.sign(hash, mechanism=Mechanism.ECDSA) csr = CertificationRequest({ 'certification_request_info': info, 'signature_algorithm': { 'algorithm': 'sha256_ecdsa', 'parameters': None }, 'signature': encode_ecdsa_signature(signature) }) der = csr.dump() result = x509.load_der_x509_csr(der, default_backend()) return result
def test_sign_csr(self): # Warning: proof of concept code only! pub, priv = self.session.generate_keypair(KeyType.RSA, 1024) info = CertificationRequestInfo({ 'version': 0, 'subject': Name.build({ 'common_name': 'Test Certificate', }), 'subject_pk_info': { 'algorithm': { 'algorithm': 'rsa', 'parameters': None, }, 'public_key': RSAPublicKey.load(encode_rsa_public_key(pub)), }, }) # Sign the CSR Info value = priv.sign(info.dump(), mechanism=Mechanism.SHA1_RSA_PKCS) csr = CertificationRequest({ 'certification_request_info': info, 'signature_algorithm': { 'algorithm': 'sha1_rsa', 'parameters': None, }, 'signature': value, }) # Pipe our CSR to OpenSSL to verify it with subprocess.Popen((OPENSSL, 'req', '-inform', 'der', '-noout', '-verify'), stdin=subprocess.PIPE, stdout=subprocess.DEVNULL) as proc: proc.stdin.write(csr.dump()) proc.stdin.close() self.assertEqual(proc.wait(), 0)
def scep(): storage = FileStorage(current_app.config['SCEPY_CA_ROOT']) op = request.args.get('operation') current_app.logger.info("Operation: %s, From: %s, User-Agent: %s", op, request.remote_addr, request.user_agent) dump_dir = current_app.config.get('SCEPY_DUMP_DIR', None) if dump_dir is not None and not os.path.exists(dump_dir): current_app.logger.debug("Creating dir for request dumps: %s", dump_dir) os.mkdir(dump_dir) dump_filename_prefix = "request-{}".format( datetime.datetime.now().timestamp()) if storage.exists(): g.ca = CertificateAuthority(storage) else: subject = x509.Name([ x509.NameAttribute(x509.NameOID.COMMON_NAME, current_app.config['SCEPY_CA_X509_CN']), x509.NameAttribute(x509.NameOID.ORGANIZATION_NAME, current_app.config['SCEPY_CA_X509_O']), x509.NameAttribute(x509.NameOID.COUNTRY_NAME, current_app.config['SCEPY_CA_X509_C']) ]) g.ca = CertificateAuthority.create(storage, subject) ca = g.ca if op == 'GetCACert': certs = [ca.certificate] if len(certs) == 1 and not current_app.config.get( 'SCEPY_FORCE_DEGENERATE_FOR_SINGLE_CERT', False): return Response(certs[0].public_bytes(Encoding.DER), mimetype='application/x-x509-ca-cert') elif len(certs): raise ValueError( 'cryptography cannot produce degenerate pkcs7 certs') # p7_degenerate = degenerate_pkcs7_der(certs) # return Response(p7_degenerate, mimetype='application/x-x509-ca-ra-cert') elif op == 'GetCACaps': return Response('\n'.join(CACAPS), mimetype='text/plain') elif op == 'PKIOperation': if request.method == 'GET': msg = request.args.get('message') # note: OS X improperly encodes the base64 query param by not # encoding spaces as %2B and instead leaving them as +'s msg = b64decode(msg.replace(' ', '+')) elif request.method == 'POST': # workaround for Flask/Werkzeug lack of chunked handling if 'chunked' in request.headers.get('Transfer-Encoding', ''): msg = request.environ['body_copy'] else: msg = request.data if dump_dir is not None: filename = "{}.bin".format(dump_filename_prefix) current_app.logger.debug('Dumping request to {}'.format( os.path.join(dump_dir, filename))) with open(os.path.join(dump_dir, filename), 'wb') as fd: fd.write(msg) req = SCEPMessage.parse(msg) current_app.logger.debug('Message Type: %s', req.message_type) print(req.debug()) if req.message_type == MessageType.PKCSReq or req.message_type == MessageType.RenewalReq: cakey = ca.private_key cacert = ca.certificate der_req = req.get_decrypted_envelope_data( cacert, cakey, ) if dump_dir is not None: filename = os.path.join(dump_dir, '{}.csr'.format(dump_filename_prefix)) current_app.logger.debug( 'Dumping CertificateSigningRequest to {}'.format( os.path.join(dump_dir, filename))) with open(filename, 'wb') as fd: fd.write(der_req) cert_req = x509.load_der_x509_csr(der_req, backend=default_backend()) req_info_bytes = cert_req.tbs_certrequest_bytes # Check the challenge password (unless it is a renewal) if 'SCEPY_CHALLENGE' in current_app.config and req.message_type == MessageType.PKCSReq: req_info = CertificationRequestInfo.load(req_info_bytes) for attr in req_info['attributes']: if attr['type'].native == 'challenge_password': assert len(attr['values']) == 1 challenge_password = attr['values'][0].native if challenge_password != current_app.config[ 'SCEPY_CHALLENGE']: current_app.logger.warning( 'Client did not send the correct challenge') signer = Signer(cacert, cakey, 'sha512') reply = PKIMessageBuilder().message_type( MessageType.CertRep).transaction_id( req.transaction_id).pki_status( PKIStatus.FAILURE, FailInfo.BadRequest).recipient_nonce( req.sender_nonce).add_signer( signer).finalize() return Response( reply.dump(), mimetype='application/x-pki-message') else: current_app.logger.debug( 'Client sent correct challenge') break current_app.logger.warning( 'Client did not send any challenge password, but there was one configured' ) signer = Signer(cacert, cakey, 'sha1') reply = PKIMessageBuilder().message_type( MessageType.CertRep).transaction_id( req.transaction_id).pki_status( PKIStatus.FAILURE, FailInfo.BadRequest).recipient_nonce( req.sender_nonce).add_signer( signer).finalize() return Response(reply.dump(), mimetype='application/x-pki-message') new_cert = ca.sign(cert_req, 'sha1') degenerate = create_degenerate_pkcs7(new_cert, ca.certificate) if dump_dir is not None: filename = os.path.join( dump_dir, '{}-degenerate.bin'.format(dump_filename_prefix)) with open(filename, 'wb') as fd: fd.write(degenerate.dump()) envelope, _, _ = PKCSPKIEnvelopeBuilder().encrypt( degenerate.dump(), 'aes256').add_recipient(req.certificates[0]).finalize() signer = Signer(cacert, cakey, 'sha1') reply = PKIMessageBuilder().message_type( MessageType.CertRep).transaction_id( req.transaction_id).pki_status( PKIStatus.SUCCESS).recipient_nonce( req.sender_nonce).sender_nonce().pki_envelope( envelope).add_signer(signer).finalize() if dump_dir is not None: filename = os.path.join( dump_dir, '{}-reply.bin'.format(dump_filename_prefix)) with open(filename, 'wb') as fd: fd.write(reply.dump()) current_app.logger.debug("Sending CertRep") return Response(reply.dump(), mimetype='application/x-pki-message') else: current_app.logger.error('unhandled SCEP message type: %d', req.message_type) return '' else: abort(404, 'unknown SCEP operation')
def scep(): op = request.args.get('operation') if storage.exists(): g.ca = CertificateAuthority(storage) else: subject = x509.Name([ x509.NameAttribute(x509.NameOID.COMMON_NAME, app.config['CA_X509_CN']), x509.NameAttribute(x509.NameOID.ORGANIZATION_NAME, app.config['CA_X509_O']), x509.NameAttribute(x509.NameOID.COUNTRY_NAME, app.config['CA_X509_C']) ]) g.ca = CertificateAuthority.create(storage, subject) ca = g.ca if op == 'GetCACert': certs = [ca.certificate] if len(certs) == 1 and not app.config.get('FORCE_DEGENERATE_FOR_SINGLE_CERT', False): return Response(certs[0].public_bytes(Encoding.DER), mimetype='application/x-x509-ca-cert') elif len(certs): raise ValueError('cryptography cannot produce degenerate pkcs7 certs') # p7_degenerate = degenerate_pkcs7_der(certs) # return Response(p7_degenerate, mimetype='application/x-x509-ca-ra-cert') elif op == 'GetCACaps': return '\n'.join(CACAPS) elif op == 'PKIOperation': if request.method == 'GET': msg = request.args.get('message') # note: OS X improperly encodes the base64 query param by not # encoding spaces as %2B and instead leaving them as +'s msg = b64decode(msg.replace(' ', '+')) elif request.method == 'POST': # workaround for Flask/Werkzeug lack of chunked handling if 'chunked' in request.headers.get('Transfer-Encoding', ''): msg = request.environ['body_copy'] else: msg = request.data req = SCEPMessage.parse(msg) app.logger.debug('Received SCEPMessage, details follow') req.debug() if req.message_type == MessageType.PKCSReq or req.message_type == MessageType.RenewalReq: app.logger.debug('received {} SCEP message'.format(MessageType(req.message_type))) cakey = ca.private_key cacert = ca.certificate der_req = req.get_decrypted_envelope_data( cacert, cakey, ) cert_req = x509.load_der_x509_csr(der_req, backend=default_backend()) req_info_bytes = cert_req.tbs_certrequest_bytes # Check the challenge password (unless it is a renewal) if 'SCEP_CHALLENGE' in app.config and req.message_type == MessageType.PKCSReq: req_info = CertificationRequestInfo.load(req_info_bytes) for attr in req_info['attributes']: if attr['type'].native == 'challenge_password': assert len(attr['values']) == 1 challenge_password = attr['values'][0].native if challenge_password != app.config['SCEP_CHALLENGE']: app.logger.warning('Client did not send the correct challenge') signer = Signer(cacert, cakey) reply = PKIMessageBuilder().message_type( MessageType.CertRep ).transaction_id( req.transaction_id ).pki_status( PKIStatus.FAILURE, FailInfo.BadRequest ).recipient_nonce( req.sender_nonce ).add_signer(signer).finalize() return Response(reply.dump(), mimetype='application/x-pki-message') else: break app.logger.warning('Client did not send any challenge password, but there was one configured') signer = Signer(cacert, cakey) reply = PKIMessageBuilder().message_type( MessageType.CertRep ).transaction_id( req.transaction_id ).pki_status( PKIStatus.FAILURE, FailInfo.BadRequest ).recipient_nonce( req.sender_nonce ).add_signer(signer).finalize() return Response(reply.dump(), mimetype='application/x-pki-message') # CA should persist all signed certs itself new_cert = ca.sign(cert_req) degenerate = create_degenerate_certificate(new_cert) # with open('/tmp/degenerate.der', 'wb') as fd: # fd.write(degenerate.dump()) envelope, _, _ = PKCSPKIEnvelopeBuilder().encrypt(degenerate.dump(), 'aes').add_recipient( req.certificates[0]).finalize() signer = Signer(cacert, cakey, 'sha512') reply = PKIMessageBuilder().message_type( MessageType.CertRep ).transaction_id( req.transaction_id ).pki_status( PKIStatus.SUCCESS ).recipient_nonce( req.sender_nonce ).pki_envelope( envelope ).certificates(new_cert).add_signer(signer).finalize() # res = SCEPMessage.parse(reply.dump()) # app.logger.debug('Reply with CertRep, details follow') # res.debug() # with open('/tmp/reply.bin', 'wb') as fd: # fd.write(reply.dump()) return Response(reply.dump(), mimetype='application/x-pki-message') else: app.logger.error('unhandled SCEP message type: %d', req.message_type) return '' else: abort(404, 'unknown SCEP operation')
# Initialise our PKCS#11 library lib = pkcs11.lib('/usr/local/lib/softhsm/libsofthsm2.so') token = lib.get_token(token_label='My token 1') cn = 'vcert1001.venafi.example' with token.open(user_pin='1234') as session: pub, priv = session.generate_keypair(KeyType.RSA, 2048) info = CertificationRequestInfo({ 'version': 0, 'subject': Name.build({ 'common_name': cn, }), 'subject_pk_info': { 'algorithm': { 'algorithm': 'rsa', 'parameters': None, }, 'public_key': RSAPublicKey.load(encode_rsa_public_key(pub)), }, }) # Sign the CSR Info value = priv.sign(info.dump(), mechanism=Mechanism.SHA1_RSA_PKCS) csr = CertificationRequest({ 'certification_request_info': info, 'signature_algorithm': { 'algorithm': 'sha1_rsa',