Skip to content

Commit

Permalink
Merge pull request #3 from jasonrig/dummy-key
Browse files Browse the repository at this point in the history
add dummy key; code cleanup; update gh actions
  • Loading branch information
jasonrig committed Dec 26, 2023
2 parents 2ea2cce + 7a3b6fe commit 6834ddd
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 31 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
with:
submodules: 'true'
- name: Set up Python 3.7
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: 3.7
- name: Install Protoc
Expand All @@ -35,13 +35,13 @@ jobs:
--outdir dist/
.
- name: Publish distribution 📦 to Test PyPI
uses: pypa/gh-action-pypi-publish@master
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip_existing: true
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
- name: Publish distribution 📦 to PyPI
if: startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@master
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
7 changes: 4 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,23 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v2
with:
submodules: 'true'
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Protoc
uses: arduino/setup-protoc@v1
- name: Install dependencies and build protobuf files
run: |
pip install -U pip
pip install -U setuptools
python setup.py build_proto
python -m pip install --upgrade pip
pip install pytest pytest-cov
pip install -e .[all]
- name: Test with pytest
Expand Down
5 changes: 4 additions & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion .idea/paramiko-cloud.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions paramiko_cloud/azure/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ class ECDSAKey(BaseKeyECDSA):
)

def __init__(self, credential: Union[DefaultAzureCredential, AzurePowerShellCredential,
InteractiveBrowserCredential, ChainedTokenCredential, EnvironmentCredential,
ManagedIdentityCredential, SharedTokenCacheCredential, AzureCliCredential,
VisualStudioCodeCredential],
InteractiveBrowserCredential, ChainedTokenCredential, EnvironmentCredential,
ManagedIdentityCredential, SharedTokenCacheCredential, AzureCliCredential,
VisualStudioCodeCredential],
vault_url: str, key_name: str):
vault_client = KeyClient(vault_url, credential=credential)
pub_key = vault_client.get_key(key_name)
Expand Down
8 changes: 4 additions & 4 deletions paramiko_cloud/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@ def __init__(self, curve: EllipticCurve):
self.curve = curve

@staticmethod
def digest(data: bytes, ec: ECDSA) -> bytes:
def digest(data: bytes, signature_algorithm: ECDSA) -> bytes:
"""
Calculates the hash of the given data according to the given elliptic curve key
Args:
data: the data for which to calculate the hash
ec: the elliptic curve key that will use the hash
signature_algorithm: the elliptic curve signature algorithm
Returns:
The hash of the data
"""
return getattr(hashlib, ec.algorithm.name)(data).digest()
return getattr(hashlib, signature_algorithm.algorithm.name)(data).digest()

