Esempio n. 1
0
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()
Esempio n. 2
0
 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
Esempio n. 3
0
    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)
Esempio n. 4
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')
Esempio n. 5
0
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')
Esempio n. 6
0
# 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',