[BACK]Return to sk-usbhid.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/sk-usbhid.c between version 1.11 and 1.12

version 1.11, 2019/12/30 09:24:45 version 1.12, 2020/01/06 02:00:46
Line 50 
Line 50 
         } while (0)          } while (0)
 #endif  #endif
   
 #define SK_VERSION_MAJOR        0x00030000 /* current API version */  #define SK_VERSION_MAJOR        0x00040000 /* current API version */
   
 /* Flags */  /* Flags */
 #define SK_USER_PRESENCE_REQD           0x01  #define SK_USER_PRESENCE_REQD           0x01
Line 87 
Line 87 
 };  };
   
 struct sk_resident_key {  struct sk_resident_key {
         uint8_t alg;          uint32_t alg;
         size_t slot;          size_t slot;
         char *application;          char *application;
         struct sk_enroll_response key;          struct sk_enroll_response key;
 };  };
   
   struct sk_option {
           char *name;
           char *value;
           uint8_t required;
   };
   
 /* If building as part of OpenSSH, then rename exported functions */  /* If building as part of OpenSSH, then rename exported functions */
 #if !defined(SK_STANDALONE)  #if !defined(SK_STANDALONE)
 #define sk_api_version          ssh_sk_api_version  #define sk_api_version          ssh_sk_api_version
Line 105 
Line 111 
 uint32_t sk_api_version(void);  uint32_t sk_api_version(void);
   
 /* Enroll a U2F key (private key generation) */  /* Enroll a U2F key (private key generation) */
 int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,  int sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
     const char *application, uint8_t flags, const char *pin,      const char *application, uint8_t flags, const char *pin,
     struct sk_enroll_response **enroll_response);      struct sk_option **options, struct sk_enroll_response **enroll_response);
   
 /* Sign a challenge */  /* Sign a challenge */
 int sk_sign(int alg, const uint8_t *message, size_t message_len,  int sk_sign(uint32_t alg, const uint8_t *message, size_t message_len,
     const char *application, const uint8_t *key_handle, size_t key_handle_len,      const char *application, const uint8_t *key_handle, size_t key_handle_len,
     uint8_t flags, const char *pin, struct sk_sign_response **sign_response);      uint8_t flags, const char *pin, struct sk_option **options,
       struct sk_sign_response **sign_response);
   
 /* Load resident keys */  /* Load resident keys */
 int sk_load_resident_keys(const char *pin,  int sk_load_resident_keys(const char *pin, struct sk_option **options,
     struct sk_resident_key ***rks, size_t *nrks);      struct sk_resident_key ***rks, size_t *nrks);
   
 static void skdebug(const char *func, const char *fmt, ...)  static void skdebug(const char *func, const char *fmt, ...)
Line 231 
Line 238 
   
 /* Iterate over configured devices looking for a specific key handle */  /* Iterate over configured devices looking for a specific key handle */
 static fido_dev_t *  static fido_dev_t *
 find_device(const uint8_t *message, size_t message_len, const char *application,  find_device(const char *path, const uint8_t *message, size_t message_len,
     const uint8_t *key_handle, size_t key_handle_len)      const char *application, const uint8_t *key_handle, size_t key_handle_len)
 {  {
         fido_dev_info_t *devlist = NULL;          fido_dev_info_t *devlist = NULL;
         fido_dev_t *dev = NULL;          fido_dev_t *dev = NULL;
         size_t devlist_len = 0, i;          size_t devlist_len = 0, i;
         const char *path;  
         int r;          int r;
   
           if (path != NULL) {
                   if ((dev = fido_dev_new()) == NULL) {
                           skdebug(__func__, "fido_dev_new failed");
                           return NULL;
                   }
                   if ((r = fido_dev_open(dev, path)) != FIDO_OK) {
                           skdebug(__func__, "fido_dev_open failed");
                           fido_dev_free(&dev);
                           return NULL;
                   }
                   return dev;
           }
   
         if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {          if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
                 skdebug(__func__, "fido_dev_info_new failed");                  skdebug(__func__, "fido_dev_info_new failed");
                 goto out;                  goto out;
Line 398 
Line 417 
 }  }
   
 static int  static int
 pack_public_key(int alg, const fido_cred_t *cred,  pack_public_key(uint32_t alg, const fido_cred_t *cred,
     struct sk_enroll_response *response)      struct sk_enroll_response *response)
 {  {
         switch(alg) {          switch(alg) {
Line 427 
Line 446 
         }          }
 }  }
   
   static int
   check_enroll_options(struct sk_option **options, char **devicep,
       uint8_t *user_id, size_t user_id_len)
   {
           size_t i;
   
           if (options == NULL)
                   return 0;
           for (i = 0; options[i] != NULL; i++) {
                   if (strcmp(options[i]->name, "device") == 0) {
                           if ((*devicep = strdup(options[i]->value)) == NULL) {
                                   skdebug(__func__, "strdup device failed");
                                   return -1;
                           }
                           skdebug(__func__, "requested device %s", *devicep);
                   } if (strcmp(options[i]->name, "user") == 0) {
                           if (strlcpy(user_id, options[i]->value, user_id_len) >=
                               user_id_len) {
                                   skdebug(__func__, "user too long");
                                   return -1;
                           }
                           skdebug(__func__, "requested user %s",
                               (char *)user_id);
                   } else {
                           skdebug(__func__, "requested unsupported option %s",
                               options[i]->name);
                           if (options[i]->required) {
                                   skdebug(__func__, "unknown required option");
                                   return -1;
                           }
                   }
           }
           return 0;
   }
   
 int  int
 sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,  sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
     const char *application, uint8_t flags, const char *pin,      const char *application, uint8_t flags, const char *pin,
     struct sk_enroll_response **enroll_response)      struct sk_option **options, struct sk_enroll_response **enroll_response)
 {  {
         fido_cred_t *cred = NULL;          fido_cred_t *cred = NULL;
         fido_dev_t *dev = NULL;          fido_dev_t *dev = NULL;
Line 450 
Line 504 
                 skdebug(__func__, "enroll_response == NULL");                  skdebug(__func__, "enroll_response == NULL");
                 goto out;                  goto out;
         }          }
           memset(user_id, 0, sizeof(user_id));
           if (check_enroll_options(options, &device,
               user_id, sizeof(user_id)) != 0)
                   goto out; /* error already logged */
   
         *enroll_response = NULL;          *enroll_response = NULL;
         switch(alg) {          switch(alg) {
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
Line 464 
Line 523 
                 skdebug(__func__, "unsupported key type %d", alg);                  skdebug(__func__, "unsupported key type %d", alg);
                 goto out;                  goto out;
         }          }
         if ((device = pick_first_device()) == NULL) {          if (device == NULL && (device = pick_first_device()) == NULL) {
                 skdebug(__func__, "pick_first_device failed");                  skdebug(__func__, "pick_first_device failed");
                 goto out;                  goto out;
         }          }
