contrib/suci-keytool.py: Convenience tool for SUCI key generation
This adds a small utility program that can be used for generating keys used for SUCI in 5G SA networks, as well as for dumping them in a format that's compatible with what is needed on the USIM. Change-Id: I9e92bbba7f700e160ea9c58da5f23fa4c31d40c6
This commit is contained in:
52
contrib/suci-keytool.py
Executable file
52
contrib/suci-keytool.py
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# small utility program to deal with 5G SUCI key material, at least for the ECIES Protection Scheme
|
||||||
|
# Profile A (curve25519) and B (secp256r1)
|
||||||
|
|
||||||
|
# (C) 2024 by Harald Welte <laforge@osmocom.org>
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from osmocom.utils import b2h
|
||||||
|
from Cryptodome.PublicKey import ECC
|
||||||
|
# if used with pycryptodome < v3.21.0 you will get the following error when using curve25519:
|
||||||
|
# "Cryptodome.PublicKey.ECC.UnsupportedEccFeature: Unsupported ECC purpose (OID: 1.3.101.110)"
|
||||||
|
|
||||||
|
def gen_key(opts):
|
||||||
|
# FIXME: avoid overwriting key files
|
||||||
|
mykey = ECC.generate(curve=opts.curve)
|
||||||
|
data = mykey.export_key(format='PEM')
|
||||||
|
with open(opts.key_file, "wt") as f:
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
|
def dump_pkey(opts):
|
||||||
|
|
||||||
|
#with open("curve25519-1.key", "r") as f:
|
||||||
|
|
||||||
|
with open(opts.key_file, "r") as f:
|
||||||
|
data = f.read()
|
||||||
|
mykey = ECC.import_key(data)
|
||||||
|
|
||||||
|
der = mykey.public_key().export_key(format='raw', compress=opts.compressed)
|
||||||
|
print(b2h(der))
|
||||||
|
|
||||||
|
arg_parser = argparse.ArgumentParser(description="""Generate or export SUCI keys for 5G SA networks""")
|
||||||
|
arg_parser.add_argument('--key-file', help='The key file to use', required=True)
|
||||||
|
|
||||||
|
subparsers = arg_parser.add_subparsers(dest='command', help="The command to perform", required=True)
|
||||||
|
|
||||||
|
parser_genkey = subparsers.add_parser('generate-key', help='Generate a new key pair')
|
||||||
|
parser_genkey.add_argument('--curve', help='The ECC curve to use', choices=['secp256r1','curve25519'], required=True)
|
||||||
|
|
||||||
|
parser_dump_pkey = subparsers.add_parser('dump-pub-key', help='Dump the public key')
|
||||||
|
parser_dump_pkey.add_argument('--compressed', help='Use point compression', action='store_true')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
opts = arg_parser.parse_args()
|
||||||
|
|
||||||
|
if opts.command == 'generate-key':
|
||||||
|
gen_key(opts)
|
||||||
|
elif opts.command == 'dump-pub-key':
|
||||||
|
dump_pkey(opts)
|
||||||
@@ -44,6 +44,7 @@ pySim consists of several parts:
|
|||||||
library
|
library
|
||||||
osmo-smdpp
|
osmo-smdpp
|
||||||
sim-rest
|
sim-rest
|
||||||
|
suci-keytool
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
|
|||||||
58
docs/suci-keytool.rst
Normal file
58
docs/suci-keytool.rst
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
suci-keytool
|
||||||
|
============
|
||||||
|
|
||||||
|
Subscriber concealment is an important feature of the 5G SA architecture: It avoids the many privacy
|
||||||
|
issues associated with having a permanent identifier (SUPI, traditionally the IMSI) transmitted in plain text
|
||||||
|
over the air interface. Using SUCI solves this issue not just for the air interface; it even ensures the SUPI/IMSI
|
||||||
|
is not known to the visited network (VPLMN) at all.
|
||||||
|
|
||||||
|
In principle, the SUCI mechanism works by encrypting the SUPI by asymmetric (public key) cryptography:
|
||||||
|
Only the HPLMN is in possession of the private key and hence can decrypt the SUCI to the SUPI, while
|
||||||
|
each subscriber has the public key in order to encrypt their SUPI into the SUCI. In reality, the
|
||||||
|
details are more complex, as there are ephemeral keys and cryptographic MAC involved.
|
||||||
|
|
||||||
|
In any case, in order to operate a SUCI-enabled 5G SA network, you will have to
|
||||||
|
|
||||||
|
#. generate a ECC key pair of public + private key
|
||||||
|
#. deploy the public key on your USIMs
|
||||||
|
#. deploy the private key on your 5GC, specifically the UDM function
|
||||||
|
|
||||||
|
pysim contains (int its `contrib` directory) a small utility program that can make it easy to generate
|
||||||
|
such keys: `suci-keytool.py`
|
||||||
|
|
||||||
|
Generating keys
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Example: Generating a *secp256r1* ECC public key pair and storing it to `/tmp/suci.key`:
|
||||||
|
::
|
||||||
|
|
||||||
|
$ ./contrib/suci-keytool.py --key-file /tmp/suci.key generate-key --curve secp256r1
|
||||||
|
|
||||||
|
Dumping public keys
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
In order to store the key to SIM cards as part of `ADF.USIM/DF.5GS/EF.SUCI_Calc_Info`, you will need
|
||||||
|
a hexadecimal representation of the public key. You can achieve that using the `dump-pub-key` operation
|
||||||
|
of suci-keytool:
|
||||||
|
|
||||||
|
Example: Dumping the public key part from a previously generated key file:
|
||||||
|
::
|
||||||
|
|
||||||
|
$ ./contrib/suci-keytool.py --key-file /tmp/suci.key dump-pub-key
|
||||||
|
0473152f32523725f5175d255da2bd909de97b1d06449a9277bc629fe42112f8643e6b69aa6dce6c86714ccbe6f2e0f4f4898d102e2b3f0c18ce26626f052539bb
|
||||||
|
|
||||||
|
If you want the point-compressed representation, you can use the `--compressed` option:
|
||||||
|
::
|
||||||
|
|
||||||
|
$ ./contrib/suci-keytool.py --key-file /tmp/suci.key dump-pub-key --compressed
|
||||||
|
0373152f32523725f5175d255da2bd909de97b1d06449a9277bc629fe42112f864
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
suci-keytool syntax
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. argparse::
|
||||||
|
:module: contrib.suci-keytool
|
||||||
|
:func: arg_parser
|
||||||
|
:prog: contrib/suci-keytool.py
|
||||||
Reference in New Issue
Block a user