Home | History | Annotate | Download | only in src
      1 /*############################################################################
      2   # Copyright 2016-2017 Intel Corporation
      3   #
      4   # Licensed under the Apache License, Version 2.0 (the "License");
      5   # you may not use this file except in compliance with the License.
      6   # You may obtain a copy of the License at
      7   #
      8   #     http://www.apache.org/licenses/LICENSE-2.0
      9   #
     10   # Unless required by applicable law or agreed to in writing, software
     11   # distributed under the License is distributed on an "AS IS" BASIS,
     12   # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13   # See the License for the specific language governing permissions and
     14   # limitations under the License.
     15   ############################################################################*/
     16 
     17 /*!
     18  * \file
     19  *
     20  * \brief Create private key revocation list request
     21  *
     22  */
     23 
     24 #include <argtable3.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 
     28 #include "epid/common/file_parser.h"
     29 #include "epid/member/api.h"
     30 #include "util/buffutil.h"
     31 #include "util/envutil.h"
     32 #include "util/stdtypes.h"
     33 
     34 const OctStr16 kEpidFileVersion = {2, 0};
     35 
     36 // Defaults
     37 #define PROGRAM_NAME "revokekey"
     38 #define PRIVKEY_DEFAULT "mprivkey.dat"
     39 #define REQFILE_DEFAULT "privreq.dat"
     40 #define PUBKEYFILE_DEFAULT "pubkey.bin"
     41 #define ARGPARSE_ERROR_MAX 20
     42 #define ARGTABLE_SIZE 8
     43 
     44 /// Partial signature request, includes all but message.
     45 typedef struct PrivRlRequestTop {
     46   EpidFileHeader header;  ///< Intel(R) EPID File Header
     47   PrivKey privkey;        ///< Intel(R) EPID Private Key
     48 } PrivRlRequestTop;
     49 
     50 int OpenKey(char const* privkey_file, char const* gpubkey_file,
     51             char const* cacert_file, PrivKey* priv_key) {
     52   int retval = EXIT_FAILURE;
     53   size_t file_size = GetFileSize(privkey_file);
     54 
     55   if (0 == file_size && !FileExists(privkey_file)) {
     56     log_error("cannot access '%s'", privkey_file);
     57     return EXIT_FAILURE;
     58   }
     59 
     60   if (file_size == sizeof(PrivKey)) {
     61     if (0 != ReadLoud(privkey_file, priv_key, sizeof(PrivKey))) {
     62       return EXIT_FAILURE;
     63     }
     64     retval = EXIT_SUCCESS;
     65   } else if (file_size == sizeof(CompressedPrivKey)) {
     66     void* signed_pubkey = NULL;
     67     if (!cacert_file) {
     68       log_error("issuing CA public key must be specified for compressed key");
     69       return EXIT_FAILURE;
     70     }
     71     if (!gpubkey_file) {
     72       log_error("group public key must be specified for compressed key");
     73       return EXIT_FAILURE;
     74     }
     75 
     76     do {
     77       size_t signed_pubkey_size = 0;
     78       CompressedPrivKey cmp_key;
     79       EpidCaCertificate cacert;
     80       GroupPubKey pub_key;
     81       EpidStatus sts;
     82       if (0 != ReadLoud(privkey_file, &cmp_key, sizeof(CompressedPrivKey))) {
     83         retval = EXIT_FAILURE;
     84         break;
     85       }
     86       signed_pubkey = NewBufferFromFile(gpubkey_file, &signed_pubkey_size);
     87       if (!signed_pubkey) {
     88         retval = EXIT_FAILURE;
     89         break;
     90       }
     91       if (0 != ReadLoud(gpubkey_file, signed_pubkey, signed_pubkey_size)) {
     92         retval = EXIT_FAILURE;
     93         break;
     94       }
     95       if (0 != ReadLoud(cacert_file, &cacert, sizeof(cacert))) {
     96         retval = EXIT_FAILURE;
     97         break;
     98       }
     99       sts = EpidParseGroupPubKeyFile(signed_pubkey, signed_pubkey_size, &cacert,
    100                                      &pub_key);
    101       if (kEpidNoErr != sts) {
    102         log_error("error while parsing group public key");
    103         retval = EXIT_FAILURE;
    104         break;
    105       }
    106       sts = EpidDecompressPrivKey(&pub_key, &cmp_key, priv_key);
    107       if (kEpidNoErr != sts) {
    108         log_error("error while decompressing member private key");
    109         retval = EXIT_FAILURE;
    110         break;
    111       }
    112       retval = EXIT_SUCCESS;
    113     } while (0);
    114     free(signed_pubkey);
    115   } else {
    116     log_error("unexpected file size for '%s'", privkey_file);
    117     retval = EXIT_FAILURE;
    118   }
    119   return retval;
    120 }
    121 
    122 int MakeRequest(PrivKey const* priv_key, char const* req_file, bool verbose) {
    123   // Request buffer
    124   uint8_t* req_buf = NULL;
    125   size_t req_size = 0;
    126   size_t req_extra_space = 0;
    127   int ret_value = EXIT_FAILURE;
    128   do {
    129     size_t entry_size = sizeof(EpidFileHeader) + sizeof(PrivKey);
    130     size_t req_file_size = 0;
    131     bool duplicate = false;
    132     size_t i = 0;
    133     PrivRlRequestTop* req_top = NULL;
    134 
    135     if (!req_file) {
    136       log_error("internal error: badarg to MakeRequest()");
    137       ret_value = EXIT_FAILURE;
    138       break;
    139     }
    140 
    141     // convert command line args to usable formats
    142 
    143     // Report Settings
    144     if (verbose) {
    145       log_msg("==============================================");
    146       log_msg("Input settings:");
    147       log_msg("");
    148       log_msg(" [in]  Group ID: ");
    149       PrintBuffer(&(priv_key->gid), sizeof(priv_key->gid));
    150       log_msg("");
    151       log_msg(" [in]  Private Key Len: %d", sizeof(PrivKey));
    152       log_msg(" [in]  Private Key: ");
    153       PrintBuffer(priv_key, sizeof(PrivKey));
    154       log_msg("");
    155       log_msg("==============================================");
    156     }
    157 
    158     req_extra_space += entry_size;
    159     if (FileExists(req_file)) {
    160       req_file_size = GetFileSize_S(req_file, SIZE_MAX - req_extra_space);
    161 
    162       if (req_file_size < entry_size) {
    163         log_error("output file smaller then size of one entry");
    164         ret_value = EXIT_FAILURE;
    165         break;
    166       }
    167 
    168       if (req_file_size % entry_size != 0) {
    169         log_error("size of output file is not multiple of the entry size");
    170         ret_value = EXIT_FAILURE;
    171         break;
    172       }
    173     } else {
    174       log_msg("request file does not exsist, create new");
    175     }
    176 
    177     req_size = req_file_size + req_extra_space;
    178 
    179     req_buf = AllocBuffer(req_size);
    180     if (!req_buf) {
    181       ret_value = EXIT_FAILURE;
    182       break;
    183     }
    184 
    185     // Load existing request file
    186     if (req_file_size > 0) {
    187       if (0 != ReadLoud(req_file, req_buf, req_file_size)) {
    188         ret_value = EXIT_FAILURE;
    189         break;
    190       }
    191 
    192       for (i = 0; i < req_file_size / entry_size; i++) {
    193         if (0 == memcmp(req_buf + entry_size * i + sizeof(EpidFileHeader),
    194                         priv_key, sizeof(PrivKey))) {
    195           duplicate = true;
    196           break;
    197         }
    198       }
    199       if (duplicate) {
    200         log_error("this private key already exists in output file");
    201         ret_value = EXIT_FAILURE;
    202         break;
    203       }
    204     }
    205 
    206     // Append to the request
    207     req_top = (PrivRlRequestTop*)(req_buf + req_file_size);
    208     req_top->header.epid_version = kEpidFileVersion;
    209     req_top->header.file_type = kEpidFileTypeCode[kPrivRlRequestFile];
    210     req_top->privkey = *priv_key;
    211 
    212     // Report Settings
    213     if (verbose) {
    214       log_msg("==============================================");
    215       log_msg("Request generated:");
    216       log_msg("");
    217       log_msg(" [in]  Request Len: %d", sizeof(PrivRlRequestTop));
    218       log_msg(" [in]  Request: ");
    219       PrintBuffer(req_top, sizeof(PrivRlRequestTop));
    220       log_msg("==============================================");
    221     }
    222 
    223     // Store request
    224     if (0 != WriteLoud(req_buf, req_size, req_file)) {
    225       ret_value = EXIT_FAILURE;
    226       break;
    227     }
    228 
    229     ret_value = EXIT_SUCCESS;
    230   } while (0);
    231 
    232   // Free allocated buffers
    233   if (req_buf) free(req_buf);
    234 
    235   return ret_value;
    236 }
    237 
    238 /// Main entrypoint
    239 int main(int argc, char* argv[]) {
    240   int retval = EXIT_FAILURE;
    241 
    242   // Verbose flag parameter
    243   static bool verbose_flag = false;
    244 
    245   // Private key
    246   PrivKey priv_key;
    247 
    248   struct arg_file* privkey_file = arg_file0(
    249       NULL, "mprivkey", "FILE",
    250       "load private key to revoke from FILE (default: " PRIVKEY_DEFAULT ")");
    251   struct arg_file* req_file = arg_file0(
    252       NULL, "req", "FILE",
    253       "append signature revocation request to FILE (default: " REQFILE_DEFAULT
    254       ")");
    255   struct arg_lit* help = arg_lit0(NULL, "help", "display this help and exit");
    256   struct arg_lit* verbose =
    257       arg_lit0("v", "verbose", "print status messages to stdout");
    258   struct arg_rem* comment_line = arg_rem(
    259       NULL, "The following options are only needed for compressed keys:");
    260   struct arg_file* gpubkey_file = arg_file0(
    261       NULL, "gpubkey", "FILE",
    262       "load group public key from FILE (default: " PUBKEYFILE_DEFAULT ")");
    263   struct arg_file* capubkey_file = arg_file0(
    264       NULL, "capubkey", "FILE", "load IoT Issuing CA public key from FILE");
    265   struct arg_end* end = arg_end(ARGPARSE_ERROR_MAX);
    266   void* argtable[ARGTABLE_SIZE];
    267   int nerrors;
    268 
    269   /* initialize the argtable array with ptrs to the arg_xxx structures
    270    * constructed above */
    271   argtable[0] = privkey_file;
    272   argtable[1] = req_file;
    273   argtable[2] = help;
    274   argtable[3] = verbose;
    275   argtable[4] = comment_line;
    276   argtable[5] = gpubkey_file;
    277   argtable[6] = capubkey_file;
    278   argtable[7] = end;
    279 
    280   // set program name for logging
    281   set_prog_name(PROGRAM_NAME);
    282   do {
    283     /* verify the argtable[] entries were allocated sucessfully */
    284     if (arg_nullcheck(argtable) != 0) {
    285       /* NULL entries were detected, some allocations must have failed */
    286       printf("%s: insufficient memory\n", PROGRAM_NAME);
    287       retval = EXIT_FAILURE;
    288       break;
    289     }
    290 
    291     /* set any command line default values prior to parsing */
    292     privkey_file->filename[0] = PRIVKEY_DEFAULT;
    293     gpubkey_file->filename[0] = PUBKEYFILE_DEFAULT;
    294     req_file->filename[0] = REQFILE_DEFAULT;
    295     capubkey_file->filename[0] = NULL;
    296 
    297     /* Parse the command line as defined by argtable[] */
    298     nerrors = arg_parse(argc, argv, argtable);
    299 
    300     if (help->count > 0) {
    301       log_fmt(
    302           "Usage: %s [OPTION]...\n"
    303           "Revoke Intel(R) EPID signature\n"
    304           "\n"
    305           "Options:\n",
    306           PROGRAM_NAME);
    307       arg_print_glossary(stdout, argtable, "  %-25s %s\n");
    308       retval = EXIT_SUCCESS;
    309       break;
    310     }
    311     if (verbose->count > 0) {
    312       verbose_flag = ToggleVerbosity();
    313     }
    314     /* If the parser returned any errors then display them and exit */
    315     if (nerrors > 0) {
    316       /* Display the error details contained in the arg_end struct.*/
    317       arg_print_errors(stderr, end, PROGRAM_NAME);
    318       fprintf(stderr, "Try '%s --help' for more information.\n", PROGRAM_NAME);
    319       retval = EXIT_FAILURE;
    320       break;
    321     }
    322     if (verbose_flag) {
    323       log_msg("\nOption values:");
    324       log_msg(" mprivkey  : %s", privkey_file->filename[0]);
    325       log_msg(" req       : %s", req_file->filename[0]);
    326       log_msg(" gpubkey   : %s", gpubkey_file->filename[0]);
    327       log_msg(" capubkey  : %s", capubkey_file->filename[0]);
    328       log_msg("");
    329     }
    330 
    331     retval = OpenKey(privkey_file->filename[0], gpubkey_file->filename[0],
    332                      capubkey_file->filename[0], &priv_key);
    333     if (EXIT_SUCCESS != retval) {
    334       break;
    335     }
    336     retval = MakeRequest(&priv_key, req_file->filename[0], verbose_flag);
    337   } while (0);
    338 
    339   arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
    340 
    341   return retval;
    342 }
    343