Line 473 
Line 532 
                 skdebug(__func__, "fido_cred_new failed");                  skdebug(__func__, "fido_cred_new failed");
                 goto out;                  goto out;
         }          }
         memset(user_id, 0, sizeof(user_id));  
         if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK) {          if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK) {
                 skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r));                  skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r));
                 goto out;                  goto out;
Line 650 
Line 708 
 }  }
   
 static int  static int
 pack_sig(int alg, fido_assert_t *assert, struct sk_sign_response *response)  pack_sig(uint32_t  alg, fido_assert_t *assert,
       struct sk_sign_response *response)
 {  {
         switch(alg) {          switch(alg) {
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
Line 664 
Line 723 
         }          }
 }  }
   
   /* Checks sk_options for sk_sign() and sk_load_resident_keys() */
   static int
   check_sign_load_resident_options(struct sk_option **options, char **devicep)
   {
           size_t i;
   
           if (options == NULL)
                   return 0;
           for (i = 0; options[i] != NULL; i++) {
                   if (strcmp(options[i]->name, "device") == 0) {
                           if ((*devicep = strdup(options[i]->value)) == NULL) {
                                   skdebug(__func__, "strdup device failed");
                                   return -1;
                           }
                           skdebug(__func__, "requested device %s", *devicep);
                   } else {
                           skdebug(__func__, "requested unsupported option %s",
                               options[i]->name);
                           if (options[i]->required) {
                                   skdebug(__func__, "unknown required option");
                                   return -1;
                           }
                   }
           }
           return 0;
   }
   
 int  int
 sk_sign(int alg, const uint8_t *message, size_t message_len,  sk_sign(uint32_t alg, const uint8_t *message, size_t message_len,
     const char *application,      const char *application,
     const uint8_t *key_handle, size_t key_handle_len,      const uint8_t *key_handle, size_t key_handle_len,
     uint8_t flags, const char *pin, struct sk_sign_response **sign_response)      uint8_t flags, const char *pin, struct sk_option **options,
       struct sk_sign_response **sign_response)
 {  {
         fido_assert_t *assert = NULL;          fido_assert_t *assert = NULL;
           char *device = NULL;
         fido_dev_t *dev = NULL;          fido_dev_t *dev = NULL;
         struct sk_sign_response *response = NULL;          struct sk_sign_response *response = NULL;
         int ret = SSH_SK_ERR_GENERAL;          int ret = SSH_SK_ERR_GENERAL;
Line 685 
Line 773 
                 goto out;                  goto out;
         }          }
         *sign_response = NULL;          *sign_response = NULL;
         if ((dev = find_device(message, message_len, application, key_handle,          if (check_sign_load_resident_options(options, &device) != 0)
             key_handle_len)) == NULL) {                  goto out; /* error already logged */
           if ((dev = find_device(device, message, message_len,
               application, key_handle, key_handle_len)) == NULL) {
                 skdebug(__func__, "couldn't find device for key handle");                  skdebug(__func__, "couldn't find device for key handle");
                 goto out;                  goto out;
         }          }
