Skip to content

Commit

Permalink
v0.2.6, "-o ext" added, add AKI/SKI in gencert"
Browse files Browse the repository at this point in the history
  • Loading branch information
yaroslaff committed Nov 18, 2024
1 parent 2436825 commit 71ae0a3
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 13 deletions.
2 changes: 1 addition & 1 deletion showcert/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.2.5'
__version__ = '0.2.6'
26 changes: 18 additions & 8 deletions showcert/gencert.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ def generate_cert(hostnames: list[str], ip_addresses: list[str] = None,
"""Generates self signed certificate for a hostname, and optional IP addresses."""

# Generate our key
certkey = rsa.generate_private_key(
privkey = rsa.generate_private_key(
public_exponent=65537,
key_size=bits,
backend=default_backend(),
)

name = x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, hostnames[0])
])
Expand All @@ -59,19 +59,23 @@ def generate_cert(hostnames: list[str], ip_addresses: list[str] = None,

# path_len=0 means this cert can only sign itself, not other certs.

now = datetime.datetime.utcnow()
now = datetime.datetime.now(datetime.timezone.utc)





builder = x509.CertificateBuilder() \
.subject_name(name) \
.public_key(certkey.public_key()) \
.public_key(privkey.public_key()) \
.serial_number(x509.random_serial_number()) \
.not_valid_before(now) \
.not_valid_after(now + datetime.timedelta(days=days)) \

# Add Subject Key Identified (SKI)
ski = x509.SubjectKeyIdentifier.from_public_key(privkey.public_key())
builder = builder.add_extension(ski, critical=False)

if ca:
print("Generate CA certificate")
basic_constraints = x509.BasicConstraints(ca=True, path_length=None)
Expand All @@ -82,7 +86,7 @@ def generate_cert(hostnames: list[str], ip_addresses: list[str] = None,
# b"CA:TRUE, pathlen:0"),

else:
basic_constraints = x509.BasicConstraints(ca=True, path_length=0)
basic_constraints = x509.BasicConstraints(ca=False, path_length=None)
builder = builder.add_extension(basic_constraints, False) \
.add_extension(san, False)

Expand All @@ -94,19 +98,25 @@ def generate_cert(hostnames: list[str], ip_addresses: list[str] = None,

# SIGN
if cakey:
aki = x509.AuthorityKeyIdentifier.from_issuer_public_key(cakey.public_key())
builder = builder.add_extension(aki, critical=False)

# sign with CA private key
cert = builder.sign(private_key=cakey,
algorithm=hashes.SHA256(),
backend=default_backend())
else:
else:
aki = x509.AuthorityKeyIdentifier.from_issuer_public_key(privkey.public_key())
builder = builder.add_extension(aki, critical=False)

# self-sign
cert = builder.sign(private_key=certkey,
cert = builder.sign(private_key=privkey,
algorithm=hashes.SHA256(),
backend=default_backend())


cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM)
key_pem = certkey.private_bytes(
key_pem = privkey.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
Expand Down
32 changes: 28 additions & 4 deletions showcert/showcert.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import sys
import argparse
import re
import hashlib
import ssl
import socket
# import OpenSSL
Expand Down Expand Up @@ -65,7 +66,7 @@ def get_args():
formatter_class=argparse.RawTextHelpFormatter, epilog=epilog)
parser.add_argument('CERT', nargs='+', help='path, - (stdin), ":le" (letsencrypt cert path), hostname or hostname:port')
parser.add_argument('-i', '--insecure', default=False, action='store_true', help='Do not verify remote certificate')
parser.add_argument('--output', '-o', default='brief', help='output format: brief, full, names, dnames (for certbot), pem, no.')
parser.add_argument('--output', '-o', default='brief', help='output format: brief, extended (ext), full, names, dnames (for certbot), pem, no.')
parser.add_argument('-c','--chain', default=False, action='store_true', help='Show chain (not only server certificate)')
parser.add_argument('-w', '--warn', default=None, metavar='DAYS', nargs='?', type=int, const=20, help='Warn about expiring certificates (def: 20 days)')

Expand Down Expand Up @@ -358,11 +359,17 @@ def print_dnames(crt):
print('-d', ' -d '.join(names))


def print_cert(crt: X509, addr=None, verified=False):
def print_cert(crt: X509, fmt='brief', addr=None, verified=False):

def tlist2str(tlist):
return ' '.join([ '{}={}'.format(t[0].decode(), t[1].decode()) for t in tlist ])

def get_ext(str: X509, short_name: str):
for i in range(crt.get_extension_count()):
ext = crt.get_extension(i)
if ext.get_short_name() == short_name.encode():
return str(ext) # Convert to string for readability
return None

tags = list()

Expand All @@ -377,11 +384,20 @@ def tlist2str(tlist):
if verified:
tags.append('[CHAIN-VERIFIED]')


nbefore = datetime.strptime(crt.get_notBefore().decode(), '%Y%m%d%H%M%SZ')
nafter = datetime.strptime(crt.get_notAfter().decode(), '%Y%m%d%H%M%SZ')
daysold = (datetime.now() - nbefore).days
daysleft = (nafter - datetime.now()).days
issuer = tlist2str(crt.get_issuer().get_components())
fingerprint = crt.digest("sha256").decode("utf-8")

ski = get_ext(str, "subjectKeyIdentifier")
aki = get_ext(str, "authorityKeyIdentifier")
#ski = crt.extensions.get_extension_for_oid(x509.ExtensionOID.SUBJECT_KEY_IDENTIFIER) \
# .value.digest.hex()



names = get_names(crt)

Expand All @@ -391,6 +407,14 @@ def tlist2str(tlist):
print("notBefore: {nbefore} ({days} days old)".format(nbefore=nbefore, days=daysold))
print("notAfter: {nafter} ({days} days left)".format(nafter=nafter, days = daysleft))
print("Issuer:", issuer)

if fmt.startswith('ext'):
print("Fingerprint (sha256):", fingerprint)
if ski:
print("SKI (sha256):", ski)
if aki:
print("AKI (sha256):", aki)

if tags:
print("Tags:", ' '.join(tags))

Expand Down Expand Up @@ -452,11 +476,11 @@ def process_cert(CERT, name=None, insecure=False, warn=False, starttls='auto'):
r = dump_certificate(FILETYPE_PEM, _c)
print(r.decode(), end='')
return 0
elif out == 'brief':
elif out in ['brief', 'ext', 'extended']:
for i,_c in enumerate(chain):
if i>0:
print()
print_cert(_c, addr=sock_host, verified=verified)
print_cert(crt = _c, fmt=out, addr=sock_host, verified=verified)

elif out == 'full':
for i,_c in enumerate(chain):
Expand Down

0 comments on commit 71ae0a3

Please sign in to comment.