Feat: Added CA-merged with Securid-Principals, Depart, Client-CLI
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
"""Cryptographic utilities for SSH operations."""
|
||||
import hashlib
|
||||
import base64
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def compute_ssh_fingerprint(public_key_str: str, hash_algorithm: str = "sha256") -> str:
|
||||
"""Compute the fingerprint of an SSH public key.
|
||||
|
||||
Args:
|
||||
public_key_str: SSH public key in OpenSSH format
|
||||
hash_algorithm: Hash algorithm to use (sha256, sha1, md5)
|
||||
|
||||
Returns:
|
||||
Fingerprint string in the format "algorithm:hex_digest"
|
||||
|
||||
Example:
|
||||
>>> key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKp2..."
|
||||
>>> fp = compute_ssh_fingerprint(key)
|
||||
>>> print(fp)
|
||||
sha256:Kb+...
|
||||
"""
|
||||
if not public_key_str:
|
||||
raise ValueError("Public key string is empty")
|
||||
|
||||
# Parse OpenSSH format: "ssh-ed25519 <base64> [comment]"
|
||||
parts = public_key_str.strip().split()
|
||||
if len(parts) < 2:
|
||||
raise ValueError("Invalid OpenSSH public key format")
|
||||
|
||||
try:
|
||||
# The base64-encoded key is the second part
|
||||
key_bytes = base64.b64decode(parts[1])
|
||||
except Exception as e:
|
||||
raise ValueError(f"Failed to decode public key: {str(e)}")
|
||||
|
||||
# Compute hash
|
||||
if hash_algorithm == "sha256":
|
||||
digest = hashlib.sha256(key_bytes).digest()
|
||||
# SSH format uses base64 encoding without padding
|
||||
fingerprint = base64.b64encode(digest).decode().rstrip('=')
|
||||
elif hash_algorithm == "sha1":
|
||||
digest = hashlib.sha1(key_bytes).hexdigest()
|
||||
fingerprint = digest
|
||||
elif hash_algorithm == "md5":
|
||||
digest = hashlib.md5(key_bytes).hexdigest()
|
||||
# Format as colons
|
||||
fingerprint = ':'.join(digest[i:i+2] for i in range(0, len(digest), 2))
|
||||
else:
|
||||
raise ValueError(f"Unsupported hash algorithm: {hash_algorithm}")
|
||||
|
||||
return f"{hash_algorithm}:{fingerprint}"
|
||||
|
||||
|
||||
def verify_ssh_key_format(public_key_str: str) -> bool:
|
||||
"""Verify that a string is in valid OpenSSH public key format.
|
||||
|
||||
Args:
|
||||
public_key_str: Potential SSH public key
|
||||
|
||||
Returns:
|
||||
True if valid OpenSSH format, False otherwise
|
||||
"""
|
||||
if not public_key_str or not isinstance(public_key_str, str):
|
||||
return False
|
||||
|
||||
parts = public_key_str.strip().split()
|
||||
|
||||
# Must have at least key type and key material
|
||||
if len(parts) < 2:
|
||||
return False
|
||||
|
||||
key_type = parts[0]
|
||||
|
||||
# Valid key types
|
||||
valid_types = [
|
||||
'ssh-rsa',
|
||||
'ssh-ed25519',
|
||||
'ecdsa-sha2-nistp256',
|
||||
'ecdsa-sha2-nistp384',
|
||||
'ecdsa-sha2-nistp521',
|
||||
'ssh-dss',
|
||||
]
|
||||
|
||||
if key_type not in valid_types:
|
||||
return False
|
||||
|
||||
# Try to decode base64
|
||||
try:
|
||||
base64.b64decode(parts[1])
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def extract_ssh_key_type(public_key_str: str) -> Optional[str]:
|
||||
"""Extract the key type from an OpenSSH public key.
|
||||
|
||||
Args:
|
||||
public_key_str: SSH public key in OpenSSH format
|
||||
|
||||
Returns:
|
||||
Key type (e.g., "ssh-ed25519") or None if invalid
|
||||
"""
|
||||
if not verify_ssh_key_format(public_key_str):
|
||||
return None
|
||||
|
||||
return public_key_str.strip().split()[0]
|
||||
|
||||
|
||||
def extract_ssh_key_comment(public_key_str: str) -> Optional[str]:
|
||||
"""Extract the comment from an OpenSSH public key.
|
||||
|
||||
Args:
|
||||
public_key_str: SSH public key in OpenSSH format
|
||||
|
||||
Returns:
|
||||
Comment string or None if not present
|
||||
"""
|
||||
if not verify_ssh_key_format(public_key_str):
|
||||
return None
|
||||
|
||||
parts = public_key_str.strip().split()
|
||||
if len(parts) >= 3:
|
||||
# Everything after the second part is the comment
|
||||
return ' '.join(parts[2:])
|
||||
|
||||
return None
|
||||
Reference in New Issue
Block a user