Git Product home page Git Product logo

tpm2-pytss's People

Contributors

aplanas avatar baloo avatar dependabot[bot] avatar diabonas avatar janwytze avatar joholl avatar lamby avatar lap1nou avatar lgtm-migrator avatar malikabhi05 avatar niooss-ledger avatar pdxjohnny avatar whooo avatar williamcroberts avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tpm2-pytss's Issues

Esys_Free on returned pointers

Looking through the CFFI documentation, it appears that all the pointers coming back are "owned" and are getting released via whatever ffi.new uses or are getting leaked. For example consider this:

    def ECC_Parameters(
        self,
        curveID,
        session1=ESYS_TR.NONE,
        session2=ESYS_TR.NONE,
        session3=ESYS_TR.NONE,
    ):

        parameters = ffi.new("TPMS_ALGORITHM_DETAIL_ECC **")
        _chkrc(
            lib.Esys_ECC_Parameters(
                self.ctx, session1, session2, session3, curveID, parameters
            )
        )
        return TPMS_ALGORITHM_DETAIL_ECC(parameters[0])

parameters is "owned" by ffi.new and will call it's destructor. The question here is who owns the pointer that paramters[0] refers to? How do we ensure that is free'd? If so how do free it with Esys_Free?

I'm not sure so I posted this question to the CFFI group:

libtss2-mu bindings

It would be useful to get access to the Marshal/Unmarshal API.
For example to generate a policy before signing it using only software.

Intermittent test failures do to TCTI requesting a port and there being none

test_auto_session_flags (tests.test_esys_auto_session_flags.TestAutoSessionFlags) ... WARNING:tcti:src/util/io.c:252:socket_connect() Failed to connect to host ::1, port 2322: errno 99: Cannot assign requested address 
WARNING:tcti:src/tss2-tcti/tctildr.c:62:tcti_from_init() TCTI init for function 0x7f23d8f15230 failed with a000a 
WARNING:tcti:src/tss2-tcti/tctildr.c:92:tcti_from_info() Could not initialize TCTI named: tcti-socket 
ERROR:tcti:src/tss2-tcti/tctildr-dl.c:150:tcti_from_file() Could not initialize TCTI file: mssim 
ERROR:tcti:src/tss2-tcti/tctildr.c:418:Tss2_TctiLdr_Initialize_Ex() Failed to instantiate TCTI 
ERROR

make size a read only property

Make size a read only property. What about count? I could see folks wanted to set count on TPML objects if they go through setattr and modify things in a way the count tracker doesn't get it right.

Some TPM2B types should be bytes-like

It would be useful if the TPM2B structures that just has a size and a series of bytes would be bytes-like.
For example, the output from NV_Read is a TPM2B_MAX_NV_BUFFER should behave like a bytes object.

Possible missing swig directory in install dir?

I have cloned the latest revision of tpm2-pytss and the built it using:

python3 setup.py build

I then used the following command to install it:

python3 setup.py install --verbose --prefix=/usr

When I do this I then get an install directory that looks like this:

binding.py
_esys_binding.cpython-36m-x86_64-linux-gnu.so
_esys_binding.py
esys_binding.py
esys.py
exceptions.py
__init__.py
__pycache__
tcti.py
util
version.py

Running the following code

from tpm2_pytss.binding import *

def main():
        print("Hello world!")

if __name__ == "__main__":
    main()

then results in the ollowing error:

Traceback (most recent call last):
  File "main.py", line 2, in <module>
    from tpm2_pytss.binding import *
  File "/usr/lib64/python3.6/site-packages/tpm2_pytss-0.0.3-py3.6-linux-x86_64.egg/tpm2_pytss/binding.py", line 417, in <module>
    TYPEDEFS = typedef_map()
  File "/usr/lib64/python3.6/site-packages/tpm2_pytss-0.0.3-py3.6-linux-x86_64.egg/tpm2_pytss/binding.py", line 409, in typedef_map
    for line in pkgutil.get_data(__name__.split(".")[0], "swig/tpm2_types.i")
  File "/usr/lib64/python3.6/pkgutil.py", line 634, in get_data
    return loader.get_data(resource_name)
  File "<frozen importlib._bootstrap_external>", line 832, in get_data
FileNotFoundError: [Errno 2] No such file or directory: '/usr/lib64/python3.6/site-packages/tpm2_pytss-0.0.3-py3.6-linux-x86_64.egg/tpm2_pytss/swig/tpm2_types.i'

In order to get things working I had to manually create the swig directory in the installation directory and copy the .i-files into it.

I wonder if this is bug or am I missing something?

How to translate command `tpm2_nvread -T device:/dev/tpmrm0 -C o -s 10 -P passwd 1` to python using pytss?

Hi

I am new to tpm2, especially this python binding. I am stumbled with very limit documents, and then find out it is mission impossible to complete even a very simple task without help.

For example, the above command, how can I translate it to python?

My knowledge currently is:

  1. First I need a tcti context, which can be done by
tcti = TCTI.load('device')
tcti_config = '/dev/tpmrm0'
tcti_ctx = ctx_stack.enter_context(tcti(config=tcti_config, retry=1))
  1. Then I need a esys context, which can be done by
esys = ESYS()
esys_ctx = ctx_stack.enter_context(esys(tcti_ctx))
  1. Then what should I do? How to use password authentication? I found an API TR_SetAuth, is it correct?
authValue = TPM2B_AUTH(size=6, buffer=list(b'passwd'))
esys_ctx.TR_SetAuth(ESYS_TR_RH_OWNER, authValue)
  1. Then I need to call NV_Read, but how to fill the arguments?
esys_ctx.NV_Read(?, ?, ?, ?, ?)

Please shed me some light. Thank you very much!

Usage of non-string FAPI Parameters

@pdxjohnny I have another question about the FAPI bindings, this time with regard to the parameters. For FAPI calls with char const * input parameters, a simple python str can be passed. E.g.

with CHAR_PTR_PTR() as description:
    description = self.fapi_ctx.GetDescription(path, description)

However, that does not work when the input parameter is a byte array

