Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add executable tools #27

Merged
merged 7 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
bin: Add pyndnsec list.
  • Loading branch information
zjkmxy committed Jul 6, 2021
commit c99dce8b5a164ba93c975988790d3cc8598ecb13
Empty file added src/ndn/bin/nfdc/__init__.py
Empty file.
29 changes: 27 additions & 2 deletions src/ndn/bin/sec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,38 @@
from . import cmd_init, cmd_list


CMD_LIST = '''
Available commands:
init Initialize a PIB
list List all known identities/keys/certificates
get-default Show the default identity/key/certificate
set-default Change the default identity/key/certificate
delete Delete an identity/key/certificate
key-gen Generate a key for an identity
sign-req Generate a certificate signing request
cert-gen Create a certificate for an identity
cert-dump Export a certificate
cert-install Import a certificate from a file

Try '%(prog)s COMMAND -h' for more information on each command
'''


def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, epilog=CMD_LIST)
subparsers = parser.add_subparsers(metavar='COMMAND', help='sub-command to execute')

cmd_init.add_parser(subparsers)
cmd_list.add_parser(subparsers)

parser.add_argument('--pib', metavar='PIB_SCHEMA', choices=['pib-sqlite3'], default='pib-sqlite3',
help='the schema of PIB. Only pib-sqlite3 is available currently.')
parser.add_argument('--path', metavar='PIB_PATH', help='the path to the base folder of PIB. '
'By default it is "~/.ndn" or "%%LOCALAPPDATA%%\\ndn".')
parser.add_argument('--tpm', metavar='TPM_SCHEMA', choices=['tpm-file', 'tpm-osxkeychain', 'tpm-cng'],
help='the TPM schema. Must be tpm-file, tpm-osxkeychain or tpm-cng.')
parser.add_argument('--tpm-path', help='the path of TPM when the schema is tpm-file')

args = parser.parse_args()
if 'executor' not in args:
parser.print_help()
Expand Down
10 changes: 1 addition & 9 deletions src/ndn/bin/sec/cmd_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@

def add_parser(subparsers):
parser = subparsers.add_parser('init')
parser.add_argument('--path', metavar='PIB_PATH', help='the path to the base folder of PIB. '
'By default it is "~/.ndn" or "%%LOCALAPPDATA%%\\ndn".')
parser.add_argument('--tpm', metavar='TPM_SCHEMA', help='the TPM schema. '
'Must be tpm-file, tpm-osxkeychain or tpm-cng.')
parser.add_argument('--tpm-path', help='the path of TPM when the schema is tpm-file')
parser.set_defaults(executor=execute)


Expand All @@ -39,14 +34,11 @@ def execute(args: argparse.Namespace):
platform = Platform()
if not tpm:
tpm = platform.default_tpm_schema()
if tpm not in {'tpm-file', 'tpm-osxkeychain', 'tpm-cng'}:
print(f'ERROR: Unrecognized TPM schema type: {tpm}. Must be tpm-file, tpm-osxkeychain or tpm-cng.')
return -2
if tpm == 'tpm-osxkeychain' and sys.platform != 'darwin':
print(f'ERROR: {tpm} only works on MacOS.')
return -2
if tpm == 'tpm-cng' and sys.platform != 'win32':
print(f'ERROR: {tpm} only works on Windows 10/11 with TPM chip.')
print(f'ERROR: {tpm} only works on Windows 10/11 with a TPM chip.')
return -2
if not base_dir:
base_dir = platform.default_pib_paths()[0]
Expand Down
71 changes: 68 additions & 3 deletions src/ndn/bin/sec/cmd_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,77 @@
# limitations under the License.
# -----------------------------------------------------------------------------
import argparse
from base64 import standard_b64encode
from ...encoding import Name, SignatureType
from ...app_support.security_v2 import parse_certificate
from .utils import resolve_keychain


def add_parser(subparsers):
par_init = subparsers.add_parser('list')
par_init.set_defaults(executor=execute)
parser = subparsers.add_parser('list')
parser.add_argument('-k', '--key', dest='verbose', action='store_const', const=1, default=0,
help='list all keys associated with each identity')
parser.add_argument('-c', '--cert', dest='verbose', action='store_const', const=2, default=0,
help='list all certificates associated with each key')
parser.add_argument('-v', '--verbose', action='count', default=0,
help='verbose mode, can be repeated for increased verbosity: '
'-v is equivalent to -k, -vv is equivalent to -c, -vvv '
'shows detailed information for each certificate')
parser.set_defaults(executor=execute)


