cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

u2f-setup-gen.py (4483B)


      1#!/usr/bin/env python3
      2#
      3# Libu2f-emu setup directory generator for USB U2F key emulation.
      4#
      5# Copyright (c) 2020 César Belley <cesar.belley@lse.epita.fr>
      6# Written by César Belley <cesar.belley@lse.epita.fr>
      7#
      8# This work is licensed under the terms of the GNU GPL, version 2
      9# or, at your option, any later version.  See the COPYING file in
     10# the top-level directory.
     11
     12import sys
     13import os
     14from random import randint
     15from typing import Tuple
     16
     17from cryptography.hazmat.backends import default_backend
     18from cryptography.hazmat.primitives.asymmetric import ec
     19from cryptography.hazmat.primitives.serialization import Encoding, \
     20    NoEncryption, PrivateFormat, PublicFormat
     21from OpenSSL import crypto
     22
     23
     24def write_setup_dir(dirpath: str, privkey_pem: bytes, cert_pem: bytes,
     25                    entropy: bytes, counter: int) -> None:
     26    """
     27    Write the setup directory.
     28
     29    Args:
     30        dirpath: The directory path.
     31        key_pem: The private key PEM.
     32        cert_pem: The certificate PEM.
     33        entropy: The 48 bytes of entropy.
     34        counter: The counter value.
     35    """
     36    # Directory
     37    os.mkdir(dirpath)
     38
     39    # Private key
     40    with open(f'{dirpath}/private-key.pem', 'bw') as f:
     41        f.write(privkey_pem)
     42
     43    # Certificate
     44    with open(f'{dirpath}/certificate.pem', 'bw') as f:
     45        f.write(cert_pem)
     46
     47    # Entropy
     48    with open(f'{dirpath}/entropy', 'wb') as f:
     49        f.write(entropy)
     50
     51    # Counter
     52    with open(f'{dirpath}/counter', 'w') as f:
     53        f.write(f'{str(counter)}\n')
     54
     55
     56def generate_ec_key_pair() -> Tuple[str, str]:
     57    """
     58    Generate an ec key pair.
     59
     60    Returns:
     61        The private and public key PEM.
     62    """
     63    # Key generation
     64    privkey = ec.generate_private_key(ec.SECP256R1, default_backend())
     65    pubkey = privkey.public_key()
     66
     67    # PEM serialization
     68    privkey_pem = privkey.private_bytes(encoding=Encoding.PEM,
     69                                        format=PrivateFormat.TraditionalOpenSSL,
     70                                        encryption_algorithm=NoEncryption())
     71    pubkey_pem = pubkey.public_bytes(encoding=Encoding.PEM,
     72                                     format=PublicFormat.SubjectPublicKeyInfo)
     73    return privkey_pem, pubkey_pem
     74
     75
     76def generate_certificate(privkey_pem: str, pubkey_pem: str) -> str:
     77    """
     78    Generate a x509 certificate from a key pair.
     79
     80    Args:
     81        privkey_pem: The private key PEM.
     82        pubkey_pem: The public key PEM.
     83
     84    Returns:
     85        The certificate PEM.
     86    """
     87    # Convert key pair
     88    privkey = crypto.load_privatekey(crypto.FILETYPE_PEM, privkey_pem)
     89    pubkey = crypto.load_publickey(crypto.FILETYPE_PEM, pubkey_pem)
     90
     91    # New x509v3 certificate
     92    cert = crypto.X509()
     93    cert.set_version(0x2)
     94
     95    # Serial number
     96    cert.set_serial_number(randint(1, 2 ** 64))
     97
     98    # Before / After
     99    cert.gmtime_adj_notBefore(0)
    100    cert.gmtime_adj_notAfter(4 * (365 * 24 * 60 * 60))
    101
    102    # Public key
    103    cert.set_pubkey(pubkey)
    104
    105    # Subject name and issueer
    106    cert.get_subject().CN = "U2F emulated"
    107    cert.set_issuer(cert.get_subject())
    108
    109    # Extensions
    110    cert.add_extensions([
    111        crypto.X509Extension(b"subjectKeyIdentifier",
    112                             False, b"hash", subject=cert),
    113    ])
    114    cert.add_extensions([
    115        crypto.X509Extension(b"authorityKeyIdentifier",
    116                             False, b"keyid:always", issuer=cert),
    117    ])
    118    cert.add_extensions([
    119        crypto.X509Extension(b"basicConstraints", True, b"CA:TRUE")
    120    ])
    121
    122    # Signature
    123    cert.sign(privkey, 'sha256')
    124
    125    return crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
    126
    127
    128def generate_setup_dir(dirpath: str) -> None:
    129    """
    130    Generates the setup directory.
    131
    132    Args:
    133        dirpath: The directory path.
    134    """
    135    # Key pair
    136    privkey_pem, pubkey_pem = generate_ec_key_pair()
    137
    138    # Certificate
    139    certificate_pem = generate_certificate(privkey_pem, pubkey_pem)
    140
    141    # Entropy
    142    entropy = os.urandom(48)
    143
    144    # Counter
    145    counter = 0
    146
    147    # Write
    148    write_setup_dir(dirpath, privkey_pem, certificate_pem, entropy, counter)
    149
    150
    151def main() -> None:
    152    """
    153    Main function
    154    """
    155    # Dir path
    156    if len(sys.argv) != 2:
    157        sys.stderr.write(f'Usage: {sys.argv[0]} <setup_dir>\n')
    158        exit(2)
    159    dirpath = sys.argv[1]
    160
    161    # Dir non existence
    162    if os.path.exists(dirpath):
    163        sys.stderr.write(f'Directory: {dirpath} already exists.\n')
    164        exit(1)
    165
    166    generate_setup_dir(dirpath)
    167
    168
    169if __name__ == '__main__':
    170    main()