with UINT8_PTR_PTR() as keyPath:
    with UINT8_PTR() as plaintext:
        plaintext = ???                              # <--- how to set the plaintext?
        with SIZE_T_PTR() as plaintextSize:
            with UINT8_PTR_PTR() as cipherText:
                with SIZE_T_PTR() as cipherTextSize:
                    ret = self.fapi_ctx.Encrypt(path, plaintext, plaintextSize, cipherText, cipherTextSize)

This leaves me with two questions:

  • Why does the user need to create and pass output parameters like description in the first example? Wouldn't it be better to handle these internally?
  • How to pass non-string input parameters like plaintext in the second example?

Thanks in advance!

Feature Request: set TSS log level per logging module

Unfortunately, there seems to be no mechanism to set the TSS log level at runtime besides via the env variable TSS2_LOG, e.g. TSS2_LOG=all+ERROR,fapi+TRACE, as documented here. What do you think of having a function setting this variable, maybe from a dict?

Example:

log_levels = { "all": "error", "tcti": "trace"}
log_levels_str = ",".join(f"{k}+{v}" for k, v in log_levels.items())  # 'all+error,tcti+trace'
os.environ["TSS2_LOG"] = log_levels_str

We might want to use enums instead of strings(?). In case you wonder, modules and log levels are parsed case insensitive.

Complete list of TSS log levels (as defined here):

  • none
  • (unused) [note: defined with parens]
  • ERROR
  • WARNING
  • info
  • debug
  • trace

Complete list of TSS log modules (grepped):

  • fapi
  • esys
  • esys_crypto
  • sys
  • marshal
  • tcti
  • log
  • test
  • all [note: covers all modules]

Docs build broken

The documentation site doesn't seem to be able to automodule the docs anymore

TR_GetName returns TPM2B_NAME object with incorrect data

When I am using tpm2_LoadExternal with a known key I get a name that is:
000b9adccfa3d608ee3601a2bcb2ee29bd45ae6f3de9aa8be44b6379c118c9692217

I then use the same key in the LoadExternal test. I use the following code to print the name of the key

key_name_ptr_ptr = stack.enter_context(TPM2B_NAME_PTR_PTR())
self.esys_ctx.TR_GetName(object_handle, key_name_ptr_ptr)
key_name_ptr = key_name_ptr_ptr.value
key_name = to_bytearray(key_name_ptr.size, key_name_ptr.name)
print(binascii.b2a_hex(key_name))

But I get the following result:
000b3268f9ca3e4af83e2547a933163a700f6580cf90d93abe8fb31afba129d2a682

I was not really sure how to extract the data from key_name_ptr_ptr variable so the error may be that I am doing it incorrectly.

TypeError: in method 'Fapi_GetRandom', argument 3 of type 'uint8_t **'

Hi,

I just installed the library and wanted to test it with a simple example:

from tpm2_pytss.fapi import FAPI, FAPIDefaultConfig
from tpm2_pytss.binding import *

fapi = FAPI()

fapi.get_random(10)

But I got this error:

Traceback (most recent call last):
  File "tpm.py", line 6, in <module>
    fapi.get_random(10)
  File "/home/pa/.local/lib/python3.8/site-packages/tpm2_pytss/fapi.py", line 196, in get_random
    self.GetRandom(length, datapp)
  File "/home/pa/.local/lib/python3.8/site-packages/tpm2_pytss/context.py", line 78, in wrapper
    return custom_wrap(func)(self.ctxp, *args, **kwds)
  File "/home/pa/.local/lib/python3.8/site-packages/tpm2_pytss/context.py", line 112, in wrapper
    result = func(self, *args, **kwds)
  File "/home/pa/.local/lib/python3.8/site-packages/tpm2_pytss/util/swig.py", line 173, in wrapper
    return func(*args, **kwargs)
  File "/home/pa/.local/lib/python3.8/site-packages/tpm2_pytss/exceptions.py", line 48, in wrapper
    rc = func(*args, **kwargs)
  File "/home/pa/.local/lib/python3.8/site-packages/tpm2_pytss/fapi_binding.py", line 10790, in Fapi_GetRandom
    return _fapi_binding.Fapi_GetRandom(context, numBytes, data)
TypeError: in method 'Fapi_GetRandom', argument 3 of type 'uint8_t **'

Any idea ?

TPM2Error should include the rc as a property

class TPM2Error(Exception):

this will need to change (it's wrong, if r != 0 then this will never get called):

r = self.esys_ctx.GetTime(
privacyAdminHandle,
signHandle,
ESYS_TR_PASSWORD,
ESYS_TR_PASSWORD,
ESYS_TR_NONE,
qualifyingData_ptr,
inScheme_ptr,
timeInfo_ptr_ptr,
signature_ptr_ptr,
)
if (
(r == TPM2_RC_COMMAND_CODE)
or (r == (TPM2_RC_COMMAND_CODE | TSS2_RESMGR_RC_LAYER))
or (r == (TPM2_RC_COMMAND_CODE | TSS2_RESMGR_TPM_RC_LAYER))
):
self.skipTest("Command TPM2_GetTime not supported by TPM")

TPM2B_PUBLIC and TPM2B_SENSITIVE from PEM files

create TPM2B_PUBLIC.fromPEM() and TPM2B_SENSITIVE.fromPEM routines to convert those data types for things like LoadExternal. Also support a fromAES? How do we want to handle symmetric keys? Should we just be able to pass a pem to the existing parse routines?

Enhancements for the simulators-based unit tests

Toggling physical presence is needed for testing PolicyPhysicalPresence and PP_Commands, I'm looking into a solution for the IBM simulator, but I'm unsure how to do it for swtpm.

Adding an EK certs with matching EK primary keys and keeping them in the standard NV indices would be useful for testing a standard MakeCredential and ActivateCredential setup as well as EK cert parsing.

Calling fapi_Sign() method with proper arguments (digest)

Hi, this would be actually very simple. I have this function from fapi:

Sign(keyPath: char const *, padding: char const *, digest: uint8_t const *, digestSize: size_t, signature: uint8_t **, signatureSize: size_t *, publicKey: char **, certificate: char **) โ†’ TSS2_RC

And I am trying to pass arguments to it, specifically the 3rd one (digest):

fapi_ctx.Sign(path_to_key, None, ???, digest_size, sig_holder, None, None, None)

After several hours of trial and error, trying everything from struct.pack(), through ctypes, to simply using several methods and fields in your class tpm2_pytss.binding (using dir()) I still receive this error:

Traceback (most recent call last):
  File "lab5.py", line 84, in <module>
    sign(ctx, stck, "HS/lab5_key", "qwe123", doc_txt)
  File "lab5.py", line 77, in sign
    fapi_ctx.Sign(path_to_key, None, digest_pointer, 32, sig_holder, None, None, None)
  File "/media/sf_LNX_FILES/SEM2/ZIO/tpm2-pytss/tpm2_pytss/context.py", line 78, in wrapper
    return custom_wrap(func)(self.ctxp, *args, **kwds)
  File "/media/sf_LNX_FILES/SEM2/ZIO/tpm2-pytss/tpm2_pytss/context.py", line 112, in wrapper
    result = func(self, *args, **kwds)
  File "/media/sf_LNX_FILES/SEM2/ZIO/tpm2-pytss/tpm2_pytss/util/swig.py", line 173, in wrapper
    return func(*args, **kwargs)
  File "/media/sf_LNX_FILES/SEM2/ZIO/tpm2-pytss/tpm2_pytss/exceptions.py", line 48, in wrapper
    rc = func(*args, **kwargs)
  File "/media/sf_LNX_FILES/SEM2/ZIO/tpm2-pytss/tpm2_pytss/fapi_binding.py", line 14997, in Fapi_Sign
    return _fapi_binding.Fapi_Sign(context, keyPath, padding, digest, digestSize, signature, signatureSize, publicKey, certificate)
TypeError: in method 'Fapi_Sign', argument 4 of type 'uint8_t const *'

I am not asking for help here, although it would be highly appreciated - instead I would just like to inform you that there is such a case, in which documentation to pytss doesn't help and hours of surfing web does no either. Perhaps there is a room for some improvement that would make passing parameters a little bit simpler for beginners?

Buffer protocol for simple TPM2B types

The TPM2B structs that are just size + fixed size byte array, such as TPM2B_DIGEST and TPM2B_PUBLIC_KEY_RSA should behave as the python bytes type.
A simple example is doing PCR_Read and then printing the value of each digest in TPML_DIGEST using base64.b16encode without having to convert each entry.

installing from pip: Unable to find file 'tpm2_pytss/swig/esys_binding.i'

python3.8 -m pip install --user tpm2-pytss
Collecting tpm2-pytss
  Using cached https://files.pythonhosted.org/packages/ff/e8/1f8e469ff55bec25b45b520a8155724c339c22d224331d15918f9cf87a0b/tpm2-pytss-0.1.0.tar.gz
Building wheels for collected packages: tpm2-pytss
  Building wheel for tpm2-pytss (setup.py) ... error
  ERROR: Command errored out with exit status 1:
   command: /usr/local/bin/python3.8 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-apmpt5p0/tpm2-pytss/setup.py'"'"'; __file__='"'"'/tmp/pip-install-apmpt5p0/tpm2-pytss/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-2mykngfn --python-tag cp38
       cwd: /tmp/pip-install-apmpt5p0/tpm2-pytss/
  Complete output (51 lines):
  running bdist_wheel
  running build
  running build_py
  file tpm2_pytss.py (for module tpm2_pytss) not found
  creating build
  creating build/lib.linux-x86_64-3.8
  creating build/lib.linux-x86_64-3.8/tests
  copying tests/test_tpm2_error.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/test_fapi_get_random.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/test_esys_auto_session_flags.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/__init__.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/test_esys_get_time.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/test_binding.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/test_base_test.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/test_esys_get_capability.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/test_esys_audit.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/base_esys.py -> build/lib.linux-x86_64-3.8/tests
  copying tests/test_esys_get_random.py -> build/lib.linux-x86_64-3.8/tests
  creating build/lib.linux-x86_64-3.8/tpm2_pytss
  copying tpm2_pytss/fapi.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
  copying tpm2_pytss/tcti.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
  copying tpm2_pytss/binding.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
  copying tpm2_pytss/context.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
  copying tpm2_pytss/__init__.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
  copying tpm2_pytss/exceptions.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
  copying tpm2_pytss/esys.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
  copying tpm2_pytss/config.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
  copying tpm2_pytss/version.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
  creating build/lib.linux-x86_64-3.8/tpm2_pytss/util
  copying tpm2_pytss/util/simulator.py -> build/lib.linux-x86_64-3.8/tpm2_pytss/util
  copying tpm2_pytss/util/__init__.py -> build/lib.linux-x86_64-3.8/tpm2_pytss/util
  copying tpm2_pytss/util/swig.py -> build/lib.linux-x86_64-3.8/tpm2_pytss/util
  copying tpm2_pytss/util/calculate.py -> build/lib.linux-x86_64-3.8/tpm2_pytss/util
  running egg_info
  writing tpm2_pytss.egg-info/PKG-INFO
  writing dependency_links to tpm2_pytss.egg-info/dependency_links.txt
  writing requirements to tpm2_pytss.egg-info/requires.txt
  writing top-level names to tpm2_pytss.egg-info/top_level.txt
  file tpm2_pytss.py (for module tpm2_pytss) not found
  reading manifest file 'tpm2_pytss.egg-info/SOURCES.txt'
  reading manifest template 'MANIFEST.in'
  warning: no files found matching 'tpm2_pytss/config.json'
  warning: no files found matching '*' under directory 'tpm2_pytss/swig'
  writing manifest file 'tpm2_pytss.egg-info/SOURCES.txt'
  file tpm2_pytss.py (for module tpm2_pytss) not found
  running build_ext
  building 'tpm2_pytss._esys_binding' extension
  swigging tpm2_pytss/swig/esys_binding.i to tpm2_pytss/swig/esys_binding_wrap.c
  swig -python -I/usr/local/include -py3 -outdir tpm2_pytss -o tpm2_pytss/swig/esys_binding_wrap.c tpm2_pytss/swig/esys_binding.i
  Unable to find file 'tpm2_pytss/swig/esys_binding.i'.
  error: command 'swig' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for tpm2-pytss
  Running setup.py clean for tpm2-pytss
Failed to build tpm2-pytss
Installing collected packages: tpm2-pytss
  Running setup.py install for tpm2-pytss ... error
    ERROR: Command errored out with exit status 1:
     command: /usr/local/bin/python3.8 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-apmpt5p0/tpm2-pytss/setup.py'"'"'; __file__='"'"'/tmp/pip-install-apmpt5p0/tpm2-pytss/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-dz7an7yw/install-record.txt --single-version-externally-managed --compile --user --prefix=
         cwd: /tmp/pip-install-apmpt5p0/tpm2-pytss/
    Complete output (51 lines):
    running install
    running build
    running build_py
    file tpm2_pytss.py (for module tpm2_pytss) not found
    creating build
    creating build/lib.linux-x86_64-3.8
    creating build/lib.linux-x86_64-3.8/tests
    copying tests/test_tpm2_error.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/test_fapi_get_random.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/test_esys_auto_session_flags.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/__init__.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/test_esys_get_time.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/test_binding.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/test_base_test.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/test_esys_get_capability.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/test_esys_audit.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/base_esys.py -> build/lib.linux-x86_64-3.8/tests
    copying tests/test_esys_get_random.py -> build/lib.linux-x86_64-3.8/tests
    creating build/lib.linux-x86_64-3.8/tpm2_pytss
    copying tpm2_pytss/fapi.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
    copying tpm2_pytss/tcti.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
    copying tpm2_pytss/binding.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
    copying tpm2_pytss/context.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
    copying tpm2_pytss/__init__.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
    copying tpm2_pytss/exceptions.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
    copying tpm2_pytss/esys.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
    copying tpm2_pytss/config.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
    copying tpm2_pytss/version.py -> build/lib.linux-x86_64-3.8/tpm2_pytss
    creating build/lib.linux-x86_64-3.8/tpm2_pytss/util
    copying tpm2_pytss/util/simulator.py -> build/lib.linux-x86_64-3.8/tpm2_pytss/util
    copying tpm2_pytss/util/__init__.py -> build/lib.linux-x86_64-3.8/tpm2_pytss/util
    copying tpm2_pytss/util/swig.py -> build/lib.linux-x86_64-3.8/tpm2_pytss/util
    copying tpm2_pytss/util/calculate.py -> build/lib.linux-x86_64-3.8/tpm2_pytss/util
    running egg_info
    writing tpm2_pytss.egg-info/PKG-INFO
    writing dependency_links to tpm2_pytss.egg-info/dependency_links.txt
    writing requirements to tpm2_pytss.egg-info/requires.txt
    writing top-level names to tpm2_pytss.egg-info/top_level.txt
    file tpm2_pytss.py (for module tpm2_pytss) not found
    reading manifest file 'tpm2_pytss.egg-info/SOURCES.txt'
    reading manifest template 'MANIFEST.in'
    warning: no files found matching 'tpm2_pytss/config.json'
    warning: no files found matching '*' under directory 'tpm2_pytss/swig'
    writing manifest file 'tpm2_pytss.egg-info/SOURCES.txt'
    file tpm2_pytss.py (for module tpm2_pytss) not found
    running build_ext
    building 'tpm2_pytss._esys_binding' extension
    swigging tpm2_pytss/swig/esys_binding.i to tpm2_pytss/swig/esys_binding_wrap.c
    swig -python -I/usr/local/include -py3 -outdir tpm2_pytss -o tpm2_pytss/swig/esys_binding_wrap.c tpm2_pytss/swig/esys_binding.i
    Unable to find file 'tpm2_pytss/swig/esys_binding.i'.
    error: command 'swig' failed with exit status 1
    ----------------------------------------
ERROR: Command errored out with exit status 1: /usr/local/bin/python3.8 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-apmpt5p0/tpm2-pytss/setup.py'"'"'; __file__='"'"'/tmp/pip-install-apmpt5p0/tpm2-pytss/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-dz7an7yw/install-record.txt --single-version-externally-managed --compile --user --prefix= Check the logs for full command output.

GetRandom example produces error, but test works

Hi there, sorry if this is a dumb question, I am quite new to working with TPMs. I followed all of the setup instructions and I can run
python3 setup.py test
with no problems.

However, if I run
python3 fapi_get_random.py 8
I get the following error:
Traceback (most recent call last): File "examples/fapi_get_random.py", line 59, in <module> main() File "examples/fapi_get_random.py", line 48, in main x = fapi_ctx.GetRandom(length) File "/home/pi/.local/lib/python3.7/site-packages/tpm2_pytss/context.py", line 78, in wrapper return custom_wrap(func)(self.ctxp, *args, **kwds) File "/home/pi/.local/lib/python3.7/site-packages/tpm2_pytss/context.py", line 112, in wrapper result = func(self, *args, **kwds) File "/home/pi/.local/lib/python3.7/site-packages/tpm2_pytss/util/swig.py", line 173, in wrapper return func(*args, **kwargs) File "/home/pi/.local/lib/python3.7/site-packages/tpm2_pytss/exceptions.py", line 48, in wrapper rc = func(*args, **kwargs) TypeError: Fapi_GetRandom() missing 1 required positional argument: 'data'

I tried adding a "data=[]" and I get
Traceback (most recent call last): File "examples/fapi_get_random.py", line 59, in <module> main() File "examples/fapi_get_random.py", line 48, in main x = fapi_ctx.GetRandom(length, data) File "/home/pi/.local/lib/python3.7/site-packages/tpm2_pytss/context.py", line 78, in wrapper return custom_wrap(func)(self.ctxp, *args, **kwds) File "/home/pi/.local/lib/python3.7/site-packages/tpm2_pytss/context.py", line 112, in wrapper result = func(self, *args, **kwds) File "/home/pi/.local/lib/python3.7/site-packages/tpm2_pytss/util/swig.py", line 173, in wrapper return func(*args, **kwargs) File "/home/pi/.local/lib/python3.7/site-packages/tpm2_pytss/exceptions.py", line 48, in wrapper rc = func(*args, **kwargs) File "/home/pi/.local/lib/python3.7/site-packages/tpm2_pytss/fapi_binding.py", line 14865, in Fapi_GetRandom return _fapi_binding.Fapi_GetRandom(context, numBytes, data) TypeError: in method 'Fapi_GetRandom', argument 3 of type 'uint8_t **'

Is there something I'm missing when running the example vs running the tests?

Thanks

Missing array support

When trying to read PCR values I hit the problem that I can't set some arrays.
For example:

from tpm2_pytss.binding import TPML_PCR_SELECTION, TPMS_PCR_SELECTION, TPM2_ALG_SHA256
sel = TPMS_PCR_SELECTION(hash=TPM2_ALG_SHA256, sizeofSelect=3, pcrSelect=(0,0,255))

sels = TPML_PCR_SELECTION(count=1, pcrSelections=(sel,))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/.local/lib/python3.7/site-packages/tpm2_pytss/binding.py", line 126, in __init__
    buffer_ptr = ByteArray.frompointer(getattr(self, buffer_prop))
TypeError: in method 'ByteArray_frompointer', argument 1 of type 'BYTE *'

The problem seems to exist for other similar types, such as TPML_DIGEST.

Esys_GetRandom TypeError

Hello guys,

I am new to using lib tpm2-pytss, and trying to run an example using the Esys_GetRandom function and received the following typeError with 'TPM2B_DIGEST **':

Captura de tela de 2020-10-21 08-39-33

getRandom example code:

import sys
import random
import tempfile
import contextlib

import tpm2_pytss.binding
import tpm2_pytss.context
import tpm2_pytss.esys
import tpm2_pytss.tcti
from tpm2_pytss.binding import *

def main():
    # Usage information
    if len(sys.argv) != 2:
        print("Ouput N random bytes to stdout")
        print("Usage:length(between 8 and 32)")
        sys.exit(1)

    # Number of random bytes to get (between 8 and 32)
    length = int(sys.argv[1])
    # Input validation
    if length < 8 or length > 32:
        raise ValueError("length must be between 8 and 32")
    
    ctxpp = tpm2_pytss.esys.ESYSContext.new_ctx_ptr()
    print(type(ctxpp))

    tcti_ctxpp = tpm2_pytss.binding.ESYSBinding.tcti_ctx_ptr_ptr()
    tcti_ctxpp.__enter__()
    tcti_ctxp = tcti_ctxpp.value

    abi_version = tpm2_pytss.binding.TSS2_ABI_VERSION

    ret = tpm2_pytss.binding.Esys_Initialize(ctxpp, tcti_ctxp, None)
    ctxp = tpm2_pytss.esys.ESYSContext.ctx_ptr_value(ctxpp)
    print(ret)

    ans = TPM2B_DIGEST_PTR_PTR()
    
    ret = Esys_GetRandom(ctxp, 
                        tpm2_pytss.binding.ESYSBinding.ESYS_TR_NONE, 
                        tpm2_pytss.binding.ESYSBinding.ESYS_TR_NONE, 
                        tpm2_pytss.binding.ESYSBinding.ESYS_TR_NONE, 
                        length, 
                        ans)



if __name__ == "__main__":
    main()

Can someone help me to run this code successfully and / or a way to run an example of getRandom using the functions with prefix "esys_"?

Documentation on FAPI return codes

@pdxjohnny I find these bindings really cool! However I do not understand the logic behind what is returned by the FAPI commands.

Example A) Fapi_GetRandom returns a Swig Object of type 'TPMI_YES_NO *' which can be casted into a ByteArray which we can iterate over to get the bytes

            length = 32
            with UINT8_PTR_PTR() as random_uin8_ptr_ptr:
                random_swig = fapi_ctx.GetRandom(length, random_uin8_ptr_ptr)
                random_ByteArray = ByteArray.frompointer(random_swig)
                random_bytearray = bytearray(length)
                for i in range(0, length):
                    random_bytearray[i] = random_ByteArray[i]
                print(random_bytearray)

Example B) Fapi_GetInfo returns a dict

            with CHAR_PTR_PTR() as info:
                cap = fapi_ctx.GetInfo(info)
                print(cap['capabilities'][1])

Example C) Fapi_List returns an int

            with CHAR_PTR_PTR() as info:
                x = fapi_ctx.List("", info)
                print(x)

How can I access the actual list? I tried print(CHAR_PTR.frompointer(x).value) but gives me a segmentation fault. Is the int returned the TPM return code or something else?

And more generally: Is the return code of Fapi commands documented somewhere?

Creating objects from dicts

Being able to create at least some type of objects (such as TPM2B_PUBLIC or TPM2B_NV_PUBLIC) from a dict could be an useful feature for users of the API.

By using dicts directly we can leave the (de)serialization part to the caller instead of enforcing a specific format such as JSON.

One use case that I have is that I want to create a NV counter on a remote system using ansible.
As ansible is a heavy user of YAML, so I want to define the NV area using an YAML hash, later on I want to do a audit session to attest the current counter value and therefor want to reuse the same YAML hash for generating the name locally to verify the audi session.

PermissionError: [Errno 13] Permission denied

Hi, I am new with tpm2-pytss. I have a Raspberry pi with a TPM2.0 chip with it and I am able to run all the TPM2.0 commands by using the IBM library https://sourceforge.net/p/ibmtpm20tss/tss/ci/master/tree/demo/. But after I installed tpm2-pytss on it and tried running the GET_RANDOM test, it always give me the PERMISSION_ERROR like below:

Traceback (most recent call last):
  File "test_py3.py", line 58, in <module>
    main()
  File "test_py3.py", line 26, in main
    simulator = ctx_stack.enter_context(Simulator())
  File "/usr/lib/python3.5/contextlib.py", line 307, in enter_context
    result = _cm_type.__enter__(cm)
  File "/home/pi/.local/lib/python3.5/site-packages/tpm2_pytss/util/simulator.py", line 128, in __enter__
    self.start()
  File "/home/pi/.local/lib/python3.5/site-packages/tpm2_pytss/util/simulator.py", line 101, in start
    stderr=subprocess.PIPE,
  File "/usr/lib/python3.5/subprocess.py", line 676, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.5/subprocess.py", line 1282, in _execute_child
    raise child_exception_type(errno_num, err_msg)
PermissionError: [Errno 13] Permission denied

test_py3.py

import sys
import random
import tempfile
import contextlib

from tpm2_pytss.fapi import FAPI, FAPIDefaultConfig
from tpm2_pytss.binding import *
from tpm2_pytss.util.simulator import Simulator


def main():
    # Usage information
    if len(sys.argv) != 2:
        print("Ouput N random bytes to stdout", file=sys.stderr)
        print("", file=sys.stderr)
        print("Usage: {sys.argv[0]} length(between 8 and 32)", file=sys.stderr)
        sys.exit(1)
    # Number of random bytes to get (between 8 and 32)
    length = int(sys.argv[1])
    # Input validation
    if length < 8 or length > 32:
        raise ValueError("length must be between 8 and 32")
    # Create a context stack
    with contextlib.ExitStack() as ctx_stack:
        # Create a simulator
        simulator = ctx_stack.enter_context(Simulator())
        # Create temporary directories to separate this example's state
        user_dir = ctx_stack.enter_context(tempfile.TemporaryDirectory())
        log_dir = ctx_stack.enter_context(tempfile.TemporaryDirectory())
        system_dir = ctx_stack.enter_context(tempfile.TemporaryDirectory())
        # Create the FAPI object
        fapi = FAPI(
            FAPIDefaultConfig._replace(
                user_dir=user_dir,
                system_dir=system_dir,
                log_dir=log_dir,
                tcti="mssim:port=%d" % (simulator.port,),
                tcti_retry=100,
                ek_cert_less=1,
            )
        )
        # Enter the context, create TCTI connection
        fapi_ctx = ctx_stack.enter_context(fapi)
        # Call Fapi_Provision
        fapi_ctx.Provision(None, None, None)
        # Create a pointer to the byte array we'll get back from GetRandom
        array = ctx_stack.enter_context(UINT8_PTR_PTR())
        # Call GetRandom and convert the resulting array to a Python bytearray
        value = to_bytearray(length, fapi_ctx.GetRandom(length, array))
        # Ensure we got the correct number of bytes
        if length != len(value):
            raise AssertionError("Requested %d bytes, got %d" % (length, len(value)))
        # Print bytes to stdout
        sys.stdout.buffer.write(value)


if __name__ == "__main__":
    main()

I did copy the latest tmp_server to my $path, which is /usr/local/bin

Do you have any clues about it?

Thanks,
Iven

Make RC in exceptions a class

Make RC an object you can retrieve from the exception that allows you to access the various fields within the RC. Most people looking at an RC care about the actual error field, and don't really care if its parameter 1 or 2, they have to mask all that crap out to figure out what actually went wrong.

Failure to install using git+ URL with pip

I have installed pytss using pip from the master branch. I'm trying to run a simple example. I'm getting a module import error like below.

>>> from tpm2_pytss.binding import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/pytss/tpm2-pytss/tpm2_pytss/binding.py", line 9, in <module>
    from . import exceptions
  File "/pytss/tpm2-pytss/tpm2_pytss/exceptions.py", line 7, in <module>
    from .esys_binding import (
ModuleNotFoundError: No module named 'tpm2_pytss.esys_binding'

Check input params

Check params before we call the esapi library so we can give better errors than something like: TypeError: expected integer.

Possible incorrect handling of parameters in Esys_LoadExternal

I was trying to write a test for esys load external. But I could not even get the simplest test case to work.

import os
import secrets

from contextlib import ExitStack
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa

from tpm2_pytss.binding import *
from .base_esys import BaseTestESYS

class TestLoadExternal(BaseTestESYS):
    def test_load_public_rsa_key(self):
            # The tpm2-tools equivalent of what this tests is attempting to do is
            # the following:

            # tpm2_loadexternal
            #    --hierarchy=o
            #    --key-algorithm=rsa
            #    --public=public_rsa_key.pem
            #    --key-context=signing_key.ctx
            #    --name=signing_key.name

        # Create the 2048 bit RSA key.
        private_rsa_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend()
        )
        public_rsa_key = private_rsa_key.public_key()

        with ExitStack() as stack:
            # Create the public part.
            in_public = TPM2B_PUBLIC(
                size=0,
                publicArea=TPMT_PUBLIC(
                    type=TPM2_ALG_RSA, # key-algorithm=rsa
                    nameAlg=TPM2_ALG_SHA256, # hash-algorithm = default = sha256
                    objectAttributes=(
                        TPMA_OBJECT_NODA
                        | TPMA_OBJECT_DECRYPT
                        | TPMA_OBJECT_SIGN_ENCRYPT
                        | TPMA_OBJECT_USERWITHAUTH
                    ),
                    authPolicy=TPM2B_DIGEST(size=0),
                    parameters=TPMU_PUBLIC_PARMS(
                        rsaDetail=TPMS_RSA_PARMS(
                            scheme=TPMT_RSA_SCHEME(
                                scheme=TPM2_ALG_NULL,
                                details=TPMU_ASYM_SCHEME(
                                    anySig=TPMS_SCHEME_HASH(
                                        hashAlg=TPM2_ALG_NULL,
                                    ),
                                ),
                            ),
                            symmetric=TPMT_SYM_DEF_OBJECT(
                                algorithm=TPM2_ALG_NULL,
                                keyBits=TPMU_SYM_KEY_BITS(sym=0),
                                mode=TPMU_SYM_MODE(sym=TPM2_ALG_NULL),
                            ),
                            keyBits=public_rsa_key.key_size, # Number of bits in the key 2048
                            exponent=public_rsa_key.public_numbers().e, # exponent of the key 65537
                        ),
                    ),
                    unique=TPM2B_PUBLIC_KEY_RSA(
                        # public part of rsa key.
                        buffer=public_rsa_key.public_numbers().n.to_bytes(public_rsa_key.key_size // 8, byteorder=sys.byteorder)
                    ),
                ),
            )

            in_public_ptr = stack.enter_context(in_public.ptr())
            object_handle = stack.enter_context(self.esys_ctx.flush_tr())

            self.esys_ctx.LoadExternal(
                ESYS_TR_NONE,
                ESYS_TR_NONE,
                ESYS_TR_NONE,
                None,
                in_public_ptr,
                ESYS_TR_RH_OWNER,
                object_handle
            )

            # Get name from the object_handle and compare it to the public key.
            # If there is a difference throw an exception.

When I run this test I get following error message. I run this directly at the device.I have tested this with a key that works for tpm2-tools by using a code that is slightly different and it does not matter the test still fails. So is pytss doing something wierd with my parameters?

"TPM2 Error tpm:parameter(2):key fields are not compatible with the selected use"

SWIG 4 support

When building this project with SWIG 4 (version 4.0.1-1 on Arch Linux), running the tests fails with

  File "/home/jonas/tpm2-software/tpm2-pytss/tpm2_pytss/exceptions.py", line 8, in <module>
    from . import esys_binding
  File "/home/jonas/tpm2-software/tpm2-pytss/tpm2_pytss/esys_binding.py", line 413, in <module>
    class TPMS_TAGGED_PROPERTY(object):
  File "/home/jonas/tpm2-software/tpm2-pytss/tpm2_pytss/esys_binding.py", line 417, in TPMS_TAGGED_PROPERTY
    value = property(_esys_binding.TPMS_TAGGED_PROPERTY_value_get, _esys_binding.TPMS_TAGGED_PROPERTY_value_set)
TypeError: 'property' object is not callable

This might actually be a bug in SWIG since it seems to overwrite its internal property() function with the class attribute property:

class TPMS_TAGGED_PROPERTY(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr
    property = property(_esys_binding.TPMS_TAGGED_PROPERTY_property_get, _esys_binding.TPMS_TAGGED_PROPERTY_property_set)
    value = property(_esys_binding.TPMS_TAGGED_PROPERTY_value_get, _esys_binding.TPMS_TAGGED_PROPERTY_value_set)

But even if the autogenerated esys_binding.py file is fixed manually, there are lots of other errors, e.g.

======================================================================
ERROR: test_audit (tests.test_esys_audit.TestAudit)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jonas/tpm2-software/tpm2-pytss/tests/base_esys.py", line 28, in setUp
    self.tcti_ctx = self.ctx_stack.enter_context(self.tcti(config=self.tcti_config))
  File "/usr/lib/python3.7/contextlib.py", line 427, in enter_context
    result = _cm_type.__enter__(cm)
  File "/home/jonas/tpm2-software/tpm2-pytss/tpm2_pytss/tcti.py", line 34, in __enter__
    ctxpp.__enter__()
  File "/home/jonas/tpm2-software/tpm2-pytss/tpm2_pytss/util/swig.py", line 162, in __enter__
    self.ptr = self._new()
TypeError: new_tcti_ctx_ptr_ptr() takes 0 positional arguments but 1 was given

The reason for this error seems to be that in SWIG 3, new_tcti_ctx_ptr_ptr is defined as

def new_tcti_ctx_ptr_ptr() -> "struct TSS2_TCTI_CONTEXT **":
    return _esys_binding.new_tcti_ctx_ptr_ptr()
new_tcti_ctx_ptr_ptr = _esys_binding.new_tcti_ctx_ptr_ptr

while in SWIG 4 the last line is missing. I guess tpm2_pytss/util/swig.py needs to be adapted to work with SWIG 4.

Installing the legacy version swig3 and adding self.swig = "swig-3" before super().run() in setup.py causes the test suite to run successfully on Arch Linux.

docs failing to build Unicode Error

I was able to dump what its failing on (see below). It appears to be reading docutils.sty. I noticed sphinx is now version 3.5.3 which was updated on March 20. I wonder what happens if we specify an older version.

BILL: b'%% docutils.sty: macros for Docutils LaTeX output.\n%%\n%%   Copyright \xc2\xa9 2020 G\xc3\xbcnter Milde\n%%   Released under the terms of the `2-Clause BSD license`, in short:\n%%\n%%      Copying and distribution of this file, with or without modification,\n%%      are permitted in any medium without royalty provided the copyright\n%%      notice and this notice are preserved.\n%%      This file is offered as-is, without any warranty.\n\n% .. include:: README.md\n%\n% Implementation\n% ==============\n%\n% ::\n\n\\NeedsTeXFormat{LaTeX2e}\n\\ProvidesPackage{docutils}\n  [2020/08/28 macros for Docutils LaTeX output]\n\n% Helpers\n% -------\n%\n% duclass::\n\n% class handling for environments (block-level elements)\n% \\begin{DUclass}{spam} tries \\DUCLASSspam and\n% \\end{DUclass}{spam} tries \\endDUCLASSspam\n\\ifx\\DUclass\\undefined % poor man\'s "provideenvironment"\n \\newenvironment{DUclass}[1]%\n  {% "#1" does not work in end-part of environment.\n   \\def\\DocutilsClassFunctionName{DUCLASS#1}\n     \\csname \\DocutilsClassFunctionName \\endcsname}%\n  {\\csname end\\DocutilsClassFunctionName \\endcsname}%\n\\fi\n\n% providelength::\n\n% Provide a length variable and set default, if it is new\n\\providecommand*{\\DUprovidelength}[2]{\n  \\ifthenelse{\\isundefined{#1}}{\\newlength{#1}\\setlength{#1}{#2}}{}\n}\n\n\n% Configuration defaults\n% ----------------------\n%\n% See `Docutils LaTeX Writer`_ for details.\n%\n% abstract::\n\n\\providecommand*{\\DUCLASSabstract}{\n  \\renewcommand{\\DUtitle}[1]{\\centerline{\\textbf{##1}}}\n}\n\n% dedication::\n\n% special topic for dedications\n\\providecommand*{\\DUCLASSdedication}{%\n  \\renewenvironment{quote}{\\begin{center}}{\\end{center}}%\n}\n\n% TODO: add \\em to set dedication text in italics?\n%\n% docinfo::\n\n% width of docinfo table\n\\DUprovidelength{\\DUdocinfowidth}{0.9\\linewidth}\n\n% error::\n\n\\providecommand*{\\DUCLASSerror}{\\color{red}}\n\n% highlight_rules::\n\n% basic code highlight:\n\\providecommand*\\DUrolecomment[1]{\\textcolor[rgb]{0.40,0.40,0.40}{#1}}\n\\providecommand*\\DUroledeleted[1]{\\textcolor[rgb]{0.40,0.40,0.40}{#1}}\n\\providecommand*\\DUrolekeyword[1]{\\textbf{#1}}\n\\providecommand*\\DUrolestring[1]{\\textit{#1}}\n\n% Elements\n% --------\n%\n% Definitions for unknown or to-be-configured Docutils elements.\n%\n% admonition::\n\n% admonition environment (specially marked topic)\n\\ifx\\DUadmonition\\undefined % poor man\'s "provideenvironment"\n \\newbox{\\DUadmonitionbox}\n \\newenvironment{DUadmonition}%\n  {\\begin{center}\n     \\begin{lrbox}{\\DUadmonitionbox}\n       \\begin{minipage}{0.9\\linewidth}\n  }%\n  {    \\end{minipage}\n     \\end{lrbox}\n     \\fbox{\\usebox{\\DUadmonitionbox}}\n   \\end{center}\n  }\n\\fi\n\n% fieldlist::\n\n% field list environment (for separate configuration of `field lists`)\n\\ifthenelse{\\isundefined{\\DUfieldlist}}{\n  \\newenvironment{DUfieldlist}%\n    {\\quote\\description}\n    {\\enddescription\\endquote}\n}{}\n\n% footnotes::\n\n% numerical or symbol footnotes with hyperlinks and backlinks\n\\providecommand*{\\DUfootnotemark}[3]{%\n  \\raisebox{1em}{\\hypertarget{#1}{}}%\n  \\hyperlink{#2}{\\textsuperscript{#3}}%\n}\n\\providecommand{\\DUfootnotetext}[4]{%\n  \\begingroup%\n  \\renewcommand{\\thefootnote}{%\n    \\protect\\raisebox{1em}{\\protect\\hypertarget{#1}{}}%\n    \\protect\\hyperlink{#2}{#3}}%\n  \\footnotetext{#4}%\n  \\endgroup%\n}\n\n% inline::\n\n% custom inline roles: \\DUrole{#1}{#2} tries \\DUrole#1{#2}\n\\providecommand*{\\DUrole}[2]{%\n  \\ifcsname DUrole#1\\endcsname%\n    \\csname DUrole#1\\endcsname{#2}%\n  \\else%\n    #2%\n  \\fi%\n}\n\n% legend::\n\n% legend environment (in figures and formal tables)\n\\ifthenelse{\\isundefined{\\DUlegend}}{\n  \\newenvironment{DUlegend}{\\small}{}\n}{}\n\n% lineblock::\n\n% line block environment\n\\DUprovidelength{\\DUlineblockindent}{2.5em}\n\\ifthenelse{\\isundefined{\\DUlineblock}}{\n  \\newenvironment{DUlineblock}[1]{%\n    \\list{}{\\setlength{\\partopsep}{\\parskip}\n            \\addtolength{\\partopsep}{\\baselineskip}\n            \\setlength{\\topsep}{0pt}\n            \\setlength{\\itemsep}{0.15\\baselineskip}\n            \\setlength{\\parsep}{0pt}\n            \\setlength{\\leftmargin}{#1}}\n    \\raggedright\n  }\n  {\\endlist}\n}{}\n\n% optionlist::\n\n% list of command line options\n\\providecommand*{\\DUoptionlistlabel}[1]{\\bfseries #1 \\hfill}\n\\DUprovidelength{\\DUoptionlistindent}{3cm}\n\\ifthenelse{\\isundefined{\\DUoptionlist}}{\n  \\newenvironment{DUoptionlist}{%\n    \\list{}{\\setlength{\\labelwidth}{\\DUoptionlistindent}\n            \\setlength{\\rightmargin}{1cm}\n            \\setlength{\\leftmargin}{\\rightmargin}\n            \\addtolength{\\leftmargin}{\\labelwidth}\n            \\addtolength{\\leftmargin}{\\labelsep}\n            \\renewcommand{\\makelabel}{\\DUoptionlistlabel}}\n  }\n  {\\endlist}\n}{}\n\n% rubric::\n\n% informal heading\n\\providecommand*{\\DUrubric}[1]{\\subsubsection*{\\emph{#1}}}\n\n% sidebar::\n\n% text outside the main text flow\n\\providecommand{\\DUsidebar}[1]{%\n  \\begin{center}\n    \\colorbox[gray]{0.80}{\\parbox{0.9\\linewidth}{#1}}\n  \\end{center}\n}\n\n% title::\n\n% title for topics, admonitions, unsupported section levels, and sidebar\n\\providecommand*{\\DUtitle}[1]{\\subsubsection*{#1}}\n\n% subtitle::\n\n% subtitle (for sidebar)\n\\providecommand*{\\DUsubtitle}[1]{\\par\\emph{#1}\\smallskip}\n\n% documentsubtitle::\n\n% subtitle (in document title)\n\\providecommand*{\\DUdocumentsubtitle}[1]{{\\large #1}}\n\n% titlereference::\n\n% titlereference standard role\n\\providecommand*{\\DUroletitlereference}[1]{\\textsl{#1}}\n\n% transition::\n\n% transition (break / fancybreak / anonymous section)\n\\providecommand*{\\DUtransition}{%\n  \\hspace*{\\fill}\\hrulefill\\hspace*{\\fill}\n  \\vskip 0.5\\baselineskip\n}\n'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.