Line 733 
Line 823 
         response = NULL;          response = NULL;
         ret = 0;          ret = 0;
  out:   out:
           free(device);
         if (response != NULL) {          if (response != NULL) {
                 free(response->sig_r);                  free(response->sig_r);
                 free(response->sig_s);                  free(response->sig_s);
Line 785 
Line 876 
                 }                  }
                 skdebug(__func__, "get metadata for %s failed: %s",                  skdebug(__func__, "get metadata for %s failed: %s",
                     devpath, fido_strerr(r));                      devpath, fido_strerr(r));
                   ret = fidoerr_to_skerr(r);
                 goto out;                  goto out;
         }          }
         skdebug(__func__, "existing %llu, remaining %llu",          skdebug(__func__, "existing %llu, remaining %llu",
Line 900 
Line 992 
 }  }
   
 int  int
 sk_load_resident_keys(const char *pin,  sk_load_resident_keys(const char *pin, struct sk_option **options,
     struct sk_resident_key ***rksp, size_t *nrksp)      struct sk_resident_key ***rksp, size_t *nrksp)
 {  {
         int ret = SSH_SK_ERR_GENERAL, r = -1;          int ret = SSH_SK_ERR_GENERAL, r = -1;
Line 908 
Line 1000 
         size_t i, ndev = 0, nrks = 0;          size_t i, ndev = 0, nrks = 0;
         const fido_dev_info_t *di;          const fido_dev_info_t *di;
         struct sk_resident_key **rks = NULL;          struct sk_resident_key **rks = NULL;
           char *device = NULL;
         *rksp = NULL;          *rksp = NULL;
         *nrksp = 0;          *nrksp = 0;
   
         if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {          if (check_sign_load_resident_options(options, &device) != 0)
                 skdebug(__func__, "fido_dev_info_new failed");                  goto out; /* error already logged */
                 goto out;          if (device != NULL) {
         }                  skdebug(__func__, "trying %s", device);
         if ((r = fido_dev_info_manifest(devlist,                  if ((r = read_rks(device, pin, &rks, &nrks)) != 0) {
             MAX_FIDO_DEVICES, &ndev)) != FIDO_OK) {  
                 skdebug(__func__, "fido_dev_info_manifest failed: %s",  
                     fido_strerr(r));  
                 goto out;  
         }  
         for (i = 0; i < ndev; i++) {  
                 if ((di = fido_dev_info_ptr(devlist, i)) == NULL) {  
                         skdebug(__func__, "no dev info at %zu", i);  
                         continue;  
                 }  
                 skdebug(__func__, "trying %s", fido_dev_info_path(di));  
                 if ((r = read_rks(fido_dev_info_path(di), pin,  
                     &rks, &nrks)) != 0) {  
                         skdebug(__func__, "read_rks failed for %s",                          skdebug(__func__, "read_rks failed for %s",
                             fido_dev_info_path(di));                              fido_dev_info_path(di));
                         continue;                          ret = r;
                           goto out;
                 }                  }
           } else {
                   /* Try all devices */
                   if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
                           skdebug(__func__, "fido_dev_info_new failed");
                           goto out;
                   }
                   if ((r = fido_dev_info_manifest(devlist,
                       MAX_FIDO_DEVICES, &ndev)) != FIDO_OK) {
                           skdebug(__func__, "fido_dev_info_manifest failed: %s",
                               fido_strerr(r));
                           goto out;
                   }
                   for (i = 0; i < ndev; i++) {
                           if ((di = fido_dev_info_ptr(devlist, i)) == NULL) {
                                   skdebug(__func__, "no dev info at %zu", i);
                                   continue;
                           }
                           skdebug(__func__, "trying %s", fido_dev_info_path(di));
                           if ((r = read_rks(fido_dev_info_path(di), pin,
                               &rks, &nrks)) != 0) {
                                   skdebug(__func__, "read_rks failed for %s",
                                       fido_dev_info_path(di));
                                   /* remember last error */
                                   ret = r;
                                   continue;
                           }
                   }
         }          }
         /* success */          /* success, unless we have no keys but a specific error */
         ret = 0;          if (nrks > 0 || ret == SSH_SK_ERR_GENERAL)
                   ret = 0;
         *rksp = rks;          *rksp = rks;
         *nrksp = nrks;          *nrksp = nrks;
         rks = NULL;          rks = NULL;
         nrks = 0;          nrks = 0;
  out:   out:
           free(device);
         for (i = 0; i < nrks; i++) {          for (i = 0; i < nrks; i++) {
                 free(rks[i]->application);                  free(rks[i]->application);
                 freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);                  freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);

Legend:
Removed from v.1.11  
changed lines
  Added in v.1.12