This walkthrough of the verifysig
example shows you how to use SDK APIs to verify an Intel® EPID 2.0 signature. Verifysig is built during the SDK build.
To verify an Intel® EPID 1.1 signature see the example code in verifysig11.c
. For information on Intel® EPID 1.1 speciifc APIs see EPID 1.1 support.
First, we include headers so we have access to needed declarations.
The utility headers are used by verifysig
for logging and buffer management. The epid/verifier/api.h
header provides access to the core verifier APIs, and the epid/common/file_parser.h
header provides an API for parsing buffers formatted according to the various IoT Intel® EPID binary file formats.
We define a stub function responsible for checking that the CA certificate is authorized by the root CA.
IsCaCertAuthorizedByRootCa is called from main.c
to validate the CA certificate before calling Verify
. In an actual implementation, you need to provide an implementation to validate the issuing CA certificate with the CA root certificate before using it in parse functions.
We use Verify
to verify an Intel® EPID signature. Verify
is a wrapper function that isolates SDK API functionality for the purpose of this walkthrough.
The Verify
parameters were either sent by the verifier to the member, or they were part of the member's configuration. The exceptions are the sig
and sig_len
parameters, which we use to input the signature to be verified.
The verifier might send the message to the member or there may be another mechanism to choose the message, but the way the message is communicated is outside the scope of the Intel® EPID scheme.
We use the parameters verifier_precomp
and verifier_precomp_is_input
to pass in a pre-computation blob if provided. We can use the pre-computation blob to increase performance when verifying signatures repeatedly with the same group public key.
The member and the verifier agree on the message, basename, hash algorithm, and SigRL that the verifier uses for verification.
Next we do basic variable setup.
We create pointers to resources to be allocated and we use the do {} while(0)
idiom so that we can reliably free resources on return from Verify
. We also allocate the group public key on the stack.
Next, we authenticate and extract the group public key using EpidParseGroupPubKeyFile.
EpidParseGroupPubKeyFile takes a buffer containing a group public key in issuer binary format and validates that the public key is signed by the private key that corresponds to the provided CA certificate, reading the key into pub_key
in the process.
Next, we create a verifier context using EpidVerifierCreate.
If a pre-computation blob is provided to the top level application, we use it. Otherwise, we pass in NULL
.
Then we serialize pre-computed verifier data using EpidVerifierWritePrecomp.
The serialized verifier pre-computation blob can be used to greatly increase performance of EpidVerifierCreate in future sessions if the same group public key is used.
We use EpidVerifierSetHashAlg to indicate the hash algorithm used for verification, which should be the same algorithm that the member used when signing.
After the hash algorithm is set, future calls to EpidVerify will use the same algorithm.
We use EpidVerifierSetBasename to indicate the basename used for verification, which should be the same one that the member used when signing.
After the basename is set, future calls to EpidVerify will use the same basename.
Before we verify a signature, we have to configure revocation lists so that we can check to see if a signer's group membership has been revoked.
We set the private key based revocation list using EpidVerifierSetPrivRl.
We use EpidParsePrivRlFile to:
To determine the required priv_rl
buffer size, we provide a null pointer for the output buffer when calling EpidParsePrivRlFile.
After we find out the required size of the priv_rl
buffer, we allocate memory for it. Then we fill the buffer using EpidParsePrivRlFile.
Next, we set the signature based revocation list using EpidVerifierSetSigRl.
We use EpidParseSigRlFile to:
To determine the required sig_rl
buffer size, we provide a null pointer for the output buffer when calling EpidParseSigRlFile.
After we find out the required size of the sig_rl
buffer, we allocate memory for it. Then we fill the buffer using EpidParseSigRlFile.
Next, we set the group based revocation list using EpidVerifierSetGroupRl.
We use EpidParseGroupRlFile to:
To determine the required grp_rl
buffer size, we provide a null pointer for the output buffer when calling EpidParseGroupRlFile.
After we find out the required size of the grp_rl
buffer, we allocate memory for it. Then we fill the buffer using EpidParseGroupRlFile.
Next, we set the verifier blacklist using EpidVerifierSetVerifierRl.
The verifier is responsible for ensuring that the verifier revocation list is authorized. Validating it is outside the scope of this example.
Next, we use EpidVerify to verify that the Intel® EPID signature was created by a valid member of a group in good standing.
Finally, we clean up and exit.
If we made it past verification without an error, we set the return code appropriately and fall out of the do-while
loop. If there was an error earlier, all breaks in the do-while
loop bring us to this point with an error status.
Then we free the allocated resources. EpidVerifierDelete deletes the verifier context.
After deleting the verifier context, we can also delete the revocation lists.
We return from Verify
with the success or error status.
This concludes the verifysig
walkthrough. Now you should be able to verify an Intel® EPID signature using the SDK APIs.
To learn more about the SDK APIs see the API Reference. To learn more about the Intel® EPID Scheme see Introduction to the Intel® EPID Scheme in the documentation.