def sign(self, data, signature_algorithm: ECDSA) -> bytes:
def sign(self, data: bytes, signature_algorithm: ECDSA) -> bytes:
"""
Calculate the signature for the given data
Expand Down
Empty file.
32 changes: 32 additions & 0 deletions paramiko_cloud/dummy/keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from typing import Optional

from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey, ECDSA
from cryptography.hazmat.primitives.serialization import load_pem_private_key

from paramiko_cloud.base import BaseKeyECDSA, CloudSigningKey


class _LocalSigningKey(CloudSigningKey):
"""
A dummy signing key
"""
def __init__(self, key: EllipticCurvePrivateKey):
super().__init__(key.curve)
self.key = key

def sign(self, data: bytes, signature_algorithm: ECDSA) -> bytes:
return self.key.sign(data, signature_algorithm)


class ECDSAKey(BaseKeyECDSA):
"""
A dummy key that demonstrates the abstraction, but just loads they key from file.
Args:
pem_private_key: A PEM-formatted private key
password: An optional password to decrypt the private key
"""
def __init__(self, pem_private_key: bytes, password: Optional[bytes] = None):
private_key: EllipticCurvePrivateKey = load_pem_private_key(pem_private_key, password)
public_key = private_key.public_key()
super().__init__((_LocalSigningKey(private_key), public_key))
45 changes: 45 additions & 0 deletions paramiko_cloud/dummy/test_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from unittest import TestCase

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
from paramiko.rsakey import RSAKey

from paramiko_cloud.dummy.keys import ECDSAKey
from paramiko_cloud.test_helpers import parse_certificate, sha256_fingerprint

private_key = ec.generate_private_key(ec.SECP256R1()).private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)


class TestECDSAKey(TestCase):
def test_key_from_cloud_can_sign(self):
key = ECDSAKey(private_key)
signature = key.sign_ssh_data(b"hello world")
signature.rewind()
self.assertTrue(key.verify_ssh_sig(b"hello world", signature), "Signature is invalid")

def test_key_from_cloud_can_produce_valid_certificate(self):
ca_key = ECDSAKey(private_key)
client_key = RSAKey.generate(1024)
cert_string = ca_key.sign_certificate(client_key, ["test.user"]).cert_string()
exit_code, cert_details = parse_certificate(cert_string)
self.assertEqual(
cert_details.public_key,
"RSA-CERT SHA256:{}".format(sha256_fingerprint(client_key))
)
self.assertEqual(
cert_details.signing_ca,
"ECDSA SHA256:{} (using ecdsa-sha2-nistp{})".format(
sha256_fingerprint(ca_key),
ca_key.ecdsa_curve.key_length
)
)
self.assertEqual(
exit_code, 0,
"Could not parse generated certificate with ssh-keygen, exit code {}".format(
exit_code
)
)
38 changes: 22 additions & 16 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import ast
import itertools
import os.path
from distutils.cmd import Command
from glob import glob
from typing import List, Tuple

from setuptools import Command
from setuptools import setup

setup_path = os.path.dirname(os.path.realpath(__file__))
Expand Down Expand Up @@ -39,10 +39,10 @@ def run(self):

# Build the gRPC stubs
grpc_tools.protoc.main([
'grpc_tools.protoc',
'-I{}'.format(self.GRPC_PROTO_PATH),
'--python_out={}'.format(self.PYTHON_OUT_PATH),
'--grpc_python_out={}'.format(self.PYTHON_OUT_PATH),
"grpc_tools.protoc",
"-I{}".format(self.GRPC_PROTO_PATH),
"--python_out={}".format(self.PYTHON_OUT_PATH),
"--grpc_python_out={}".format(self.PYTHON_OUT_PATH),
os.path.join(self.GRPC_PROTO_PATH, "rpc.proto")
])

Expand Down Expand Up @@ -81,22 +81,28 @@ def run(self):
}
extras_require["all"] = list(itertools.chain(*extras_require.values()))

with open("README.md", "rt") as f:
long_description = f.read()

setup(
name='paramiko-cloud',
version='1.2.1',
version='1.3.0',
packages=[
'paramiko_cloud',
'paramiko_cloud.aws',
'paramiko_cloud.azure',
'paramiko_cloud.gcp',
'paramiko_cloud.protobuf'
"paramiko_cloud",
"paramiko_cloud.dummy",
"paramiko_cloud.aws",
"paramiko_cloud.azure",
"paramiko_cloud.gcp",
"paramiko_cloud.protobuf"
],
include_package_data=True,
url='https://github.com/jasonrig/paramiko-cloud/',
license='MIT',
author='Jason Rigby',
author_email='hello@jasonrig.by',
description='Use cloud-managed keys to sign SSH certificates',
url="https://github.com/jasonrig/paramiko-cloud/",
license="MIT",
author="Jason Rigby",
author_email="hello@jasonrig.by",
description="Use cloud-managed keys to sign SSH certificates",
long_description=long_description,
long_description_content_type='text/markdown',
setup_requires=[
"protobuf_distutils",
"grpcio-tools",
Expand Down

0 comments on commit 6834ddd

Please sign in to comment.