def build_key_and_cert(subject_name, *, ca=False, ca_key=None, issuer_name=''): if not issuer_name: issuer_name = subject_name # DDS-Security section 9.3.1 calls for prime256v1, for which SECP256R1 is an alias private_key = ec.generate_private_key(ec.SECP256R1, cryptography_backend()) if not ca_key: ca_key = private_key if ca: extension = x509.BasicConstraints(ca=True, path_length=1) else: extension = x509.BasicConstraints(ca=False, path_length=None) utcnow = datetime.datetime.utcnow() builder = x509.CertificateBuilder().issuer_name(issuer_name).serial_number( x509.random_serial_number() ).not_valid_before( # Using a day earlier here to prevent Connext (5.3.1) from complaining # when extracting it from the permissions file and thinking it's in the future # https://github.com/ros2/ci/pull/436#issuecomment-624874296 utcnow - datetime.timedelta(days=1)).not_valid_after( # TODO: This should not be hard-coded utcnow + datetime.timedelta(days=3650)).public_key( private_key.public_key()).subject_name( subject_name).add_extension(extension, critical=ca) cert = builder.sign(ca_key, hashes.SHA256(), cryptography_backend()) return (cert, private_key)
def _build_key_and_cert(subject_name, *, ca=False, ca_key=None, issuer_name=''): if not issuer_name: issuer_name = subject_name # DDS-Security section 9.3.1 calls for prime256v1, for which SECP256R1 is an alias private_key = ec.generate_private_key(ec.SECP256R1, cryptography_backend()) if not ca_key: ca_key = private_key if ca: extension = x509.BasicConstraints(ca=True, path_length=1) else: extension = x509.BasicConstraints(ca=False, path_length=None) utcnow = datetime.datetime.utcnow() builder = x509.CertificateBuilder().issuer_name(issuer_name).serial_number( x509.random_serial_number()).not_valid_before(utcnow).not_valid_after( # TODO: This should not be hard-coded utcnow + datetime.timedelta(days=3650)).public_key( private_key.public_key()).subject_name( subject_name).add_extension(extension, critical=ca) cert = builder.sign(ca_key, hashes.SHA256(), cryptography_backend()) return (cert, private_key)
def test_ca_key(keystore_dir): with open(os.path.join(keystore_dir, 'ca.key.pem'), 'rb') as f: key = load_pem_private_key(f.read(), password=None, backend=cryptography_backend()) public = key.public_key() assert public.curve.name == 'secp256r1'
def check_ca_key_pem(path): with open(path, 'rb') as f: key = load_pem_private_key(f.read(), password=None, backend=cryptography_backend()) public = key.public_key() assert public.curve.name == 'secp256r1'
def _create_key_and_cert(keystore_ca_cert_path, keystore_ca_key_path, identity, cert_path, key_path): # Load the CA cert and key from disk with open(keystore_ca_cert_path, 'rb') as f: ca_cert = x509.load_pem_x509_certificate(f.read(), cryptography_backend()) with open(keystore_ca_key_path, 'rb') as f: ca_key = serialization.load_pem_private_key(f.read(), None, cryptography_backend()) cert, private_key = _build_key_and_cert(x509.Name( [x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, identity)]), issuer_name=ca_cert.subject, ca_key=ca_key) _write_key(private_key, key_path) _write_cert(cert, cert_path)
def _create_smime_signed_file(cert_path, key_path, unsigned_file_path, signed_file_path): # Load the CA cert and key from disk with open(cert_path, 'rb') as cert_file: cert = x509.load_pem_x509_certificate(cert_file.read(), cryptography_backend()) with open(key_path, 'rb') as key_file: private_key = serialization.load_pem_private_key( key_file.read(), None, cryptography_backend()) # Get the contents of the unsigned file, which we're about to sign with open(unsigned_file_path, 'rb') as f: content = f.read() # Sign the contents, and write the result to the appropriate place with open(signed_file_path, 'wb') as f: f.write(_sign_bytes(cert, private_key, content))
def test_ca_cert(keystore_dir): with open(os.path.join(keystore_dir, 'ca.cert.pem'), 'rb') as f: cert = x509.load_pem_x509_certificate(f.read(), cryptography_backend()) names = cert.subject.get_attributes_for_oid( x509.oid.NameOID.COMMON_NAME) assert len(names) == 1 assert names[0].value == _DEFAULT_COMMON_NAME names = cert.subject.get_attributes_for_oid( x509.oid.NameOID.ORGANIZATION_NAME) assert len(names) == 0
def check_ca_cert_pem(path): with open(path, 'rb') as f: cert = x509.load_pem_x509_certificate(f.read(), cryptography_backend()) names = cert.subject.get_attributes_for_oid( x509.oid.NameOID.COMMON_NAME) assert len(names) == 1 assert names[0].value == u'sros2testCA' names = cert.subject.get_attributes_for_oid( x509.oid.NameOID.ORGANIZATION_NAME) assert len(names) == 0
def load_certificate_request(path, backend='pyopenssl'): """Load the specified certificate signing request.""" try: with open(path, 'rb') as csr_fh: csr_content = csr_fh.read() except (IOError, OSError) as exc: raise OpenSSLObjectError(exc) if backend == 'pyopenssl': return crypto.load_certificate_request(crypto.FILETYPE_PEM, csr_content) elif backend == 'cryptography': return x509.load_pem_x509_csr(csr_content, cryptography_backend())
def load_certificate(path, content=None, backend='pyopenssl'): """Load the specified certificate.""" try: if content is None: with open(path, 'rb') as cert_fh: cert_content = cert_fh.read() else: cert_content = content if backend == 'pyopenssl': return crypto.load_certificate(crypto.FILETYPE_PEM, cert_content) elif backend == 'cryptography': return x509.load_pem_x509_certificate(cert_content, cryptography_backend()) except (IOError, OSError) as exc: raise OpenSSLObjectError(exc)
def main(): module = AnsibleModule(argument_spec=dict( ca_cert=dict(type='path'), host=dict(type='str', required=True), port=dict(type='int', required=True), proxy_host=dict(type='str'), proxy_port=dict(type='int', default=8080), timeout=dict(type='int', default=10), select_crypto_backend=dict( type='str', choices=['auto', 'pyopenssl', 'cryptography'], default='auto'), ), ) ca_cert = module.params.get('ca_cert') host = module.params.get('host') port = module.params.get('port') proxy_host = module.params.get('proxy_host') proxy_port = module.params.get('proxy_port') timeout = module.params.get('timeout') backend = module.params.get('select_crypto_backend') if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion( MINIMAL_CRYPTOGRAPHY_VERSION) can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion( MINIMAL_PYOPENSSL_VERSION) # First try cryptography, then pyOpenSSL if can_use_cryptography: backend = 'cryptography' elif can_use_pyopenssl: backend = 'pyopenssl' # Success? if backend == 'auto': module.fail_json(msg=( "Can't detect any of the required Python libraries " "cryptography (>= {0}) or PyOpenSSL (>= {1})" ).format(MINIMAL_CRYPTOGRAPHY_VERSION, MINIMAL_PYOPENSSL_VERSION)) if backend == 'pyopenssl': if not PYOPENSSL_FOUND: module.fail_json(msg=missing_required_lib( 'pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), exception=PYOPENSSL_IMP_ERR) module.deprecate( 'The module is using the PyOpenSSL backend. This backend has been deprecated', version='2.13') elif backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib( 'cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) result = dict(changed=False, ) if not PYOPENSSL_FOUND: module.fail_json(msg=missing_required_lib('pyOpenSSL >= 0.15'), exception=PYOPENSSL_IMP_ERR) if timeout: setdefaulttimeout(timeout) if ca_cert: if not isfile(ca_cert): module.fail_json(msg="ca_cert file does not exist") if proxy_host: if not HAS_CREATE_DEFAULT_CONTEXT: module.fail_json( msg= 'To use proxy_host, you must run the get_certificate module with Python 2.7 or newer.', exception=CREATE_DEFAULT_CONTEXT_IMP_ERR) try: connect = "CONNECT %s:%s HTTP/1.0\r\n\r\n" % (host, port) sock = socket() atexit.register(sock.close) sock.connect((proxy_host, proxy_port)) sock.send(connect.encode()) sock.recv(8192) ctx = create_default_context() ctx.check_hostname = False ctx.verify_mode = CERT_NONE if ca_cert: ctx.verify_mode = CERT_OPTIONAL ctx.load_verify_locations(cafile=ca_cert) cert = ctx.wrap_socket(sock, server_hostname=host).getpeercert(True) cert = DER_cert_to_PEM_cert(cert) except Exception as e: module.fail_json( msg="Failed to get cert from port with error: {0}".format(e)) else: try: cert = get_server_certificate((host, port), ca_certs=ca_cert) except Exception as e: module.fail_json( msg="Failed to get cert from port with error: {0}".format(e)) result['cert'] = cert if backend == 'pyopenssl': x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert) result['subject'] = {} for component in x509.get_subject().get_components(): result['subject'][component[0]] = component[1] result['expired'] = x509.has_expired() result['extensions'] = [] extension_count = x509.get_extension_count() for index in range(0, extension_count): extension = x509.get_extension(index) result['extensions'].append({ 'critical': extension.get_critical(), 'asn1_data': extension.get_data(), 'name': extension.get_short_name(), }) result['issuer'] = {} for component in x509.get_issuer().get_components(): result['issuer'][component[0]] = component[1] result['not_after'] = x509.get_notAfter() result['not_before'] = x509.get_notBefore() result['serial_number'] = x509.get_serial_number() result['signature_algorithm'] = x509.get_signature_algorithm() result['version'] = x509.get_version() elif backend == 'cryptography': x509 = cryptography.x509.load_pem_x509_certificate( to_bytes(cert), cryptography_backend()) result['subject'] = {} for attribute in x509.subject: result['subject'][crypto_utils.cryptography_oid_to_name( attribute.oid, short=True)] = attribute.value result['expired'] = x509.not_valid_after < datetime.datetime.utcnow() result['extensions'] = [] for dotted_number, entry in crypto_utils.cryptography_get_extensions_from_cert( x509).items(): oid = cryptography.x509.oid.ObjectIdentifier(dotted_number) result['extensions'].append({ 'critical': entry['critical'], 'asn1_data': base64.b64decode(entry['value']), 'name': crypto_utils.cryptography_oid_to_name(oid, short=True), }) result['issuer'] = {} for attribute in x509.issuer: result['issuer'][crypto_utils.cryptography_oid_to_name( attribute.oid, short=True)] = attribute.value result['not_after'] = x509.not_valid_after.strftime('%Y%m%d%H%M%SZ') result['not_before'] = x509.not_valid_before.strftime('%Y%m%d%H%M%SZ') result['serial_number'] = x509.serial_number result['signature_algorithm'] = crypto_utils.cryptography_oid_to_name( x509.signature_algorithm_oid) # We need the -1 offset to get the same values as pyOpenSSL if x509.version == cryptography.x509.Version.v1: result['version'] = 1 - 1 elif x509.version == cryptography.x509.Version.v3: result['version'] = 3 - 1 else: result['version'] = "unknown" module.exit_json(**result)
def load_cert(cert_path: pathlib.Path): with open(cert_path, 'rb') as cert_file: return x509.load_pem_x509_certificate(cert_file.read(), cryptography_backend())
def load_privatekey(path, passphrase=None, check_passphrase=True, backend='pyopenssl'): """Load the specified OpenSSL private key.""" try: with open(path, 'rb') as b_priv_key_fh: priv_key_detail = b_priv_key_fh.read() if backend == 'pyopenssl': # First try: try to load with real passphrase (resp. empty string) # Will work if this is the correct passphrase, or the key is not # password-protected. try: result = crypto.load_privatekey(crypto.FILETYPE_PEM, priv_key_detail, to_bytes(passphrase or '')) except crypto.Error as e: if len(e.args) > 0 and len(e.args[0]) > 0: if e.args[0][0][2] in ('bad decrypt', 'bad password read'): # This happens in case we have the wrong passphrase. if passphrase is not None: raise OpenSSLBadPassphraseError( 'Wrong passphrase provided for private key!') else: raise OpenSSLBadPassphraseError( 'No passphrase provided, but private key is password-protected!' ) raise OpenSSLObjectError( 'Error while deserializing key: {0}'.format(e)) if check_passphrase: # Next we want to make sure that the key is actually protected by # a passphrase (in case we did try the empty string before, make # sure that the key is not protected by the empty string) try: crypto.load_privatekey( crypto.FILETYPE_PEM, priv_key_detail, to_bytes('y' if passphrase == 'x' else 'x')) if passphrase is not None: # Since we can load the key without an exception, the # key isn't password-protected raise OpenSSLBadPassphraseError( 'Passphrase provided, but private key is not password-protected!' ) except crypto.Error as e: if passphrase is None and len(e.args) > 0 and len( e.args[0]) > 0: if e.args[0][0][2] in ('bad decrypt', 'bad password read'): # The key is obviously protected by the empty string. # Don't do this at home (if it's possible at all)... raise OpenSSLBadPassphraseError( 'No passphrase provided, but private key is password-protected!' ) elif backend == 'cryptography': try: result = load_pem_private_key(priv_key_detail, passphrase, cryptography_backend()) except TypeError as dummy: raise OpenSSLBadPassphraseError( 'Wrong or empty passphrase provided for private key') except ValueError as dummy: raise OpenSSLBadPassphraseError( 'Wrong passphrase provided for private key') return result except (IOError, OSError) as exc: raise OpenSSLObjectError(exc)