Last active
September 12, 2021 00:31
-
-
Save mzpqnxow/b863ee8ea4b30c96c10f7ee4d101e887 to your computer and use it in GitHub Desktop.
Generate a mapping for IANA, OpenSSL and the int16 representation of SSL/TLS cipher-suites
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# | |
# Parse https://testssl.sh/openssl-iana.mapping.html or a copy/paste of | |
# the content from a browser, drop it in a line-based JSON file | |
# | |
# This lets you quickly translate from IANA<->OpenSSL<->int16 which is | |
# useful for unusual people :> | |
# | |
# Requirements: lxml, pandas>=1.2 | |
# If Pandas is too old, you will get: | |
# TypeError: applymap() got an unexpected keyword argument 'na_action' | |
# Install Pandas >= 1.2 | |
# | |
# - (C) 2021, [email protected], BSD 3-Clause License | |
# | |
import pandas as pd | |
from typing import Optional, Iterable | |
SSL_MAPPING_URL = 'https://testssl.sh/openssl-iana.mapping.html' | |
# You can copy+paste the table from a browser into a file | |
# and save it locally if you want, it loads fine. Otherwise | |
# leave this None | |
# SSL_MAPPING_CSV = 'copy-pasted-from-testssl-sh.csv' | |
SSL_MAPPING_CSV = None | |
DEFAULT_COLUMNS = ['suite_id', 'openssl_name', 'kex', 'symmetric', 'keysize', 'iana_name'] | |
OUTFILE = 'cipher_map.ndjson' | |
def postprocess(df: pd.DataFrame): | |
df = df.merge( | |
df['keysize'].str.extract(r'(\d+),?(.*)', expand=True), | |
left_index=True, | |
right_index=True).rename(columns={0: 'keysize_bits', 1: 'export'}) | |
df.drop(columns=['keysize'], inplace=True) | |
df['suite_id'] = df['suite_id'].str.strip('[]') | |
df[['suite_id', 'keysize_bits']] = df[['suite_id', 'keysize_bits']].applymap( | |
lambda s: int(s, base=0x10), na_action='ignore') | |
df['export'] = df['export'].str.strip().map(bool, na_action='ignore') | |
return df | |
def from_url(url: str, flavor: str = 'lxml', | |
columns: Optional[Iterable[str]] = None) -> pd.DataFrame: | |
if columns is None: | |
columns = DEFAULT_COLUMNS | |
df = pd.read_html(SSL_MAPPING_URL, flavor='lxml').pop() | |
return df.rename(columns=dict(zip(df.columns, columns))) | |
def from_csv(infile: str, names: Iterable[str] = None) -> pd.DataFrame: | |
if names is None: | |
names = DEFAULT_COLUMNS | |
return pd.read_csv(infile, delimiter='\t', names=names) | |
def main(): | |
df = from_csv(SSL_MAPPING_CSV) if SSL_MAPPING_CSV is not None else from_url(SSL_MAPPING_URL) | |
df = postprocess(df) | |
df.to_json(OUTFILE, orient='records', lines=True) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment