Application Keys

Although a user (customer) application has a great deal of flexibility about how it manages its keys, the security world API provides a standard approach.

Within a security world application keys are often denoted KA. Within a given application they should be given a more descriptive name!

Secret Key ACLs

If the standard tools are used, then private and symmetric keys have (some of) the groups described in the following sections:

Main Use Group

Normally all keys have a main use group allowing the operations relevant to their purpose. For application key it would usually allow the following:

  • Whichever of Sign, Verify, Encrypt, Decrypt, SignModuleCert, UseAsCertificate, UseAsLoaderKey, and UseAsBlobKey are appropriate to the key type and application.

    UseAsLoaderKey is used for SEE confidentiality keys; it allows decryption but only when loading an SEE machine or userdata.

  • GetAppData.

  • Safe operations such as DuplicateHandle, ReduceACL and GetACL.

Example

groups[0].flags= none 0x00000000
         .n_limits= 0
         .n_actions= 1
         .actions[ 0].type= OpPermissions
         .details.oppermissions.perms= DuplicateHandle UseAsCertificate GetAppData ReduceACL Decrypt UseAsBlobKey Sign
                                       GetACL SignModuleCert 0x0000b52b
         .certifier absent
         .certmech absent
         .moduleserial absent

Encrypt and Verify are missing because this is the ACL for the private half of an asymmetric key. UseAsBlobKey is present because this bit controls both creation and loading of blobs.

The effect is that authorized users of the key, for example, as identified by ability to present an operator card set quorum, can use the key to perform cryptographic operations (sign, decrypt, and so on) but not change its protection.

In some cases this group is split into two. See Use Limits And SEE Application Keys.

Working Blob Group

Most keys have a working blob group to allow them to be persisted. For application keys this will allow MakeBlob under KM (for module keys) or the logical token that will protect the key. This is a single-use group.

Example

.groups[1].flags= none 0x00000000
          .n_limits= 1
          .limits[0].type= Global
                    .details.global.id= 20 bytes 423141fd d65aa9d7 5982be14 2bd1c572 a7475f94
                                   .max= 0x00000001 1
          .n_actions= 1
          .actions[0].type= MakeBlob
                    .details.makeblob.flags= AllowKmOnly AllowNonKm0 kmhash_present 0x00000007
                                     .kmhash= 20 bytes 8fd82ce3 2e58f8e4 b559dddb 62de8cf6 5e66ce58
                                     .kthash absent
                                     .ktparams absent
                                     .blobfile absent
          .certifier absent
          .certmech absent
          .moduleserial absent

kmhash (0x8fd82ce3…​) constrains the module key that will protect this key.

In contrast the ACL for a token-protected key identifies the logical token under which it may be blobbed. Here only the action is shown, the rest of the group has the same structure as above:

.actions[0].type= MakeBlob
           .details.flags= AllowNonKm0|kmhash_present|kthash_present|ktparams_present
                   .kmhash= 8fd82ce3 2e58f8e4 b559dddb 62de8cf6 5e66ce58
                   .kthash= 608631c1 699af879 5ff36393 f597155a 0a53af05
                   .ktparams.flags= AllTokensRemovable|AllButOneRemovable
                            .sharesneeded= 1
                            .sharestotal= 1
                            .timelimit= 0

Here kmhash (0x8fd8…​) constrains the module key associated with the logical token that will protect this key. kthash (0x6086…​) constrains the hash of the logical token itself.

The values below ktparams represent the least secure token parameters acceptable, for example, the minimum sharesneeded and the maximum sharestotal.

This group is only used during key generation. Permission groups with a global use limit are dropped when the key is reloaded (via Cmd_LoadBlob).

Trump Operations Group

Recoverable keys, and most of the security world administrator keys have a trump operations group, allowing:

  • The safe permissions: DuplicateHandle, GetACL, ReduceACL.

  • The following additional permissions: GetAppData, SetAppData and ExpandACL.

  • Except in strict-FIPS worlds, ExportAsPlain.

  • MakeBlob and MakeArchiveBlob actions.

This group requires KNSO authorization.

Example

.groups[2].flags= certifier_present FreshCerts 0x00000003
          .n_limits= 0
          .n_actions= 3
          .actions[0].type= OpPermissions
                     .details.oppermissions.perms= DuplicateHandle ExportAsPlain GetAppData SetAppData ReduceACL ExpandACL GetACL 0x0000207d
          .actions[1].type= MakeBlob
                     .details.makeblob.flags= AllowKmOnly AllowNonKm0 AllowNullKmToken 0x00000023
                                      .kmhash absent
                                      .kthash absent
                                      .ktparams absent
                                      .blobfile absent
          .actions[2].type= MakeArchiveBlob
                     .details.makearchiveblob.flags= none 0x00000000
                                      .mech= Any
                                      .kahash absent
                                      .blobfile absent
          .certifier= 20 bytes 787720a1 e305a5af 6c8564af 3f6bfe55 122a733d
          .certmech absent
          .moduleserial absent

0x787720a1…​ is the hash of KNSO for this security world.

The effect of this group is to allow changes to the key’s protection and application data, and (except in strict-FIPS worlds) export of its key material, authorized by an administrator cardset quorum.

Recovery blob group

Recoverable keys have a recovery blob group allowing MakeArchiveBlob under KRE. This is a single-use group, only used during key generation.

Example

.groups[3].flags= none 0x00000000
          .n_limits= 1
          .limits[0].type= Global
                    .details.global.id= 20 bytes 5989ba51 acfda26b e09d735a 389621fb f260b2e4
                                   .max= 0x00000001 1
          .n_actions= 1
          .actions[0].type= MakeArchiveBlob
                     .details.makearchiveblob.flags= kahash_present 0x00000001
                                             .mech= BlobCryptv2kRSAeRijndaelCBC0hSHA512mSHA512HMAC
                                             .kahash= 20 bytes a7ae9935 f04f4680 c3046a02 c7fa838d d3ffd3ed
                                             .blobfile absent
          .certifier absent
          .certmech absent
          .moduleserial absent

0xa7ae9935…​ is the hash of KRE.

Note that module-protected keys are always recoverable, i.e., they have a trump operations group.

  • Module-protected keys are protected by encryption under KM.

  • KM is in turn protected by encryption under LTM.

  • KM also has a trump operations group, necessary to support Administrator Card Set replacement.

The consequence of these facts is that control of an Administrator Card Set quorum is sufficient to recover the plaintext of a module-protected key, even in the absence of the trump ops or recovery blob groups on that key. Only softcard- and OCS-protected keys can be non-recoverable.

Public Key ACLs

The standard ACL for a public key is much simpler. There is just one group with no limits or certification requirements, containing a permissive main use action and a blobbing action allowing any module key to be used. In practice, KMWK will be used.

Example

.groups[0].flags= none 0x00000000
          .n_limits= 0
          .n_actions= 2
          .actions[0].type= OpPermissions
                     .details.oppermissions.perms= DuplicateHandle ExportAsPlain GetAppData SetAppData ReduceACL ExpandACL
                                                   Encrypt Verify UseAsBlobKey GetACL 0x000026fd
          .actions[1].type= MakeBlob
                    .details.makeblob.flags= AllowKmOnly AllowNonKm0 AllowNullKmToken 0x00000023
                                     .kmhash absent
                                     .kthash absent
                                     .ktparams absent
                                     .blobfile absent
          .certifier absent
          .certmech absent
          .moduleserial absent

Use Limits And SEE Application Keys

ACL construction can specify the following restrictions on the use of secret keys:

  • Time limits. This is done with a UseLim_Time limit.

  • Use count limits. This is done with a UseLim_Auth limit.

  • Restriction to SEE machines. This is done by requiring certification from the SEE integrity key that will sign the SEE machine(s).

If any of these restrictions are present then then the main use permission group is split in two.

The first is similar to an ordinary main use group but only allows the DuplicateHandle, ReduceACL and GetACL permissions.

The second allows the remaining permissions (GetAppData and the permissions specific to the key type), and carries the restrictions.

An example group requiring authorization from a SEE integrity key:

.groups[ 1].flags= certmech_present 0x00000004
           .n_limits= 0
           .n_actions= 1
           .actions[0].type= OpPermissions
                      .details.oppermissions.perms= UseAsCertificate GetAppData Encrypt Decrypt Verify UseAsBlobKey Sign
                                                    SignModuleCert 0x0000978a
           .certifier absent
           .certmech.hash= 20 bytes 2864a558 3012768e bf20da8a 4bfc7ee0 ceeee9cb
                    .mech= Any
           .moduleserial absent

0x2864a558…​ is the hash of the SEE integrity key.

SEE applications would present authorization in the form of a SEECert certificate, either hard-coding the signing key’s hash or using Cmd_GetWorldSigners to retrieve it.

The time limit and use limit can be found in the timelimit and pa_uselimit members of an NFKM_Key structure. The identifier of the SEE integrity key can be found in the identseeinteg member.

Non-Volatile Use Limits (Key Counting)

This feature allows the use of a key to be counted and for a maximum number of uses to be enforced.

Counting is implemented by identifying a region of an NVRAM file that will contain the counter. Other file types, such as smartcards, cannot be used. This means that key counting is only implemented within the context of a single module. If the key is used on multiple modules then the counts must be added up separately.

"Blocks" of uses may be reserved in advance, allowing a trade-off between performance and accuracy.

Counting is implemented as a use limit on a permission group. A typical configuration would split the main use group in two (as above), with the "harmless" permissions, such as GetACL, uncounted and the important ones such as Sign, Decrypt, counted.

The limit may contain an upper bound on the number of uses of the key. If the requirement is just counting then this limit can be set to 264-1.

The mscapi and caping components support key counting. The standard ACL generation code does not provide any standard way to add the extra use limits, though this could be done manually with an ACL they construct.

An example use limit allowing any number of uses but requiring exact counting:

.type= NonVolatile 4
.details.nonvolatile.flags= none 0x00000000
                    .file= (name) 11 bytes
                    .range.first= 0x00000000 0
                          .last= 0x00000007 7
                    .maxlo= 0xffffffff
                    .maxhi= 0xffffffff
                    .prefetch= 0x00000000 0

The name of the NVRAM file is chosen by the host. The convention used is that the first byte of the name is 1 for a key-exchange key, 2 for a signature key (RSA or DSA) and 3 for a caping key. (These are numeric values, not ASCII digits.)

NVRAM Keys (Keys In The Box)

This feature allows encrypted key blobs to be stored in the module’s NVRAM rather than in the host’s key management data directory.

To write a key blob to an NVRAM file, Cmd_MakeBlob requires extra parameters:

  • file.file must identify the NVRAM file to write to.

  • file.kacl must be a KeyType_DKTemplate key giving the ACL for the file. The ACL must permit blobs to be loaded from it.

The real key blob is written to the file and the blob field in the reply is just a pointer to the file, which Cmd_LoadBlob knows how to interpret.

To require that a key can only be written to an NVRAM file, the MakeBlob and MakeArchiveBlob actions in its ACL must specify additional restrictions:

  • blobfile.devs must restrict key to being written to NVRAM files.

  • blobfile.aclhash must specify the hash of the NVRAM file’s ACL. This is best computed by temporarily constructing the DKTemplate key that will eventually be used to supply the ACL to the file and retrieving its key hash, rather than by attempting to hash the ACL directly.

Example MakeBlob action:

.actions[ 0].type= MakeBlob
            .details.makeblob.flags= AllowKmOnly AllowNonKm0 kmhash_present blobfile_present 0x00000047
                             .kmhash= 20 bytes 8fd82ce3 2e58f8e4 b559dddb 62de8cf6 5e66ce58
                             .kthash absent
                             .ktparams absent
                             .blobfile.flags= devs_present aclhash_present 0x00000003
                                      .devs= NVMem PhysToken 0x00000003
                                      .aclhash= 20 bytes 7e8d1b59 fd7e2de0 eb383c52 2468aed0 20010018
.certifier absent
.certmech absent
.moduleserial absent

Example NVRAM file ACL:

ACL.groups[0].flags= 0x0
             .limits= empty
            .actions[0].type= NVMemOpPerms
                      .details.perms= GetACL|LoadBlob
            .actions[1].type= FileCopy
                      .details.flags= 0x0
                              .to= NVMem|PhysToken
                              .from= NVMem|PhysToken
.groups[1].flags= certifier_present|FreshCerts
            .limits= empty
            .actions[0].type= NVMemOpPerms
.details.perms= Read|Write|Free|GetACL|LoadBlob|Resize
            .certifier= 787720a1 e305a5af 6c8564af 3f6bfe55 122a733d

Note the presence of LoadBlob in the permissions. The FileCopy action in the first group permits backup to a smartcard.

The name of the NVRAM file is chosen by the host. The convention is that the first byte of the name is 'b' (0x62) for the working blob and 'r' (0x72) for a recovery blob, with the remaining 10 bytes being the first half of the key hash.

Application Key Generation APIs

The nCore commands are as follows:

  • Cmd_GenerateKey and Cmd_GenerateKeyPair generate symmetric and asymmetric keys, respectively. They require certification from KNSO (via KFIPS) in a strict-FIPS security world.

  • Cmd_Import imports a symmetric key or one half of an asymmetric key. The import of secret keys (symmetric keys and private halves of asymmetric keys) is forbidden in strict-FIPS security worlds.

  • Cmd_DeriveKey can be used to combine keys to construct new ones, for instance merging keys via XOR or decrypting one key with another.

Supporting C APIs are declared in nfkm.h:

  • NFKM_newkey_makeaclx() can be used to construct ACLs for new application keys. Unless the key has unusual requirements this should be used instead of attempting to construct the ACL manually. It may be convenient to construct the ACL with this function and then modify it.

  • NFKM_newkey_makeauth() can be used to supply the KFIPS delegation when generating keys. General –purpose code can call it without caring whether it is in a strict-FIPS world or not since in a non-strict-FIPS world it does nothing.

  • NFKM_newkey_makeblobsx() can be used to create working and recovery blobs for newly generated keys, storing the blob(s) in an NFKM_Key (for later storage to the key management data directory). It assumes a reasonably standard ACL was used.

  • NFKM_newkey_writecert() can be used to store key generation certificates for newly generated keys.

  • NFKM_recordkey() writes an NFKM_Key structure to disk.

For NVRAM keys:

  • The NKFM_NKF_NVMemBlob and NFKM_NKF_NVMemBlobX flags cause NFKM_newkey_makeaclx() to generate an ACL which requires the key to be written to an NVRAM file. The former uses a default ACL for the file (which allows backup to a smartcard), the latter allow the callers to specify the hash of the ACL.

  • The same flags cause NFKM_newkey_makeblobsx() to write the working and recovery blobs to NVRAM files. As above the it is possible either to use a default ACL or to supply one (as a DKTemplate key). In either case, a handle to KNV must be supplied to authorize writing to NVRAM.

The Python APIs are analogous:

  • nfkm.makeacl() and nfkm.makeaclandflags() to construct ACLs.

  • nfkm.makeblobs() to create blobs.

  • nfkm.writecert() to store key generation certificates.

  • nfkm.recordkey() writes the key data (including blobs) to disk.

Application Key Generation Example

This example shows:

  • Identifying a usable module. This step is necessary if any attached module may not be fully usable, either because it is not in operational mode or if it is not in the security world used by the application.

  • Constructing the key generation command, including automatic ACL construction. Don’t construct ACLs manually unless you have special requirements or do not care about the security of the key.

  • Generating blobs and module certificates for the key.

  • Storing the key to the key management data directory.

#! /opt/nfast/python/bin/python
import nfkm,time

# nCore connectivity
conn=nfkm.connection()

# Find a usable module
for moduleinfo in nfkm.getinfo(conn).modules:
    if moduleinfo.state == 'Usable':
        module=moduleinfo.module

# Construct key generation command
cmd=nfkm.Command()
cmd.cmd='GenerateKeyPair'
cmd.args.flags='Certify'
cmd.args.module=module
cmd.args.params.type='DSAPrivate'
cmd.args.params.params.lenbits=1024

# Get sworld library to construct ACLs
cmd.args.aclpriv,privflags=nfkm.makeaclandflags(conn,['Sign'])
cmd.args.aclpub=nfkm.makeacl(conn,['Verify'], pubkey=True)

# Generate the key
print cmd,"\n"
reply = conn.transact(cmd)
print reply,"\n"

# Fill in the key information structure
key=nfkm.makeblobs(conn, privflags, reply.reply.keypriv, reply.reply.keypub)
key=nfkm.writecert(conn, module,
                   reply.reply.keypriv, reply.reply.certpriv, key)
key.appname="simple"
key.ident="example"
key.gentime=int(time.time())
print key,"\n"

# Save the key
nfkm.recordkey(conn,key)

For a roughly analogous example in C, see the mkaeskey.c example from CipherTools.