def execute(args: argparse.Namespace):
print(f'list::: {args}')
kc = resolve_keychain(args)
verbose = args.verbose

for iden_name in kc:
iden = kc[iden_name]
is_default_id = '*' if iden.is_default else ' '
print(f'{is_default_id} {Name.to_str(iden_name)}')
if verbose >= 1:
for key_name in iden:
key = iden[key_name]
is_default_key = '*' if key.is_default else ' '
print(f' +->{is_default_key} {Name.to_str(key_name)}')
if verbose >= 2:
for cert_name in key:
cert = key[cert_name]
is_default_cert = '*' if cert.is_default else ' '
print(f' +->{is_default_cert} {Name.to_str(cert_name)}')
if verbose >= 3:
print_cert(cert)
print()
print()


def print_cert(cert):
try:
cert_val = parse_certificate(cert.data)
except (ValueError, IndexError):
print(' Unable to parse certificate')
return
print(' Certificate name:')
print(' ' + Name.to_str(cert.name))
if cert_val.signature_info and cert_val.signature_info.validity_period:
print(' Validity:')
print(f' NotBefore: {bytes(cert_val.signature_info.validity_period.not_before).decode()}')
print(f' NotAfter: {bytes(cert_val.signature_info.validity_period.not_after).decode()}')
if cert_val.content:
print(' Public key bits:')
text = standard_b64encode(bytes(cert_val.content)).decode()
cnt = (len(text) + 63) // 64
for i in range(cnt):
print(f' {text[i*64:(i+1)*64]}')
if cert_val.signature_info:
print(' Signature Information:')
sig_type_dict = {
SignatureType.NOT_SIGNED: 'Not Signed',
SignatureType.DIGEST_SHA256: 'DigestSha256',
SignatureType.SHA256_WITH_RSA: 'SignatureSha256WithRsa',
SignatureType.SHA256_WITH_ECDSA: 'SignatureSha256WithEcdsa',
SignatureType.HMAC_WITH_SHA256: 'SignatureHmacWithSha256',
}
sig_type = sig_type_dict.get(cert_val.signature_info.signature_type, 'Unknown')
print(f' Signature Type: {sig_type}')
if cert_val.signature_info.key_locator and cert_val.signature_info.key_locator.name:
print(f' Key Locator: {Name.to_str(cert_val.signature_info.key_locator.name)}')
59 changes: 59 additions & 0 deletions src/ndn/bin/sec/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# -----------------------------------------------------------------------------
# Copyright (C) 2019-2021 The python-ndn authors
#
# This file is part of python-ndn.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
import os
import sys
import argparse
from ...platform import Platform
from ...security import KeychainSqlite3
from ...client_conf import default_keychain


def resolve_keychain(args: argparse.Namespace) -> KeychainSqlite3:
tpm = args.tpm
tpm_path = args.tpm_path
base_dir = args.path
platform = Platform()
if not tpm:
tpm = platform.default_tpm_schema()
if tpm == 'tpm-osxkeychain' and sys.platform != 'darwin':
print(f'ERROR: {tpm} only works on MacOS.')
exit(-2)
if tpm == 'tpm-cng' and sys.platform != 'win32':
print(f'ERROR: {tpm} only works on Windows 10/11 with a TPM chip.')
exit(-2)
if not base_dir:
for d in platform.default_pib_paths():
if os.path.exists(d):
base_dir = d
break
if not base_dir:
print(f'ERROR: Cannot find a PIB.')
exit(-2)

pib_path = os.path.join(base_dir, 'pib.db')
if not os.path.exists(pib_path):
print(f'ERROR: Specified or default PIB database file {pib_path} does not exist.')
exit(-2)

if not tpm_path:
if tpm == 'tpm-file':
tpm_path = os.path.join(base_dir, 'ndnsec-key-file')
else:
tpm_path = ''

return default_keychain(f'pib-sqlite3:{base_dir}', f'{tpm}:{tpm_path}')